⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 btfiles.cpp

📁 cTorrent advanced 3.3.2。是对 CTorrent 的一个改进版本。这是目前的最新版。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "btfiles.h"#ifdef WINDOWS#include <io.h>#include <memory.h>#include <direct.h>#else#include <unistd.h>#include <dirent.h>#include <sys/param.h>#endif#include <sys/stat.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <errno.h>#include <ctype.h>  // isprint#include "bencode.h"#include "btcontent.h"#include "bitfield.h"#include "console.h"#include "bttime.h"#ifndef HAVE_SNPRINTF#include "compat.h"#endif#define MAX_OPEN_FILES 20btFiles::btFiles(){  m_btfhead = (BTFILE*) 0;  m_nfiles = 0;  m_file = (BTFILE **)0;  m_total_files_length = 0;  m_total_opened = 0;  m_flag_automanage = 1;  m_directory = (char*)0;}btFiles::~btFiles(){  _btf_destroy();  if( m_directory ) delete []m_directory;}BTFILE* btFiles::_new_bfnode(){  BTFILE *pnew = new BTFILE;#ifndef WINDOWS  if( !pnew ) return (BTFILE*) 0;#endif  pnew->bf_flag_opened = 0;  pnew->bf_flag_readonly = 0;  pnew->bf_filename = (char*) 0;  pnew->bf_fp = (FILE*) 0;  pnew->bf_length = 0;  pnew->bf_buffer = (char *) 0;  pnew->bf_last_timestamp = (time_t) 0;  pnew->bf_next = (BTFILE*) 0;  return pnew;}void btFiles::CloseFile(size_t nfile){  if( nfile && nfile <= m_nfiles )    _btf_close(m_file[nfile-1]);}int btFiles::_btf_close_oldest(){  BTFILE *pbf_n,*pbf_close;  pbf_close = (BTFILE *) 0;  for(pbf_n = m_btfhead; pbf_n; pbf_n = pbf_n->bf_next){    if(!pbf_n->bf_flag_opened) continue; // file not been opened.    if(!pbf_close || pbf_n->bf_last_timestamp < pbf_close->bf_last_timestamp)      pbf_close = pbf_n;  }  if(!pbf_close) return -1;  return _btf_close(pbf_close);}int btFiles::_btf_close(BTFILE *pbf){  if( !pbf->bf_flag_opened ) return 0;  if( fclose(pbf->bf_fp) == EOF )    CONSOLE.Warning(2, "warn, error closing file \"%s\":  %s",      pbf->bf_filename, strerror(errno));  pbf->bf_flag_opened = 0;  pbf->bf_fp = (FILE *)0;  if( pbf->bf_buffer ){    delete []pbf->bf_buffer;    pbf->bf_buffer = (char *)0;  }  m_total_opened--;  return 0;}int btFiles::_btf_open(BTFILE *pbf, const int iotype){  char fn[MAXPATHLEN];  if( pbf->bf_flag_opened ){    if( pbf->bf_flag_readonly && iotype ) _btf_close(pbf);    else return 0;  // already open in a usable mode  }    if(m_flag_automanage && (m_total_opened >= MAX_OPEN_FILES)){  // close a file    if( _btf_close_oldest() < 0 ) return -1;  }  if( m_directory ){    if( MAXPATHLEN <= snprintf(fn, MAXPATHLEN, "%s%c%s", m_directory, PATH_SP,                               pbf->bf_filename) ){      errno = ENAMETOOLONG;      return -1;    }  }else{    strcpy(fn, pbf->bf_filename);  }  pbf->bf_last_timestamp = now + 1;  if( !(pbf->bf_fp = fopen(fn, iotype ? "r+b" : "rb")) ){    if( EMFILE == errno || ENFILE == errno ){      if( _btf_close_oldest() < 0 ||          !(pbf->bf_fp = fopen(fn, iotype ? "r+b" : "rb")) )        return -1;  // caller prints error    }else return -1;  // caller prints error  }  pbf->bf_buffer = new char[DEFAULT_SLICE_SIZE];  if(pbf->bf_buffer)    setvbuf(pbf->bf_fp, pbf->bf_buffer, _IOFBF, DEFAULT_SLICE_SIZE);  pbf->bf_flag_opened = 1;  pbf->bf_flag_readonly = iotype ? 0 : 1;  m_total_opened++;  return 0;}ssize_t btFiles::IO(char *buf, uint64_t off, size_t len, const int iotype){  uint64_t n = 0;  off_t pos,nio;  BTFILE *pbf = m_btfhead;  if( (off + (uint64_t)len) > m_total_files_length ){    CONSOLE.Warning(1, "error, data offset %llu length %lu out of range",      (unsigned long long)off, (unsigned long)len);    return -1;  }  for(; pbf; pbf = pbf->bf_next){    n += (uint64_t) pbf->bf_length;    if(n > off) break;  }  if( !pbf ){    CONSOLE.Warning(1, "error, failed to find file for offset %llu",      (unsigned long long)off);    return -1;  }  pos = off - (n - pbf->bf_length);  for(; len ;){    if( (!pbf->bf_flag_opened || (iotype && pbf->bf_flag_readonly)) &&        _btf_open(pbf, iotype) < 0 ){      CONSOLE.Warning(1, "error, failed to open file \"%s\":  %s",        pbf->bf_filename, strerror(errno));      return -1;    }    pbf->bf_last_timestamp = now;#ifdef HAVE_FSEEKO    if( fseeko(pbf->bf_fp,pos,SEEK_SET) < 0 ){#else    if( fseek(pbf->bf_fp,(long) pos,SEEK_SET) < 0 ){#endif      CONSOLE.Warning(1, "error, failed to seek to %llu on file \"%s\":  %s",        (unsigned long long)pos, pbf->bf_filename, strerror(errno));      return -1;    }//  }    nio = (len < pbf->bf_length - pos) ? len : (pbf->bf_length - pos);    if(0 == iotype){      errno = 0;      if( 1 != fread(buf,nio,1,pbf->bf_fp) && ferror(pbf->bf_fp) ){        CONSOLE.Warning(1, "error, read failed at %llu on file \"%s\":  %s",          (unsigned long long)pos, pbf->bf_filename, strerror(errno));        return -1;      }    }else{      errno = 0;      if( 1 != fwrite(buf,nio,1,pbf->bf_fp) ){        CONSOLE.Warning(1, "error, write failed at %llu on file \"%s\":  %s",          (unsigned long long)pos, pbf->bf_filename, strerror(errno));        return -1;      }      if( fflush(pbf->bf_fp) == EOF ){        CONSOLE.Warning(1, "error, flush failed at %llu on file \"%s\":  %s",          (unsigned long long)pos, pbf->bf_filename, strerror(errno));        return -1;      }    }    len -= nio;    buf += nio;    if( len ){      do{        pbf = pbf->bf_next;        if( !pbf ){          CONSOLE.Warning(1,            "error, data left over with no more files to write");          return -1;        }      }while( 0==pbf->bf_length );      pos = 0;    }  } // end for  return 0;}int btFiles::_btf_destroy(){  BTFILE *pbf,*pbf_next;  for(pbf = m_btfhead; pbf;){    pbf_next = pbf->bf_next;    if( pbf->bf_fp && pbf->bf_flag_opened ) fclose( pbf->bf_fp );    if( pbf->bf_filename ) delete []pbf->bf_filename;    if( pbf->bf_buffer ) delete []pbf->bf_buffer;    delete pbf;    pbf = pbf_next;  }  m_btfhead = (BTFILE*) 0;  m_total_files_length = (uint64_t) 0;  m_total_opened = 0;  return 0;}int btFiles::_btf_ftruncate(int fd,int64_t length){  if( arg_allocate ){    char *c = new char[256*1024];    if( !c ){ errno = ENOMEM; return -1; }    memset(c, 0, 256*1024);    int r, wlen;    int64_t len = 0;    for( int i=0; len < length; i++ ){      if( len + 256*1024 > length ) wlen = (int)(length - len);      else wlen = 256*1024;      if( 0 == i % 100 ) CONSOLE.Interact_n(".");      if( (r = write(fd, c, wlen)) < 0 ) return r;      len += wlen;    }    delete []c;    return r;  }#ifdef WINDOWS  char c = (char)0;  if( lseek(fd,length - 1, SEEK_SET) < 0 ) return -1;  return write(fd, &c, 1);#else  // ftruncate() not allowed on [v]fat under linux  int retval = ftruncate(fd,length);  if( retval < 0 ) {    char c = (char)0;    if( lseek(fd,length - 1, SEEK_SET) < 0 ) return -1;    return write(fd, &c, 1);  }  else return retval;#endif}int btFiles::_btf_recurses_directory(const char *cur_path, BTFILE* *plastnode){  char full_cur[MAXPATHLEN];  char fn[MAXPATHLEN];  struct stat sb;  struct dirent *dirp;  DIR *dp;  BTFILE *pbf;  if( !getcwd(full_cur,MAXPATHLEN) ) return -1;  if( cur_path ){    strcpy(fn, full_cur);    if( MAXPATHLEN <= snprintf(full_cur, MAXPATHLEN, "%s%c%s", fn, PATH_SP,                               cur_path) ){      errno = ENAMETOOLONG;      return -1;    }  }        if( (DIR*) 0 == (dp = opendir(full_cur)) ){    CONSOLE.Warning(1, "error, open directory \"%s\" failed:  %s",      cur_path, strerror(errno));    return -1;  }  while( (struct dirent*) 0 != (dirp = readdir(dp)) ){        if( 0 == strcmp(dirp->d_name, ".") ||        0 == strcmp(dirp->d_name, "..") ) continue;    if( cur_path ){      if(MAXPATHLEN < snprintf(fn, MAXPATHLEN, "%s%c%s", cur_path, PATH_SP,                               dirp->d_name)){        CONSOLE.Warning(1, "error, pathname too long");        errno = ENAMETOOLONG;        return -1;      }    }else{      strcpy(fn, dirp->d_name);    }    if( stat(fn, &sb) < 0 ){      CONSOLE.Warning(1, "error, stat \"%s\" failed:  %s",fn,strerror(errno));      return -1;    }    if( S_IFREG & sb.st_mode ){            pbf = _new_bfnode();#ifndef WINDOWS      if( !pbf ){ errno = ENOMEM; return -1; }#endif      pbf->bf_filename = new char[strlen(fn) + 1];#ifndef WINDOWS      if( !pbf->bf_filename ){ closedir(dp); errno = ENOMEM; return -1; }#endif      strcpy(pbf->bf_filename, fn);            pbf->bf_length = sb.st_size;      m_total_files_length += sb.st_size;      if( *plastnode ) (*plastnode)->bf_next = pbf; else m_btfhead = pbf;      *plastnode = pbf;    }else if( S_IFDIR & sb.st_mode ){      if(_btf_recurses_directory(fn, plastnode) < 0){closedir(dp); return -1;}    }else{      CONSOLE.Warning(1, "error, \"%s\" is not a directory or regular file.",        fn);      closedir(dp);      return -1;    }  } // end while  closedir(dp);  return 0;}int btFiles::_btf_creat_by_path(const char *pathname, int64_t file_length){  struct stat sb;  int fd;  char *p,*pnext,last = 0;  char sp[MAXPATHLEN];  strcpy(sp,pathname);  pnext = sp;  if(PATH_SP == *pnext) pnext++;  for(; !last; ){    for(p = pnext; *p && PATH_SP != *p; p++) ;    if( !*p ) last = 1;    if(last && PATH_SP == *p){ last = 0; break;}    *p = '\0';    if(stat(sp,&sb) < 0){      if( ENOENT == errno ){        if( !last ){#ifdef WINDOWS          if(mkdir(sp) < 0) break;#else          if(mkdir(sp,0755) < 0) break;#endif        }else{          if((fd = creat(sp,0644)) < 0){ last = 0; break; }          if(file_length && _btf_ftruncate(fd, file_length) < 0){            close(fd); last = 0; break;          }          close(fd);        }      }else{last = 0; break;}    }    if( !last ){ *p = PATH_SP; pnext = p + 1; }  }  return last;}int btFiles::BuildFromFS(const char *pathname){  struct stat sb;  BTFILE *pbf = (BTFILE*) 0;  BTFILE *lastnode = (BTFILE*) 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -