📄 btfiles.cpp
字号:
#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 + -