èæ¯
å°ãåãã€ãŸã6æ5æ¥ã«alan008ãšããååã®
ããŒããŒãã³ã
質åãããŸãã ã è©³çŽ°ãæ±ããªãããã«ãããã«åœŒãé£ããŠããŸãã
å©ããå¿
èŠã§ãïŒ
æ°å¹Žã«ããããããŸããŸãªã¯ã©ã€ã¢ã³ãïŒäž»ã«uTorrentïŒã«ãã£ãŠãããŸããŸãªäŸ¿å©ãªã³ã³ãã³ãã®å€ãã®ã®ã¬ãã€ããããŸããŸãªãã©ãã«ãŒïŒäž»ã«rutrackerã䜿çšïŒããããŠã³ããŒããããŠããŸããã ããŠã³ããŒãããããã¡ã€ã«ã¯ããã®åŸæåã§ãããã©ã€ãããå¥ã®ãã©ã€ãã«ç§»åãããuTorrentã¯ããã«å¿ããŠãããã衚瀺ããŸããã å€ãã®.torrentãã¡ã€ã«ã¯ããèªäœã§ã¯å€ããªã£ãŠããŸãïŒããšãã°ãã·ãªãŒãºã®é
åžã¯ã.torrentãã¡ã€ã«ã眮ãæããŠæ°ããã·ãªãŒãºã远å ããããšã«ããå®è¡ãããŸããïŒã
ããŠã質åèªäœïŒã³ã³ãã¥ãŒã¿ãŒäžã®.torrentãã¡ã€ã«ãšã³ã³ãã¥ãŒã¿ãŒã®ç°ãªãè«çãã©ã€ãã«æ£åšããã³ã³ãã³ããšã®éã®å¯Ÿå¿ãèªåçã«ïŒæåã§ã¯ãªãïŒç¢ºç«ããæ¹æ³ã¯ãããŸããïŒ ç®çïŒäžèŠãªïŒç¡é¢ä¿ãªïŒ.torrentãã¡ã€ã«ãåé€ããå®éã®ãã¡ã€ã«ã§ã¯-é
åžç©ã«ãã¹ãŠã眮ããŸãã 誰ãã¢ã€ãã¢ãæã£ãŠããŸããïŒ :)
å¿
èŠã«å¿ããŠïŒå¿
èŠãªå ŽåïŒãåãè«çãã©ã€ãäžã®1ã€ã®ãã£ã¬ã¯ããªã«ãã¹ãŠã®ããŒã¿ãã¡ã€ã«ãå床é
眮ã§ããŸãã
è°è«ã¯ããããã§ããã®ã§ããã°ããã³ã§ããã§ããªãããšã«åæããã ãã®è³ªåã¯ç§ã«ãšã£ãŠã¯é¢çœããã§ãäŒæããæ»ã£ãåŸãæéããããŠæŽçããŸããã
.torrentãã¡ã€ã«åœ¢åŒã®è§£æã«åèš1é±éãè²»ãããè§£æçšã®äœæ¥ã©ã€ãã©ãªãæ¢ããŠãäžèšã®è³ªåã§çºçããåé¡ã解決ããããã°ã©ã ã®äœæãéå§ããŸããã
å§ããåã«ãããã€ãã®ç¹ã«æ³šæãã䟡å€ããããŸãã
- å€ãã®ããšã倿ããŸãããããã¹ãŠã§ã¯ãããŸããã§ããã
- .torrentãã¡ã€ã«åœ¢åŒã§ã¯ãå¿
èŠãªèª¬æã®ã¿ãæäŸãããŸãã
- æã
äœå質ã®ã³ãŒãã«ææãªäººã¯ç§ãèš±ããŠãã ãã-å€ãã®æ¹ãããè¯ããããæé©ã«ããšã©ãŒãªãã§æžããããšãç¥ã£ãŠããŸãã
æè¡çãªè©³çްãšèœãšã穎-ç«ã®äžã§ãããããæ¥ããã®ã«èå³ããã人ã®ããã«ã
ãã®å Žåãããã解決ããããã®çŽ æŽãããæ¹æ³ããããŸã-åã³ãã³ãã§ãã¿ãŸãã ããããç§ãã¡ã¯ç°¡åãªæ¹æ³ãæ¢ããŠããŸããããã®ãããªãªãã·ã§ã³ãææ¡ãããŸããïŒ ãããã£ãŠãå°é£ãªã¿ã¹ã¯ã解決ããŸã-
ããŠã³ããŒãããªãã§ãã ãã ã
ããã°ã©ã ã®äœæãéå§ãããšãã¯ããŸããã®æäœã®å°ãªããšãåºæ¬çãªã¢ã«ãŽãªãºã ã«ã€ããŠèããå¿
èŠããããŸãã ãã®å Žåãã¢ã«ãŽãªãºã ã¯åºæ¬çã«2ã€ã®ã¹ãããã§æ§æãããŸãã
- ãã¹ãŠã®.torrentãã¡ã€ã«ãèŠã€ããŠèªã¿åããŸãã
- .torrentã§èª¬æãããŠãããã®ãšäžèŽãããã¡ã€ã«ããŒããæ¢ãã.torrentã®ãã¹ã«å¯Ÿå¿ãããã©ã«ããŒã«ç§»åããŸãã
ç§ã®ã¢ã€ãã¢ãå®è£
ããããã«ãç§ã¯CïŒã䜿çšããŸãããããã³ã³ãŒã圢åŒã®ãã¡ã€ã«ãèªã¿èŸŒãããã®ã©ã€ãã©ãªãåããèšèªã¯ããã«é©ããŠãããSHA-1ããã·ã¥ãèªã¿èŸŒãããšãå¯èœã§ãã
ããŠãã¿ã¹ã¯ã®è§£æ±ºçã«é²ã¿ãŸãããã
ãã¬ã³ããæ¢ããŠèªã
ããã€ã¹ã®.torrent-filesãèŠã€ããåŸããã®ãã¹ãŠã®å¥è·¡ãè§£æãããšããåé¡ã«çŽé¢ããŸããã ãã®ããŒãã§ã€ã³ã¿ãŒãããã粟æ»ããŠããã®ããžãã¹ã®ããã®ããã€ãã®.NETã©ã€ãã©ãªãçºèŠããŸããã
BencodeLibraryã©ã€ãã©ãªã§éžæãéžæããŸããããå€ããå°ãªããæç¢ºã§ãããã«äœ¿çšã§ããŸãããåŸã§ããŒãºã«å°ã远å ããå¿
èŠããããŸããããããã«ã€ããŠã¯åŸã§è©³ãã説æããŸãã
.torrentãèªããšããæãåçŽãªç¬éããå§ããŸãããã
.torrentãã¡ã€ã«ã®æ§é ã¯éåžžã«åçŽã§ããããã¯ã
ãã³ã³ãŒã圢åŒã®èŸæžã§ãã ãã®èŸæžã§ã¯ã
æ
å ±ããŒãšã®ãã¢ãã€ãŸããã¡ã€ã«èšè¿°ãããã¯ã®ã¿ã«é¢å¿ããããŸãã ãããèŸæžã§ããããã¡ã€ã«ã®ååããµã€ãºã«é¢ããæ
å ±ãå«ãŸããŠããŸãã ããã«ãå€ãã®äººãç¥ã£ãŠããããã«ãæ¥æµã¯ãã¡ã€ã«ãå®å
šã«ã§ã¯ãªããç¹å®ã®é·ãã®æçã«ããã·ã¥ããŸããããã¯ãããã®ãã¡ã€ã«ã®ãµã€ãºã«äŸåããŸãã ãã®äœåã®ãµã€ãºã«é¢ããæ
å ±ã
æ
å ±èŸæžã«å«ãŸããŠããŸãã
èªã¿åã£ããã¡ã€ã«ããã®æ
å ±ãä¿åããã«ã¯ã次ã®
Torrent
ã¯ã©ã¹ã䜿çšããŸãã
ã¯ã©ã¹æ¥æµ public class Torrent { public Torrent(string name, List<LostFile> files, int pieceLength, char[] hash, string fileName) { Name = name; Files = files; PieceLength = pieceLength; Hash = hash; FileName= fileName; } public string Name; public int PieceLength; public char[] Hash; public List<LostFile> Files; public string FileName; ... }
ããã§ããã£ãŒã«ãã«ã¯æ¬¡ã®æ
å ±ãæ ŒçŽãããŸãã
*
Name
-ãã¬ã³ãåïŒäžè¬çã«èšãã°-ãã©ã«ããŒåãŸãã¯ãã¡ã€ã«åïŒ
*
Files
-ä»åŸæ€çŽ¢ããå¿
èŠããããã¡ã€ã«ã®ãªã¹ã
*
PieceLength
ãããã®ããŒã¹ã®ãµã€ãºãèæ
®ãã¹ãããã·ã¥
*
Hash
-ãã¹ãŠã®ãã¡ã€ã«ã®ããã·ã¥æåå
*
FileName
ãã£ã¹ã¯äžã®.torrentãã¡ã€ã«ã®åå
ããã·ã¥ã©ã€ã³ã«æ³šç®ãã䟡å€ããããŸãã éåžžã«ç°¡åã«æ§æãããŠããŸãã ãã¹ãŠã®ãã¡ã€ã«ã¯æ¬¡ã
ãšïŒäºå®äžïŒæ¥çããã1ã€ã®BIGOOOOOOOYã®ä»®æ³ãã¡ã€ã«ã圢æããŸãã ãã®æ¶ç©ºã®ãã¡ã€ã«ã§ã¯ã
PieceLength
ã®é·ãã®æçãååŸããSHA1ããã·ã¥ãèæ
®ããããã·ã¥ãè¡ã«å
¥ããæ¬¡ã®æçãååŸããããã·ã¥ãèæ
®ããåã®æçã®ããã·ã¥ã§è¡ã®æ«å°Ÿã«è¿œå ããŸãã ã€ãŸãããã¹ãŠã®ããŒã¹ã®ããã·ã¥ã®éåžžã®é£çµã§ãã

