00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef _WIN32
00024 #pragma warning(disable:4786)
00025 #endif
00026 #include <Parse.h>
00027 #include <sys/stat.h>
00028 #include <sys/types.h>
00029 #ifndef _WIN32
00030 #include <unistd.h>
00031 #endif
00032 #include <openssl/sha.h>
00033 #include "PeerHandler.h"
00034 #include "Session.h"
00035 #include "FileManager.h"
00036
00037 #ifdef _DEBUG
00038 #define DEB(x) x
00039 #else
00040 #define DEB(x)
00041 #endif
00042
00043
00044
00045 FileManager::FileManager(PeerHandler& h,const std::string& hash)
00046 :m_hash(hash)
00047 ,m_handler(h)
00048 ,m_single_file(NULL)
00049 {
00050 DEB( printf("FileManager()\n");)
00051 Session *sess = h.GetSession(hash);
00052 if (sess)
00053 {
00054 m_basename = h.GetTorrentDirectory() + "/" + sess -> GetInfoHash() + "/" + sess -> GetName();
00055 GetFiles(m_files);
00056 m_length = sess -> GetLength();
00057
00058 DEB( printf("OpenFiles()\n");)
00059 OpenFiles();
00060 }
00061 }
00062
00063
00064 FileManager::~FileManager()
00065 {
00066 DEB( printf("~FileManager()\n");)
00067 if (m_single_file)
00068 {
00069 fclose(m_single_file);
00070 }
00071 for (fil_v::iterator it = m_files.begin(); it != m_files.end(); it++)
00072 {
00073 FIL *p = *it;
00074 if (p -> fil)
00075 {
00076 fclose(p -> fil);
00077 }
00078 delete p;
00079 }
00080 }
00081
00082
00083 void FileManager::OpenFiles()
00084 {
00085 if (m_length)
00086 {
00087 std::string full = m_basename;
00088
00089 Handler().mkpath( full );
00090 m_single_file = fopen(full.c_str(),"r+b");
00091 if (!m_single_file)
00092 {
00093 m_single_file = fopen(full.c_str(),"w+b");
00094 }
00095 size_t size = GetFilesize(full);
00096 if (size > m_length)
00097 {
00098 DEB( printf("Single file already too large - aborting\n");)
00099 }
00100 return;
00101 }
00102
00103 for (fil_v::iterator it = m_files.begin(); it != m_files.end(); it++)
00104 {
00105 FIL *p = *it;
00106 std::string full = p -> path;
00107
00108 Handler().mkpath( full );
00109 p -> fil = fopen(full.c_str(),"r+b");
00110 if (!p -> fil)
00111 {
00112 p -> fil = fopen(full.c_str(),"w+b");
00113 }
00114 size_t size = GetFilesize(full);
00115 if (size > p -> length)
00116 {
00117 DEB( printf("File '%s' too large - aborting\n",full.c_str());)
00118 }
00119 }
00120 }
00121
00122
00123 size_t FileManager::ReadPiece(size_t index,unsigned char *buf,size_t length)
00124 {
00125 Session *sess = Handler().GetSession(m_hash);
00126 if (!sess)
00127 return 0;
00128 size_t piece_length = sess -> GetPieceLength();
00129 if (m_length)
00130 {
00131 long offset = index * piece_length;
00132 if (fseek(m_single_file,offset,SEEK_SET))
00133 {
00134 DEB( perror("fseek() failed");)
00135 }
00136 size_t n = fread(buf,1,length,m_single_file);
00137 buf[0]++;
00138 return n;
00139 }
00140 int64_t start = index * piece_length;
00141 size_t bufset = 0;
00142 size_t left = piece_length;
00143 int64_t ptr = 0;
00144 size_t read_length = 0;
00145
00146 for (fil_v::iterator it = m_files.begin(); it != m_files.end() && left; it++)
00147 {
00148 FIL *p = *it;
00149
00150 if (start < ptr + p -> length)
00151 {
00152 long offset = start - ptr;
00153 size_t len = p -> length - offset;
00154 if (len > left)
00155 {
00156 len = left;
00157 }
00158 if (fseek(p -> fil,offset,SEEK_SET))
00159 {
00160 DEB( perror("fseek() failed");)
00161 }
00162 read_length += fread(buf + bufset,1,len,p -> fil);
00163
00164 start += len;
00165 bufset += len;
00166 left -= len;
00167 if (!left)
00168 return read_length;
00169 }
00170 ptr += p -> length;
00171 }
00172 buf[0]++;
00173 return read_length;
00174 }
00175
00176
00177 void FileManager::Write(size_t index,unsigned char *buf,size_t length,size_t begin)
00178 {
00179 Session *sess = Handler().GetSession(m_hash);
00180 if (!sess)
00181 return;
00182 size_t piece_length = sess -> GetPieceLength();
00183 if (m_length)
00184 {
00185 long offset = index * piece_length + begin;
00186 if (fseek(m_single_file,offset,SEEK_SET))
00187 {
00188 DEB( perror("fseek() failed");)
00189 }
00190 long pos = ftell(m_single_file);
00191 if (pos < offset)
00192 {
00193 long diff = offset - pos;
00194 char *tmp = new char[diff];
00195 memset(tmp,0,diff);
00196 fwrite(tmp,1,diff,m_single_file);
00197 delete tmp;
00198 }
00199 fwrite(buf,1,length,m_single_file);
00200 fflush(m_single_file);
00201 return;
00202 }
00203 int64_t start = index * piece_length + begin;
00204 size_t bufset = 0;
00205 size_t left = length;
00206 int64_t ptr = 0;
00207 for (fil_v::iterator it = m_files.begin(); it != m_files.end() && left; it++)
00208 {
00209 FIL *p = *it;
00210
00211 if (start < ptr + p -> length)
00212 {
00213 long offset = start - ptr;
00214 size_t len = p -> length - offset;
00215 if (len > left)
00216 {
00217 len = left;
00218 }
00219
00220 if (fseek(p -> fil,offset,SEEK_SET))
00221 {
00222 DEB( perror("fseek() failed");)
00223 }
00224
00225 long pos = ftell(p -> fil);
00226 if (pos < offset)
00227 {
00228 long diff = offset - pos;
00229 char *tmp = new char[diff];
00230 memset(tmp,0,diff);
00231 fwrite(tmp,1,diff,p -> fil);
00232 delete tmp;
00233 DEB(printf(" adding %ld bytes\n",diff);)
00234 }
00235
00236 if (fwrite(buf + bufset,1,len,p -> fil) != len)
00237 {
00238 DEB( printf(" * short write!!!!!!\n");)
00239 }
00240 fflush(p -> fil);
00241
00242 start += len;
00243 bufset += len;
00244 left -= len;
00245 }
00246 ptr += p -> length;
00247 }
00248 }
00249
00250
00251 size_t FileManager::GetFilesize(const std::string& path)
00252 {
00253 struct stat st;
00254 stat(path.c_str(),&st);
00255 return st.st_size;
00256 }
00257
00258
00259 uint64_t FileManager::GetTotalLength()
00260 {
00261 uint64_t l = 0;
00262 for (fil_v::iterator it = m_files.begin(); it != m_files.end(); it++)
00263 {
00264 FIL *p = *it;
00265 l += p -> length;
00266 }
00267 return l;
00268 }
00269
00270
00271 void FileManager::GetFiles(FileManager::fil_v& files)
00272 {
00273 Session *sess = Handler().GetSession(m_hash);
00274 if (!sess)
00275 return;
00276 file_v& ref = sess -> GetFiles();
00277 for (file_v::iterator it = ref.begin(); it != ref.end(); it++)
00278 {
00279 file_t *f = *it;
00280 std::string full = Handler().GetTorrentDirectory() + "/" + sess -> GetInfoHash() + "/" + f -> name;
00281 FIL *p2 = new FIL(f -> length, full);
00282 files.push_back(p2);
00283 }
00284 }
00285
00286
00287 bool FileManager::Verify(size_t index, size_t length)
00288 {
00289 Session *sess = Handler().GetSession(m_hash);
00290 if (!sess)
00291 {
00292 DEB(printf("Verify: no session\n");)
00293 return false;
00294 }
00295 Piece *ptr = sess -> GetIncomplete(index);
00296 if (!ptr)
00297 {
00298 DEB(printf("Verify: no piece ptr\n");)
00299 return false;
00300 }
00301 unsigned char *p = new unsigned char[length];
00302 unsigned char hash[20];
00303 size_t read_length;
00304 read_length = ReadPiece(index, p, length );
00305 if (read_length != length)
00306 {
00307
00308 delete[] p;
00309 return false;
00310 }
00311 SHA1( p, read_length, hash );
00312 delete[] p;
00313 if (CompareHash(hash,(unsigned char *)sess -> GetPieces().substr(index * 20,20).c_str()))
00314 {
00315 DEB( printf("Verify OK!\n");)
00316 return true;
00317 }
00318
00319 return false;
00320 }
00321
00322
00323 bool FileManager::CompareHash(unsigned char *h1,unsigned char *h2)
00324 {
00325 for (size_t i = 0; i < 20; i++)
00326 if (h1[i] != h2[i])
00327 return false;
00328 return true;
00329 }
00330
00331