void tr_setConfigDir( tr_session * session, const char * configDir ) { char * path; session->configDir = tr_strdup( configDir ); path = tr_buildPath( configDir, RESUME_SUBDIR, NULL ); tr_mkdirp( path, 0777 ); session->resumeDir = path; path = tr_buildPath( configDir, TORRENT_SUBDIR, NULL ); tr_mkdirp( path, 0777 ); session->torrentDir = path; migrateFiles( session ); }
/** * returns 0 on success, or an errno value on failure. * errno values include ENOENT if the parent folder doesn't exist, * plus the errno values set by tr_mkdirp() and open(). */ static int TrOpenFile( int i, const char * folder, const char * torrentFile, int doWrite, int doPreallocate, uint64_t desiredFileSize ) { struct tr_openfile * file = &gFd->open[i]; int flags; char * filename; struct stat sb; int alreadyExisted; /* confirm the parent folder exists */ if( stat( folder, &sb ) || !S_ISDIR( sb.st_mode ) ) return ENOENT; /* create subfolders, if any */ filename = tr_buildPath( folder, torrentFile, NULL ); if( doWrite ) { char * tmp = tr_dirname( filename ); const int err = tr_mkdirp( tmp, 0777 ) ? errno : 0; tr_free( tmp ); if( err ) { tr_free( filename ); return err; } } alreadyExisted = !stat( filename, &sb ) && S_ISREG( sb.st_mode ); if( doWrite && !alreadyExisted && doPreallocate ) if( preallocateFile( filename, desiredFileSize ) ) tr_inf( _( "Preallocated file \"%s\"" ), filename ); /* open the file */ flags = doWrite ? ( O_RDWR | O_CREAT ) : O_RDONLY; #ifdef O_LARGEFILE flags |= O_LARGEFILE; #endif #ifdef WIN32 flags |= O_BINARY; #endif file->fd = open( filename, flags, 0666 ); if( file->fd == -1 ) { const int err = errno; tr_err( _( "Couldn't open \"%1$s\": %2$s" ), filename, tr_strerror( err ) ); tr_free( filename ); return err; } tr_free( filename ); return 0; }
void tr_setConfigDir( tr_handle * handle, const char * configDir ) { char * path; handle->configDir = tr_strdup( configDir ); path = tr_buildPath( configDir, RESUME_SUBDIR, NULL ); tr_mkdirp( path, 0777 ); handle->resumeDir = path; path = tr_buildPath( configDir, TORRENT_SUBDIR, NULL ); tr_mkdirp( path, 0777 ); handle->torrentDir = path; migrateFiles( handle ); }
int gtr_mkdir_with_parents( const char * path, int mode ) { #if GLIB_CHECK_VERSION( 2, 8, 0 ) return !g_mkdir_with_parents( path, mode ); #else return !tr_mkdirp( path, mode ); #endif }
void libttest_zero_torrent_populate (tr_torrent * tor, bool complete) { tr_file_index_t i; for (i=0; i<tor->info.fileCount; ++i) { int err; uint64_t j; FILE * fp; char * path; char * dirname; const tr_file * file = &tor->info.files[i]; struct stat sb; if (!complete && (i==0)) path = tr_strdup_printf ("%s%c%s.part", tor->currentDir, TR_PATH_DELIMITER, file->name); else path = tr_strdup_printf ("%s%c%s", tor->currentDir, TR_PATH_DELIMITER, file->name); dirname = tr_dirname (path); tr_mkdirp (dirname, 0700); fp = fopen (path, "wb+"); for (j=0; j<file->length; ++j) fputc (((!complete) && (i==0) && (j<tor->info.pieceSize)) ? '\1' : '\0', fp); fclose (fp); tr_free (dirname); tr_free (path); path = tr_torrentFindFile (tor, i); assert (path != NULL); err = errno; errno = 0; stat (path, &sb); assert (errno == 0); errno = err; tr_free (path); } sync (); libttest_blockingTorrentVerify (tor); if (complete) assert (tr_torrentStat(tor)->leftUntilDone == 0); else assert (tr_torrentStat(tor)->leftUntilDone == tor->info.pieceSize); }
static void create_text_file (const char * path, const char * contents) { FILE * fp; char * dir; dir = tr_dirname (path); tr_mkdirp (dir, 0700); tr_free (dir); tr_remove (path); fp = fopen (path, "w+"); fprintf (fp, "%s", contents); fclose (fp); sync (); }
/* this is for really old versions of T and will probably be removed someday */ void tr_metainfoMigrate( tr_session * session, tr_info * inf ) { struct stat new_sb; char * name = getTorrentFilename( session, inf ); if( stat( name, &new_sb ) || ( ( new_sb.st_mode & S_IFMT ) != S_IFREG ) ) { char * old_name = getOldTorrentFilename( session, inf ); size_t contentLen; uint8_t * content; tr_mkdirp( tr_getTorrentDir( session ), 0777 ); if( ( content = tr_loadFile( old_name, &contentLen ) ) ) { FILE * out; errno = 0; out = fopen( name, "wb+" ); if( !out ) { tr_nerr( inf->name, _( "Couldn't create \"%1$s\": %2$s" ), name, tr_strerror( errno ) ); } else { if( fwrite( content, sizeof( uint8_t ), contentLen, out ) == contentLen ) { tr_free( inf->torrent ); inf->torrent = tr_strdup( name ); tr_sessionSetTorrentFile( session, inf->hashString, name ); unlink( old_name ); } fclose( out ); } } tr_free( content ); tr_free( old_name ); } tr_free( name ); }
/** * returns 0 on success, or an errno value on failure. * errno values include ENOENT if the parent folder doesn't exist, * plus the errno values set by tr_mkdirp () and open (). */ static int cached_file_open (struct tr_cached_file * o, const char * filename, bool writable, tr_preallocation_mode allocation, uint64_t file_size) { int flags; struct stat sb; bool alreadyExisted; /* create subfolders, if any */ if (writable) { char * dir = tr_dirname (filename); const int err = tr_mkdirp (dir, 0777) ? errno : 0; if (err) { tr_err (_("Couldn't create \"%1$s\": %2$s"), dir, tr_strerror (err)); tr_free (dir); return err; } tr_free (dir); } alreadyExisted = !stat (filename, &sb) && S_ISREG (sb.st_mode); if (writable && !alreadyExisted && (allocation == TR_PREALLOCATE_FULL)) if (preallocate_file_full (filename, file_size)) tr_dbg ("Preallocated file \"%s\"", filename); /* open the file */ flags = writable ? (O_RDWR | O_CREAT) : O_RDONLY; flags |= O_LARGEFILE | O_BINARY | O_SEQUENTIAL; o->fd = open (filename, flags, 0666); if (o->fd == -1) { const int err = errno; tr_err (_("Couldn't open \"%1$s\": %2$s"), filename, tr_strerror (err)); return err; } /* If the file already exists and it's too large, truncate it. * This is a fringe case that happens if a torrent's been updated * and one of the updated torrent's files is smaller. * http://trac.transmissionbt.com/ticket/2228 * https://bugs.launchpad.net/ubuntu/+source/transmission/+bug/318249 */ if (alreadyExisted && (file_size < (uint64_t)sb.st_size)) { if (ftruncate (o->fd, file_size) == -1) { const int err = errno; tr_err (_("Couldn't truncate \"%1$s\": %2$s"), filename, tr_strerror (err)); return err; } } if (writable && !alreadyExisted && (allocation == TR_PREALLOCATE_SPARSE)) preallocate_file_sparse (o->fd, file_size); /* Many (most?) clients request blocks in ascending order, * so increase the readahead buffer. * Also, disable OS-level caching because "inactive memory" angers users. */ tr_set_file_for_single_pass (o->fd); return 0; }
static void tr_sessionInitImpl( void * vdata ) { int64_t i; int64_t j; double d; tr_bool found; const char * str; tr_benc settings; char * filename; struct init_data * data = vdata; tr_benc * clientSettings = data->clientSettings; tr_session * session = data->session; assert( tr_amInEventThread( session ) ); assert( tr_bencIsDict( clientSettings ) ); dbgmsg( "tr_sessionInit: the session's top-level bandwidth object is %p", session->bandwidth ); tr_bencInitDict( &settings, 0 ); tr_sessionGetDefaultSettings( &settings ); tr_bencMergeDicts( &settings, clientSettings ); #ifndef WIN32 /* Don't exit when writing on a broken socket */ signal( SIGPIPE, SIG_IGN ); #endif found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ); assert( found ); session->peerLimitPerTorrent = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_MSGLEVEL, &i ); assert( found ); tr_setMessageLevel( i ); tr_setMessageQueuing( data->messageQueuingEnabled ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEX_ENABLED, &i ); assert( found ); session->isPexEnabled = i != 0; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ENCRYPTION, &i ); assert( found ); assert( tr_isEncryptionMode( i ) ); session->encryptionMode = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PREALLOCATION, &i ); assert( found ); assert( tr_isPreallocationMode( i ) ); session->preallocationMode = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_SOCKET_TOS, &i ); assert( found ); session->peerSocketTOS = i; found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, &str ); assert( found ); session->downloadDir = tr_strdup( str ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_ENABLED, &i ); assert( found ); session->isProxyEnabled = i != 0; found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY, &str ); assert( found ); session->proxy = tr_strdup( str ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_PORT, &i ); assert( found ); session->proxyPort = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_TYPE, &i ); assert( found ); session->proxyType = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_AUTH_ENABLED, &i ); assert( found ); session->isProxyAuthEnabled = i != 0; found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_USERNAME, &str ); assert( found ); session->proxyUsername = tr_strdup( str ); found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_PASSWORD, &str ); assert( found ); session->proxyPassword = tr_strdup( str ); session->so_sndbuf = 1500 * 3; /* 3x MTU for most ethernet/wireless */ session->so_rcvbuf = 8192; tr_setConfigDir( session, data->configDir ); tr_trackerSessionInit( session ); assert( session->tracker != NULL ); session->peerMgr = tr_peerMgrNew( session ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_LAZY_BITFIELD, &i ); assert( found ); session->useLazyBitfield = i != 0; /* Initialize rate and file descripts controls */ found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_OPEN_FILE_LIMIT, &i ); assert( found ); session->openFileLimit = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, &j ); assert( found ); tr_fdInit( session->openFileLimit, j ); /** *** random port **/ found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_ENABLED, &i ); assert( found ); session->isPortRandom = i != 0; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i ); assert( found ); session->randomPortLow = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, &i ); assert( found ); session->randomPortHigh = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PORT_FORWARDING, &i ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT, &j ); assert( found ); session->peerPort = session->isPortRandom ? getRandomPort( session ) : j; session->shared = tr_sharedInit( session, i, session->peerPort ); session->isPortSet = session->isPortRandom || j>0; /** **/ found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, &i ); assert( found ); session->uploadSlotsPerTorrent = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED, &i ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED_ENABLED, &j ); assert( found ); tr_sessionSetSpeedLimit( session, TR_UP, i ); tr_sessionSetSpeedLimitEnabled( session, TR_UP, j ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED, &i ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED_ENABLED, &j ); assert( found ); tr_sessionSetSpeedLimit( session, TR_DOWN, i ); tr_sessionSetSpeedLimitEnabled( session, TR_DOWN, j ); found = tr_bencDictFindDouble( &settings, TR_PREFS_KEY_RATIO, &d ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_RATIO_ENABLED, &j ); assert( found ); tr_sessionSetRatioLimit( session, d ); tr_sessionSetRatioLimited( session, j ); /* initialize the blocklist */ filename = tr_buildPath( session->configDir, "blocklists", NULL ); tr_mkdirp( filename, 0777 ); tr_free( filename ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &i ); assert( found ); session->isBlocklistEnabled = i; loadBlocklists( session ); session->rpcServer = tr_rpcInit( session, &settings ); tr_bencFree( &settings ); assert( tr_isSession( session ) ); /* first %s is the application name second %s is the version number */ tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING ); tr_statsInit( session ); session->web = tr_webInit( session ); metainfoLookupRescan( session ); session->isWaiting = FALSE; dbgmsg( "returning session %p; session->tracker is %p", session, session->tracker ); }
/** * returns 0 on success, or an errno value on failure. * errno values include ENOENT if the parent folder doesn't exist, * plus the errno values set by tr_mkdirp() and open(). */ static int TrOpenFile( tr_session * session, int i, const char * filename, tr_bool doWrite, tr_preallocation_mode preallocationMode, uint64_t desiredFileSize ) { int flags; struct stat sb; tr_bool alreadyExisted; struct tr_openfile * file; assert( tr_isSession( session ) ); assert( session->fdInfo != NULL ); file = &session->fdInfo->openFiles[i]; /* create subfolders, if any */ if( doWrite ) { char * dir = tr_dirname( filename ); const int err = tr_mkdirp( dir, 0777 ) ? errno : 0; if( err ) { tr_err( _( "Couldn't create \"%1$s\": %2$s" ), dir, tr_strerror( err ) ); tr_free( dir ); return err; } tr_free( dir ); } alreadyExisted = !stat( filename, &sb ) && S_ISREG( sb.st_mode ); if( doWrite && !alreadyExisted && ( preallocationMode == TR_PREALLOCATE_FULL ) ) if( preallocateFileFull( filename, desiredFileSize ) ) tr_dbg( _( "Preallocated file \"%s\"" ), filename ); /* open the file */ flags = doWrite ? ( O_RDWR | O_CREAT ) : O_RDONLY; #ifdef O_SEQUENTIAL flags |= O_SEQUENTIAL; #endif #ifdef O_LARGEFILE flags |= O_LARGEFILE; #endif #ifdef WIN32 flags |= O_BINARY; #endif file->fd = open( filename, flags, 0666 ); if( file->fd == -1 ) { const int err = errno; tr_err( _( "Couldn't open \"%1$s\": %2$s" ), filename, tr_strerror( err ) ); return err; } /* If the file already exists and it's too large, truncate it. * This is a fringe case that happens if a torrent's been updated * and one of the updated torrent's files is smaller. * http://trac.transmissionbt.com/ticket/2228 * https://bugs.launchpad.net/ubuntu/+source/transmission/+bug/318249 */ if( alreadyExisted && ( desiredFileSize < (uint64_t)sb.st_size ) ) ftruncate( file->fd, desiredFileSize ); if( doWrite && !alreadyExisted && ( preallocationMode == TR_PREALLOCATE_SPARSE ) ) preallocateFileSparse( file->fd, desiredFileSize ); #ifdef HAVE_POSIX_FADVISE /* this doubles the OS level readahead buffer, which in practice * turns out to be a good thing, because many (most?) clients request * chunks of blocks in order. * It's okay for this to fail silently, so don't let it affect errno */ { const int err = errno; posix_fadvise( file->fd, 0, 0, POSIX_FADV_SEQUENTIAL ); errno = err; } #endif #if defined( SYS_DARWIN ) /** * 1. Enable readahead for reasons described above w/POSIX_FADV_SEQUENTIAL. * * 2. Disable OS-level caching due to user reports of adverse effects of * excessive inactive memory. However this is experimental because * previous attempts at this have *also* had adverse effects (see r8198) * * It's okay for this to fail silently, so don't let it affect errno */ { const int err = errno; fcntl( file->fd, F_NOCACHE, 1 ); fcntl( file->fd, F_RDAHEAD, 1 ); errno = err; } #endif return 0; }
tr_session * libttest_session_init (tr_variant * settings) { size_t len; const char * str; char * sandbox; char * path; tr_quark q; static bool formatters_inited = false; tr_session * session; tr_variant local_settings; tr_variantInitDict (&local_settings, 10); if (settings == NULL) settings = &local_settings; sandbox = libtest_sandbox_create (); if (!formatters_inited) { formatters_inited = true; tr_formatter_mem_init (MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR); tr_formatter_size_init (DISK_K,DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR); tr_formatter_speed_init (SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR); } /* download dir */ q = TR_KEY_download_dir; if (tr_variantDictFindStr (settings, q, &str, &len)) path = tr_strdup_printf ("%s/%*.*s", sandbox, (int)len, (int)len, str); else path = tr_buildPath (sandbox, "Downloads", NULL); tr_mkdirp (path, 0700); tr_variantDictAddStr (settings, q, path); tr_free (path); /* incomplete dir */ q = TR_KEY_incomplete_dir; if (tr_variantDictFindStr (settings, q, &str, &len)) path = tr_strdup_printf ("%s/%*.*s", sandbox, (int)len, (int)len, str); else path = tr_buildPath (sandbox, "Incomplete", NULL); tr_variantDictAddStr (settings, q, path); tr_free (path); path = tr_buildPath (sandbox, "blocklists", NULL); tr_mkdirp (path, 0700); tr_free (path); q = TR_KEY_port_forwarding_enabled; if (!tr_variantDictFind (settings, q)) tr_variantDictAddBool (settings, q, false); q = TR_KEY_dht_enabled; if (!tr_variantDictFind (settings, q)) tr_variantDictAddBool (settings, q, false); q = TR_KEY_message_level; if (!tr_variantDictFind (settings, q)) tr_variantDictAddInt (settings, q, verbose ? TR_LOG_DEBUG : TR_LOG_ERROR); session = tr_sessionInit ("libtransmission-test", sandbox, !verbose, settings); tr_free (sandbox); tr_variantFree (&local_settings); return session; }