æ³šææ·±ãèªè
ãæ°ä»ãããã«ãã¯ã©ã¹å
ã®ãã¡ã€ã«ã¯åãªããã¡ã€ã«ã§ã¯ãªãã
LostFile
åã®ç¹å®ã®æ§é ã«ãã£ãŠãã¡ã€ã«ãèšè¿°ãããç¹å¥ãªããŒã¿åã§ãã ããã«ãããŸãïŒ
ã¯ã©ã¹LostFile public class LostFile { public LostFile(string name, long length, long beginFrom) { Name = name; Length = length; BeginFrom = beginFrom; } public string Name; public long Length; public long BeginFrom; . . . }
ããã§ã¯ãã¹ãŠãç°¡åã§ãããã¡ã€ã«ã®ååãšãµã€ãºã§ãã ããã«ããã®ã¯ã©ã¹ã«ã¯ã
BeginFrom
å¥ã®ãã£ãŒã«ããå«ãŸããŠããŸãã ãã®å€§ããªæ³åäžã®ãã¡ã€ã«ã§ãã®ãã¡ã€ã«ã®å§ãŸãã説æããŠããŸãã ããã·ã¥ãèšç®ããã«ã¯ããã¡ã€ã«ã®æ£ããéšåãååŸããå¿
èŠããããŸã-ãã¡ã€ã«ã®é·ããæçã®é·ãã®åæ°ã«ãªãããšã¯éåžžã«ãŸãã§ãã

