Logo
~Apps~
~Projects~
~Contact~


FileManager.cpp

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 2005  Anders Hedstrom
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this program; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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) // single file
00086         {
00087                 std::string full = m_basename;
00088 //DEB(printf("single file: %s\n", full.c_str());)
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         // multi file
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 //DEB(printf("multifile: %s\n", full.c_str());)
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; // offset in buf
00142         size_t left = piece_length;
00143         int64_t ptr = 0;
00144         size_t read_length = 0;
00145 //DEB(printf("ReadPiece(%d, ptr = %lld)\n", index, ptr);)
00146         for (fil_v::iterator it = m_files.begin(); it != m_files.end() && left; it++)
00147         {
00148                 FIL *p = *it;
00149                 // start within this file?
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                         // update
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; // offset in buf
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                 // start within this file?
00211                 if (start < ptr + p -> length)
00212                 {
00213                         long offset = start - ptr;
00214                         size_t len = p -> length - offset; // length of file remaining from start of this write
00215                         if (len > left)
00216                         {
00217                                 len = left;
00218                         }
00219 //DEB(printf("writing@%08x length %04x\n",offset,len);)
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                         // update
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; // name, offset, length
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 //DEB(          printf(" *** Verify(): only read %d bytes out of %d\n",read_length,length);)
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 //DEB(  printf("Verify failed\n");)
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 
Page, code, and content Copyright (C) 2006 by Anders Hedström
Generated on Mon Aug 29 20:21:47 2005 for C++ Sockets by  doxygen 1.4.4