å¿
èŠãªæ
å ±ãä¿åããããã®æ§é ãæºåããããããããåããããšãã§ããŸãã
ã€ã³ã¿ãŒãããã«ãã
BencodeLibraryã©ã€ãã©ãªã䜿çšããŠã.torrentãã¡ã€ã«ãèªã¿åãããããã
æ
å ±ãããã¯ãã«ãŒãããŸãã
List<LostFile> files = new List<LostFile>();
次ã«ããã®ãããã¯ããããã¬ã³ãã®ååãããŒã¹ã®ãµã€ãºã«é¢ããããŒã¿ãåéããå¿
èŠããããŸãã
string name = ((BString)fileInfo["name"]).Value; int pieceLength = (int)((BInt)fileInfo["piece length"]).Value;
ããã·ã¥ã®èªã¿åãã«åé¡ããããŸãããããã®è§£æ±ºçã¯ããŸã奜ãã§ã¯ãããŸããããããŸããããŸãã å®éã仿§ã«ããã°ã.torrentãã¡ã€ã«ã®ãã¹ãŠã®è¡ã¯UFT8ã«ããå¿
èŠããããŸãã 仿§ã«åŸã£ãŠãUTF8æååãšããŠãã³ã³ãŒãæååã®åœ¢åŒã§èšè¿°ãããããã·ã¥ãèªã¿åããšãæ¯èŒã®åé¡ãçºçããŸã-åäžã®æçã®ããã·ã¥ã¯äžèŽããŸããã ææ¡ããããšã³ã³ãŒãã³ãŒãããŒãž437ã®ãã¬ã³ããèªããšããã¹å
ã®ãã·ã¢æåã«åé¡ããããŸãã ç°ãªããšã³ã³ãŒãã£ã³ã°ã§2åèªããšããã2æ¥éã®é床ãèœãšããããªç¶æ³ããæãåºãæ¹æ³ãèŠã€ããŸããã
torrent = (BDict)BencodingUtils.DecodeFile(filename, Encoding.GetEncoding(437)); char[] pieces = ((BString)((BDict)torrent["info"])["pieces"]).Value.ToCharArray();
ãã®æç¹ã§ããšã³ã³ãŒãæ
å ±ã2çªç®ã®ãã©ã¡ãŒã¿ãŒãšã㊠`BencodingUtils.DecodeFile`ã¡ãœããã«æž¡ããŸãã ããã¯ãŸãã«ãã©ã€ãã©ãªã«ã¡ãœããã1ã€è¿œå ããªããã°ãªããªãã£ãç¬éã§ã-æåã¯codepage-437ãã³ãŒãã«çž«ãä»ããããŠããŸããã
ãã®éšåã§æãè峿·±ããã€ã³ãã«å°éããŸãã-ãã¡ã€ã«æ
å ±ã®èªã¿åãã ãã¬ã³ããã¡ã€ã«ã«ã¯2ã€ã®ã¿ã€ãããããŸãã ãããã®ã¿ã€ãã¯ããããã«èšè¿°ãããŠãããã¡ã€ã«ã®æ°ãç°ãªããŸãã .torrentã§1ã€ã®ãã¡ã€ã«ã®ã¿ãèšè¿°ããå Žåããã®ååãšãµã€ãºãæžã蟌ãŸããŸãã
æåã«ã1ã€ã®ãã¡ã€ã«ã®èª¬æã䜿çšããŠ.torrentãåæããŸãã
long Length = ((BInt)fileInfo["length"]).Value; files.Add(new LostFile(name, Length, 0)); // files -
ããã§ã¯ãã¹ãŠãåçŽã§ã-ãã¬ã³ãã®ååã¯ãã¡ã€ã«åãšåãã§ãã ãã£ã¹ããªãã¥ãŒã·ã§ã³ã«å€æ°ã®ãã¡ã€ã«ãããå Žåãããããå
¥ãããã©ã«ããŒã®
ååãååãã£ãŒã«ãã«æžã蟌ãŸããŸãïŒå®éã«ã¯ãäœã§ãæ§ããŸããããäœããã®çç±ã§ã誰ãããããã®ãã¡ã€ã«ãäœææã«é
眮ããããã©ã«ããŒã®ååãæžã蟌ã¿ãŸãïŒã ããã«ãåãã¡ã€ã«ã«é¢ããæ
å ±ïŒãã¹ãšãµã€ãºïŒãå«ã
ãã¡ã€ã«ã®ãªã¹ãã衚瀺ãããŸãã ãµã€ãºãæŽæ°ã®å Žåããã¡ã€ã«ãã¹ã¯æååïŒãã£ã¬ã¯ããªåïŒã®ãªã¹ãã§ããããã®ãã¡ã€ã«ãä»ããŠè¡šç€ºãããŸãã
ããã¯ãäŸã«ãã£ãŠæããã説æãããŸãã ãã¡ã€ã«
level_1\level_2_1\file_1.txt
ããã³
level_1\level_2_2\file_2.txt
å Žåãããããé
åžããå Žåã
ååãã£ãŒã«ãã«ã¯æäžäœãã©ã«ããŒã®ååïŒ
"level_1"
ïŒãå«ãŸãããã¡ã€ã«ã®1ã€ã®
ãã¹ãªã¹ãã¯æ¬¡ã®ããã«ãªããŸãïŒ
{"level_2_1", "file_1.txt"}
ããã³
{"level_2_2", "file_2.txt"}
å¥ã®ã
è€æ°ã®ãã¡ã€ã«ãå«ã.torrentã®å Žåãåãã¡ã€ã«ãžã®ãã¹ã1è¡ã§åéããå¿
èŠããããŸãã ããã«ãåãã¡ã€ã«ã®å
é ããã®BOLSHOOOOMã«ä¿åããå¿
èŠããããŸãïŒå¿ããªãã§ãã ãããæ¬åœã«ïŒïŒïŒã
BList filesData = (BList)fileInfo["files"]; long begin = 0; foreach (BDict file in filesData) { BList filePaths = (BList)file["path"]; long length = ((BInt)file["length"]).Value; string fullPath = name; foreach (BString partOfPath in filePaths) { fullPath += @"\" + partOfPath.Value; } files.Add(new LostFile(fullPath, length, begin)); // files - begin += length; }
BOLSHOOOOOMãã¡ã€ã«å
ã®ãã¡ã€ã«ã®é åºã¯ä»»æã§ãããå¿
ãããã¢ã«ãã¡ãããé ãŸãã¯ãµã€ãºã§ã¯ãªãããšã«æ³šæããããšãéåžžã«éèŠã§ãã ãã ãã
ãã¡ã€ã«ãªã¹ãå
ã®
ãã¡ã€ã«ã®é åºã¯ãŸã£ããåãã«ãªããŸãã ããã¯ãããã·ã¥ã®åçãçè§£ããããã®éµã§ãã ããšãã°ãæåã®å³ã«ç€ºãç¶æ³ã§ã¯ããã¡ã€ã«ã®ãªã¹ãã¯æ¬¡ã®ããã«ãªããŸãïŒ
{"file_3","file_1", ..., "file_2"}
ã ãããã£ãŠããããã¡ã€ã«ã®ããã·ã¥ãèæ
®ãããšã次ã«ååŸããå¿
èŠããããã¡ã€ã«ãããããŸãã
ãã®ãã¹ãŠãèªãã§ã«ãŠã³ããããã
Torrent
ã³ããŒãäœæããŠè¿ããŸãããã
new Torrent(name, files, pieceLength, pieces, filename);
.torrentãã¡ã€ã«ã®ãã¹ãŠã®èªã¿åãå€ãšåæããŸãšããŠåéãããšã次ã®ããã«ãªããŸãã
ReadTorrent static Torrent ReadTorrent(string filename) { List<LostFile> files = new List<LostFile>(); BDict torrent = (BDict)BencodingUtils.DecodeFile(filename); BDict fileInfo = (BDict)torrent["info"]; string name = ((BString)fileInfo["name"]).Value; int pieceLength = (int)((BInt)fileInfo["piece length"]).Value; torrent = (BDict)BencodingUtils.DecodeFile(filename, Encoding.GetEncoding(437)); char[] pieces = ((BString)((BDict)torrent["info"])["pieces"]).Value.ToCharArray(); if (fileInfo.ContainsKey("files")) // Multifile torrent { BList filesData = (BList)fileInfo["files"]; long begin = 0; foreach (BDict file in filesData) { BList filePaths = (BList)file["path"]; long length = ((BInt)file["length"]).Value; string fullPath = name; foreach (BString partOfPath in filePaths) { fullPath += @"\" + partOfPath.Value; } files.Add(new LostFile(fullPath, length, begin)); begin += length; } } else // Singlefile torrent { long Length = ((BInt)fileInfo["length"]).Value; files.Add(new LostFile(name, Length, 1)); } return new Torrent(name, files, pieceLength, pieces, filename); }
å¿
èŠãªããŒã¿ããã¹ãŠæã£ãã®ã§ãæãè峿·±ãããšãã€ãŸããã¡ã€ã«ã®æ€çŽ¢ã®æºåãã§ããŸããã
ãã¡ã€ã«ãæ¢ããŠããŸã
ã¢ã«ãŽãªãºã ã®2çªç®ã®ã¹ãããã®å®è£
ã«è¿ã¥ããŸããã ãããè¡ãã«ã¯ã次ã®ãã©ãŒã ã®
FindFiles
ã¡ãœããã䜿çšããŸãã
void FindFiles(Torrent torrent, List<FileInfo> files, string destinationPath) {}
ããã§ã
files
ã¯æ€çŽ¢å¯Ÿè±¡ã®ãã¡ã€ã«ã®ãªã¹ã
files
ã¯ãèŠã€ãã£ããã¡ã€ã«ãé
眮ãããå®å
ãã©ã«ããŒãžã®ãã¹ã§ãã
.torrentã®åãã¡ã€ã«ã«ã€ããŠãããŒããããã¹ãŠã®ãã¡ã€ã«ãå埩åŠçããããããæ¯èŒããŸãã ããã·ã¥ã®ãã§ãã¯ã¯éåžžã«é«äŸ¡ãªã®ã§ãæåã«å·ŠåŽã®ãã¡ã€ã«ãæç€ºçã«ã¯ãªã¢ããå¿
èŠããããŸãã ããŠãèªåã§å€æããŠãã ããããã£ã¹ã³ã°ã©ãã£ãŒã.mp3ã«ããŠã³ããŒãããŠç§»åããŠããæããã«ãã¡ã€ã«æ¡åŒµåã¯å€æŽããŸããã§ããã ååã¯å€æŽã§ããŸãããæ¡åŒµåã¯ã»ãšãã©ãããŸããã
FileInfo fileOnDisk = files[j]; if (fileOnDisk.Extension != Path.GetExtension(fileInTorrent.Name)) continue;
ãã¡ã€ã«ã®é·ãã確èªãã䟡å€ããããŸãããããã¯ãã§ã«çããããã®ã§ããã誀æ€ç¥ãåŒãèµ·ããå ŽåããããŸãã æ¡åŒµåã«ãã£ãŠæç€ºçã«æ®ããããã¡ã€ã«ããµããã«ãããåŸã«ã®ã¿ãããã·ã¥ã®ãã§ãã¯ãéå§ã§ããŸãã
if (!torrent.CheckHash(i, fileOnDisk)) continue
æ€èšŒãå®äºãããã¡ã€ã«ãæ¢ããŠãããã®ãšäžèŽããããšã確èªããåŸãæ£ãããã¹ã§å®å
ãã©ã«ããŒã«ç§»åããŸãã ç§»åããåã«ããã£ã¬ã¯ããªã®ååšãèªç¶ã«ç¢ºèªãããã®ãããªãã¡ã€ã«ããã§ã«ãããã©ããã確èªããŸãã
copyFile
ãŠãŒã¶ãŒããã©ãŒã ããæž¡ãã倿°ããã®ç®çã¯èª°ã«ã§ãæããã ãšæããŸãã
FileInfo fileToMove = new FileInfo(destinationPath + @"\" + fileInTorrent.Name); if (!Directory.Exists(fileToMove.DirectoryName)) Directory.CreateDirectory(fileToMove.DirectoryName); if (!fileToMove.Exists) { // - if (copyFile) File.Copy(fileOnDisk.FullName, fileToMove.FullName); else File.Move(fileOnDisk.FullName, fileToMove.FullName); // files.Remove(fileOnDisk); // torrent.Files.RemoveAt(i
äžèšã®ã³ãŒãã§èª¬æããéèŠãª3ã€ã®ãã€ã³ãããããŸãã æåŸã®2ã€ããå§ããŸããã-ãããã®è¡ïŒ
files.Remove(fileOnDisk); torrent.Files.RemoveAt(i--);
ãœãŒãæžã¿ã®ãã¡ã€ã«ãèæ
®ããé€å€ããããšã¯éåžžã«è«ççã§ããããšãããããŸãããããã«ãããæ€çŽ¢ã®å®è¡æéããããã«ççž®ãããŸãã 2è¡ç®ã«ã¯ãæ§æ
.RemoveAt(i--);
ãå«ãŸããŠã
.RemoveAt(i--);
çŸåšã®èŠçŽ ã¯ã³ã¬ã¯ã·ã§ã³ããåé€ããããããæ¬¡ã®èŠçŽ ãã«ãŒããééããã®ã§ã¯ãªããã«ãŒãã®æ¬¡ã®å埩ã§ååŸãããããã«ããã€ã³ã¿ãŒãæ»ãå¿
èŠããããŸãã
æåã®ç¬éã«ã€ããŠã ãªã¹ãã«
foreach
ãååšããããšã¯ç¥ã£ãŠããŸãããããã䜿çšããå Žåããã®ã¹ããŒã«ãŒã倿Žããããšã¯ã§ããŸãããã€ãŸããæ¢ã«äžèŠãªèŠçŽ ãåé€ããããšã¯ã§ããŸããã ãããã£ãŠãäžèšã®ãã¹ãŠã1ã€ã®æ¹æ³ã§åéãããšã次ã®ããã«ãªããŸãã
ReadTorrent public static void FindFiles(Torrent torrent, List<FileInfo> files, string destinationPath, bool copyFile) { for (int i = 0; i < torrent.Files.Count; i++)// (LostFile fileInTorrent in torrent.Files) { LostFile fileInTorrent = torrent.Files[i]; for (int j = 0; j < files.Count; j++) { FileInfo fileOnDisk = files[j]; // if (fileOnDisk.Extension != Path.GetExtension(fileInTorrent.Name)) continue; // if (fileOnDisk.Length != fileInTorrent.Length) continue; // if (!torrent.CheckHash(i, fileOnDisk)) continue; // . // FileInfo fileToMove = new FileInfo(destinationPath + @"\" + fileInTorrent.Name); if (!Directory.Exists(fileToMove.DirectoryName)) Directory.CreateDirectory(fileToMove.DirectoryName); if (!fileToMove.Exists) { if (copyFile) File.Copy(fileOnDisk.FullName, fileToMove.FullName); else File.Move(fileOnDisk.FullName, fileToMove.FullName); // files.Remove(fileOnDisk); // torrent.Files.RemoveAt(i
ããããã«ïŒ æãããããã
ããã·ã¥ãã§ãã¯
äžèšã®ã³ãŒããããããããã«ãããã·ã¥ã確èªããããã«ããã£ã¹ã¯äžã®ãã¡ã€ã«åãšãã¬ã³ããã¡ã€ã«ã®ãªã¹ãå
ã®ãã¡ã€ã«çªå·ã転éããŸãã ããã¯ããã¡ã€ã«ã®ãªã¹ãã§æ€çŽ¢ãéå§ããã®ã§ã¯ãªããæ¢ç¥ã§ãããããããã«çªå·ã§æ€çŽ¢ããããã«å¿
èŠã§ãïŒã«ãŒãã®å¥ã®ã+1ãïŒã
public class Torrent { public string Name; public int PieceLength; public char[] Hash; public List<LostFile> Files; public string FileName; public bool CheckHash(int index, FileInfo fileOnDisk) {} }
ããã§ã¯ãããã·ã¥æ€èšŒã¡ãœããã®å®è£
ã«åãââæãããŸãããã ãã®æ®µéã§ããã¬ã³ããã¡ã€ã«ã®ãªã¹ãã®çªå·ãšãã£ã¹ã¯äžã®ãã¡ã€ã«ãžã®ãã¹ãããããŸãã
LostFile checkingFile = this.Files[index]; if (checkingFile.Length < this.PieceLength * 2 - 1) return false;
ååãšããŠãä»»æã®ãã¡ã€ã«ã®ããã·ã¥ãèæ
®ããããšãã§ããŸãããã¿ã¹ã¯ãå°ãç°¡åã«ããŸãããã é·ãã
PieceLength * 2 - 1
以äžã®ãã¡ã€ã«ã®ã¿ã䜿çšããŸãã ãã®ãããªå¶éã«ãããæ€èšŒã®ããã«å°ãªããšã1ã€ã®éšåãåé¢ã§ããŸããããã¯å®å
šã«ãã¡ã€ã«å
ã«ãããŸãã ãã®ã¢ãããŒãã«ã¯ãããã€ãã®éèŠãªå©ç¹ããããŸãã
- ãã£ã¹ã¯äžã®é£æ¥ãã¡ã€ã«ã远å ã§æ€çŽ¢ããå¿
èŠã¯ãããŸããã
- ããã·ã¥ãã£ã³ã¯ã®é·ãã2ã4 MBãè¶
ããããšã¯ãã£ãã«ãããŸãããããã«ãããããã©ãŒãã³ã¹ãšæéã®ç¹ã§ããã£ã¹ã¯äžã®ãã¡ã€ã«ãæ¢ããããã¯ããã«ç°¡åã«ããŠã³ããŒãã§ããŸãã
ãã®æ®µéã§ãç§ãã¡ã¯ãããªããã°ãªããªãããšã®äžã§æãå°é£ãªããš-æ€èšŒã®ããã®é©åãªããŒã¹ãèŠã€ããããšã«ãªããŸããã ããã°ã©ãã³ã°ããå°ãé¢ããŠãæ°åŠã«ç®ãåããŠãè£å©çãªåé¡ãå®åŒåããŸãããã
ãã¬ã³ãã¯ã©ã€ã¢ã³ãããã¡ã€ã«ãããã·ã¥ãããšãããã·ã¥ãé çªã«èæ
®ãããŸããã1ã€ä»¥äžã®ãã¡ã€ã«ãååšããªãããšãèµ·ãããŸãã æ¬¡ã«ããã¬ã³ãã¯ã©ã€ã¢ã³ãã¯ã次ã®ããŒã¹ãååŸããæ¬¡ã«äœ¿çšå¯èœãªãã¡ã€ã«ã®ã©ãããéå§ããããç¥ãå¿
èŠããããŸãã ãããã®2æ¡ãèšç®ããã«ã¯ã次ã®ã³ãŒãã䜿çšããŸã
firstChunkNumber
倿°ã«ã¯ããã®ãã¡ã€ã«ã«å®å
šã«å«ãŸããæåã®ããŒã¹ã®çªå·ãšã
bytesOverhead
ãã¡ã€ã«ã®å
é ãããã®ããŒã¹ã®å
é ãŸã§ã®ãã€ãæ°ãå«ãŸããŸãã ãã®ç¹ãããããçè§£ããã«ã¯ãã³ãŒãã®åŸã®èª¬æå³ãã芧ãã ããã
long start = 0; long firstChunkNumber = 0; long bytesOveload = checkingFile.BeginFrom % this.PieceLength; if (bytesOveload == 0) // { start = checkingFile.BeginFrom; firstChunkNumber = checkingFile.BeginFrom / this.PieceLength; } else { firstChunkNumber = checkingFile.BeginFrom / this.PieceLength + 1; start = firstChunkNumber * this.PieceLength - checkingFile.BeginFrom; }

ããã®éå§ããã¡ã€ã«ã®éå§ãšäžèŽããå ŽåãšãããŒã¹ãå
éšã«ããå Žåãšã§ã¯ãªãããŒã¹çªå·ãç°ãªãã®ãããšãã質åã«å¯Ÿããçãã¯ãç¬ç«ããŠææ¡ãããŠããŸãã
ããŒã¹ã®çªå·ãããã£ãããæ¬¡ã®æ§æã䜿çšããŠãã¬ã³ãããããã·ã¥ãååŸããå¿
èŠããããŸãã
char[] hashInTorrent = new char[20]; // 20 - SHA1 Array.Copy(this.Hash, firstChunkNumber * 20, hashInTorrent, 0, 20);
ãã®åŸããã¡ã€ã«ããããŒã¹ãèªã¿åãããã®ããã·ã¥ãèšç®ããå¿
èŠããããŸãã
char[] fileHash = new char[this.PieceLength]; using (BinaryReader fs = new BinaryReader(new FileStream(fileOnDisk.FullName, FileMode.Open))) { using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) { byte[] piece = new byte[this.PieceLength]; fs.BaseStream.Position = start; fs.Read(piece, 0, this.PieceLength); fileHash = Encoding.GetEncoding(437).GetString(sha1.ComputeHash(piece)).ToCharArray(); } }
ããŠãæãéèŠãªããšã¯ããããã§ãã¯ããããšã§ãã äœããã®çç±ã§ãç§ã«ãšã£ãŠã¯ã
Equals()
ã¡ãœãããèŠã€ãããªãã£ããããæ¬¡ã®æ¹æ³ã§ãã§ãã¯ããŸãã
for (int i = 0; i < fileHash.Length; i++) { if (fileHash[i] != hashInTorrent[i]) return false; }
è奮ããè³ã®äœæããŸãšãããšã次ã®å
容ã®ã¡ãœãããåŸãããŸãã
ãã§ãã¯ããã·ã¥ public bool CheckHash(int index, FileInfo fileOnDisk) { LostFile checkingFile = this.Files[index]; if (checkingFile.Length < this.PieceLength * 2 - 1) return false; long start = 0; long firstChunkNumber = 0; long bytesOveload = checkingFile.BeginFrom % this.PieceLength; if (bytesOveload == 0) { start = checkingFile.BeginFrom; firstChunkNumber = checkingFile.BeginFrom / this.PieceLength; } else { firstChunkNumber = checkingFile.BeginFrom / this.PieceLength + 1; start = firstChunkNumber * this.PieceLength - checkingFile.BeginFrom; } char[] hashInTorrent = new char[20]; Array.Copy(this.Hash, firstChunkNumber * 20, hashInTorrent, 0, 20); char[] fileHash = new char[this.PieceLength]; using (BinaryReader fs = new BinaryReader(new FileStream(fileOnDisk.FullName, FileMode.Open))) { using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) { byte[] piece = new byte[this.PieceLength]; fs.BaseStream.Position = start; fs.Read(piece, 0, this.PieceLength); fileHash = Encoding.GetEncoding(437).GetString(sha1.ComputeHash(piece)).ToCharArray(); } } for (int i = 0; i < fileHash.Length; i++) if (fileHash[i] != hashInTorrent[i]) return false; return true; }
ãã®çŽ æŽãããã¡ã¢ã§ãæ¹æ³ãšã¢ã«ãŽãªãºã ã®ç©èªã¯çµãããç§ãã¡ã¯ãã®åµé ã®å®ç掻ã«ãããå®çŸã®ç©èªã«ç§»ããŸãã ãã®åé¡ã解決ããããã«ç§ã«ãã£ãŠè§£æ±ºãããã®ã§ã¯ãªããå®çŸããããã«è§£æ±ºãããããšã¯éåžžã«æããã§ãã ãããã£ãŠãç§ã¯ãäžã«æžããããã®ãã¹ãŠãå®è£
ããç§ã®åµé ç©ãå
¬éè£å€æã«æã¡èŸŒã¿ãŸãã
ããã°ã©ã
ããã°ã©ã ã¯ãCïŒã§æ¢ã«è¿°ã¹ãããã«æžãããŠããŸãã äœæ¥äžã¯ããŸãæ°ãŸããã§ã¯ãªãã.NET 2.0ã®ã¿ãå¿
èŠã§ãã ãã ãããã®äœ¿çšã«ã¯1ã€ã®å¶éããããŸãããã¬ã³ããã¡ã€ã«ãšã³ã¬ã¯ã·ã§ã³ãè«çãã©ã€ãã®ã«ãŒãããåé€ããããšããå§ãããŸãã ãã®å¶éã®çç±ã¯ããã£ã¬ã¯ããªãã¹ãã£ã³ãããšãã«ãSearchOption.AllDirectoriesããã©ã¡ãŒã¿ã䜿çšããããã§ããããã¯ããã¿ç®±ããã·ã¹ãã ããªã¥ãŒã æ
å ±ããªã©ã®éãããã£ã¬ã¯ããªãèªã¿åãããšãããšã¯ã©ãã·ã¥ããŸãïŒç¥èã®ãã人ããããåé¿ããæ¹æ³ãæããŠããããããšãŠãæè¬ããŠããŸãïŒã ãã¡ãããå®å
ãã©ã«ããŒã«ã¯ç¹å¥ãªå¶éã¯ãããŸãããäž»ãªããšã¯ããããåãŸãããšã§ãããããã«æžã蟌ãããšãã§ããŸããããããªããšã¯ã©ãã·ã¥ããŸãïŒã·ãã¥ã¬ãŒãããŸããã§ããããè«ççã«ïŒã
ããã»ã¹ã§ã¯ã次ã®ãã¡ã€ã«ã®åŠçåŸãçµæã衚瀺ãããŸã-ãã£ã¹ã¯äžã®.torrentãã¡ã€ã«ã®ååãšåŠçããããã¡ã€ã«ã®æ°ã

ã¹ãã£ã³ãéå§ããã«ã¯ã3ã€ã®ãã£ã¬ã¯ããªïŒ.torrentãã¡ã€ã«ãäžŠã¹æ¿ãçšã®ãã¡ã€ã«ãããã³äžŠã¹æ¿ãçšã®ãã©ã«ãïŒãéžæãããªãã·ã§ã³ã§2ã€ã®ãªãã·ã§ã³ãæå®ããŠã¹ãã£ã³ãéå§ããå¿
èŠããããŸãã
ããã©ãŒãã³ã¹ã«ã€ããŠã ãŸã äœãïŒ10åã®å€§ããªãã¬ã³ããã¡ã€ã«ã®åŠçã«ã¯çŽ5åããããŸããã
ã¢ããªã±ãŒã·ã§ã³ã¯1ã€ã®ã¹ã¬ããã§åäœãããããå®è¡æã«ã€ã³ã¿ãŒãã§ã€ã¹ãããªãŒãºããŸãããäœæ¥äžã§ãã ãŸããããã·ã¥ãæ€èšŒã§ããªããããå°ããªãã¡ã€ã«ïŒ2ã¡ã¬ãã€ãæªæºïŒã¯ç§»åãããªãããšããç¥ããããŸãã 誀
firstChunkNumber
ãçªå·
firstChunkNumber
äžã®1ã€ã®ããŒã¹ã®ã¿
firstChunkNumber
ããããšããäºå®ãåå ã§ããå¯èœæ§ãéåžžã«é«ãã§ãã ãããŸã§ã®ãšããããã¹ãŠã®ããŒã¹ããã§ãã¯ããã®ã¯éåžžã«é«äŸ¡ã§ãããèšç»ããããŸãã
ãã£ã¹ã¯ã®ã«ãŒãã§åéããããã¬ã³ããååž°çã«æ€çŽ¢ããªãã§ãã ããã
ã³ããŒã«ã¯æéãããããããã€ã³ã¿ãŒãã§ã€ã¹ãããªãŒãºããå¯èœæ§ããããŸããå¿é
ããªãã§ãã ããããã®4funããã°ã©ã ã¯æžãããŠããã®ã§ãã³ãŒãã®å質ã¯ç§ãæãã§ãããã®ãšã¯å°ãç°ãªããŸãããç§ã«ãšã£ãŠã¯ããŸããããŸãã ãã®ããã°ã©ã ã¯ãã¹ããããŠããããæãããªãšã©ãŒã®ã¿ãä¿®æ£ããããããé ããŠããå¯èœæ§ããããŸãããé ããŠãããã°ããããŸãã
ãã®ããã°ã©ã ã䜿çšãããšãããªãã¯èªåã®è²¬ä»»ã§ããã䜿çšããŸãããœãŒã¹ã¯
githubã§å
¥æã§ã
ãŸã ã GPLv2ã§é
åžã å®è¡å¯èœãã¡ã€ã«ãå«ãã¢ãŒã«ã€ãããããŸãã äœæ¥ã«ã¯Bencode Libraryãå¿
èŠã§ãããå
ã®ã©ã€ãã©ãªã¯å¿
èŠãããŸããããç§ãä¿®æ£ããŸããïŒ
ãªããžããªã«ããããµãã¢ãžã¥ãŒã«ã§æ¥ç¶ãããŠã
ãŸã ïŒã
å¿èã瀺ãããã®èšäºãæåŸãŸã§èªãã§ãããçããã«æè¬ããŸãã ããªãã®è³ªåãèããŠåãã§ãã¢ã«ãŽãªãºã ãç¹ã«ã³ãŒããæ¹åããããã®ããããçš®é¡ã®å©ããæè¿ããŸãã
ãœãŒã¹ïŒ
BitTorrentSpecificationUPD1ã è°è«ã®çµæã«åºã¥ããŠãé
åžçšã®ãã¡ã€ã«ãåŒã£åŒµã£ãŠæ¢åã®ã³ã¬ã¯ã·ã§ã³ãå£ããã«ããããæ£ããã³ã¬ã¯ã·ã§ã³å
ã®ãã¡ã€ã«ãžã®é
åžçšã®é©åãªå Žæã«ããŒããªã³ã¯ãäœæããæ¹ãæ£ããããšãæããã«ãªããŸããïŒäŸãã°ãæ ç»ããã£ã¹ã³ã°ã©ãã£ãŒïŒã å°æ¥ãããã°ã©ã ã¯ãã®ããã«æ©èœããŸãã
UPD2ã ãã®ãŠãŒãã£ãªãã£ã䜿çšããäººãæ©èœããã°ã¬ããŒãã«é¢ããŠä»ã«åžæãããå Žåã¯ãåé¡ãã©ãã«ãŒã®githubã«æ®ããŠãã ããã