static const char * getOldConfigDir( void ) { static char * path = NULL; if( !path ) { #ifdef __BEOS__ char buf[MAX_PATH_LENGTH]; find_directory( B_USER_SETTINGS_DIRECTORY, dev_for_path( "/boot" ), true, buf, sizeof( buf ) ); path = tr_buildPath( buf, "Transmission", NULL ); #elif defined( SYS_DARWIN ) path = tr_buildPath( getHomeDir( ), "Library", "Application Support", "Transmission", NULL ); #elif defined( __AMIGAOS4__ ) path = tr_strdup( "PROGDIR:.transmission" ); #elif defined( WIN32 ) char appdata[MAX_PATH]; /* SHGetFolderPath() requires MAX_PATH */ SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, appdata ); path = tr_buildPath( appdata, "Transmission", NULL ); #else path = tr_buildPath( getHomeDir( ), ".transmission", NULL ); #endif } return path; }
static int test_path_exists (void) { char * const test_dir = create_test_dir (__FUNCTION__); tr_error * err = NULL; char * path1, * path2; path1 = tr_buildPath (test_dir, "a", NULL); path2 = tr_buildPath (test_dir, "b", NULL); /* Non-existent file does not exist */ check (!tr_sys_path_exists (path1, &err)); check (err == NULL); /* Create file and see that it exists */ libtest_create_file_with_string_contents (path1, "test"); check (tr_sys_path_exists (path1, &err)); check (err == NULL); tr_sys_path_remove (path1, NULL); /* Create directory and see that it exists */ tr_sys_dir_create (path1, 0, 0777, NULL); check (tr_sys_path_exists (path1, &err)); check (err == NULL); tr_sys_path_remove (path1, NULL); if (create_symlink (path1, path2, false)) { /* Non-existent file does not exist (via symlink) */ check (!tr_sys_path_exists (path1, &err)); check (err == NULL); /* Create file and see that it exists (via symlink) */ libtest_create_file_with_string_contents (path2, "test"); check (tr_sys_path_exists (path1, &err)); check (err == NULL); tr_sys_path_remove (path2, NULL); /* Create directory and see that it exists (via symlink) */ tr_sys_dir_create (path2, 0, 0777, NULL); check (tr_sys_path_exists (path1, &err)); check (err == NULL); tr_sys_path_remove (path2, NULL); tr_sys_path_remove (path1, NULL); } else { fprintf (stderr, "WARNING: [%s] unable to run symlink tests\n", __FUNCTION__); } tr_free (path2); tr_free (path1); tr_free (test_dir); return 0; }
static void moveFiles( const char * oldDir, const char * newDir ) { if( oldDir && newDir && strcmp( oldDir, newDir ) ) { DIR * dirh = opendir( oldDir ); if( dirh ) { int count = 0; struct dirent * dirp; while( ( dirp = readdir( dirh ) ) ) { if( strcmp( dirp->d_name, "." ) && strcmp( dirp->d_name, ".." ) ) { char * o = tr_buildPath( oldDir, dirp->d_name, NULL ); char * n = tr_buildPath( newDir, dirp->d_name, NULL ); rename( o, n ); ++count; tr_free( n ); tr_free( o ); } } if( count ) tr_inf( _( "Migrated %1$d files from \"%2$s\" to \"%3$s\"" ), count, oldDir, newDir ); closedir( dirh ); } } }
static const char * getOldConfigDir( void ) { static char * path = NULL; if( !path ) { #ifdef SYS_DARWIN path = tr_buildPath( getHomeDir( ), "Library", "Application Support", "Transmission", NULL ); #elif defined( WIN32 ) char appdata[MAX_PATH]; /* SHGetFolderPath() requires MAX_PATH */ SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, appdata ); path = tr_buildPath( appdata, "Transmission", NULL ); #elif defined( __HAIKU__ ) char buf[TR_PATH_MAX]; find_directory( B_USER_SETTINGS_DIRECTORY, -1, true, buf, sizeof(buf) ); path = tr_buildPath( buf, "Transmission", NULL ); #else path = tr_buildPath( getHomeDir( ), ".transmission", NULL ); #endif } return path; }
const char* tr_getDefaultConfigDir( void ) { static char * s = NULL; if( !s ) { if( ( s = getenv( "TRANSMISSION_HOME" ) ) ) { s = tr_strdup( s ); } else { #ifdef SYS_DARWIN s = tr_buildPath( getHomeDir( ), "Library", "Application Support", "Transmission", NULL ); #elif defined( WIN32 ) char appdata[MAX_PATH]; /* SHGetFolderPath() requires MAX_PATH */ SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, appdata ); s = tr_buildPath( appdata, "Transmission", NULL ); #else if( ( s = getenv( "XDG_CONFIG_HOME" ) ) ) s = tr_buildPath( s, "transmission", NULL ); else s = tr_buildPath( getHomeDir( ), ".config", "transmission", NULL ); #endif } } return s; }
const char* tr_getDefaultDownloadDir (void) { static char * user_dir = NULL; if (user_dir == NULL) { const char * config_home; char * config_file; char * content; size_t content_len; /* figure out where to look for user-dirs.dirs */ config_home = getenv ("XDG_CONFIG_HOME"); if (config_home && *config_home) config_file = tr_buildPath (config_home, "user-dirs.dirs", NULL); else config_file = tr_buildPath (getHomeDir (), ".config", "user-dirs.dirs", NULL); /* read in user-dirs.dirs and look for the download dir entry */ content = (char *) tr_loadFile (config_file, &content_len); if (content && content_len>0) { const char * key = "XDG_DOWNLOAD_DIR=\""; char * line = strstr (content, key); if (line != NULL) { char * value = line + strlen (key); char * end = strchr (value, '"'); if (end) { *end = '\0'; if (!memcmp (value, "$HOME/", 6)) user_dir = tr_buildPath (getHomeDir (), value+6, NULL); else if (!strcmp (value, "$HOME")) user_dir = tr_strdup (getHomeDir ()); else user_dir = tr_strdup (value); } } } if (user_dir == NULL) #ifdef __HAIKU__ user_dir = tr_buildPath (getHomeDir (), "Desktop", NULL); #else user_dir = tr_buildPath (getHomeDir (), "Downloads", NULL); #endif tr_free (content); tr_free (config_file); } return user_dir; }
static int test_buildpath (void) { char * out; out = tr_buildPath ("foo", "bar", NULL); check_streq ("foo" TR_PATH_DELIMITER_STR "bar", out); tr_free (out); out = tr_buildPath ("", "foo", "bar", NULL); check_streq (TR_PATH_DELIMITER_STR "foo" TR_PATH_DELIMITER_STR "bar", out); tr_free (out); return 0; }
static void rm_rf (const char * killme) { struct stat sb; if (!stat (killme, &sb)) { DIR * odir; if (S_ISDIR (sb.st_mode) && ((odir = opendir (killme)))) { struct dirent *d; for (d = readdir(odir); d != NULL; d=readdir(odir)) { if (d->d_name && strcmp(d->d_name,".") && strcmp(d->d_name,"..")) { char * tmp = tr_buildPath (killme, d->d_name, NULL); rm_rf (tmp); tr_free (tmp); } } closedir (odir); } if (verbose) fprintf (stderr, "cleanup: removing %s\n", killme); tr_remove (killme); } }
static char* getOldTorrentFilename( const tr_session * session, const tr_info * inf ) { int i; char * path; struct stat sb; const int tagCount = 5; const char * tags[] = { "beos", "cli", "daemon", "macosx", "wx" }; /* test the beos, cli, daemon, macosx, wx tags */ for( i=0; i<tagCount; ++i ) { path = tr_strdup_printf( "%s%c%s-%s", tr_getTorrentDir( session ), '/', inf->hashString, tags[i] ); if( !stat( path, &sb ) && ( ( sb.st_mode & S_IFMT ) == S_IFREG ) ) return path; tr_free( path ); } /* test a non-tagged file */ path = tr_buildPath( tr_getTorrentDir( session ), inf->hashString, NULL ); if( !stat( path, &sb ) && ( ( sb.st_mode & S_IFMT ) == S_IFREG ) ) return path; tr_free( path ); /* return the -gtk form by default, since that's the most common case. don't bother testing stat() on it since this is the last candidate and we don't want to return NULL anyway */ return tr_strdup_printf( "%s%c%s-%s", tr_getTorrentDir( session ), '/', inf->hashString, "gtk" ); }
static tr_time_t* getMTimes( const tr_torrent * tor, int * setme_n ) { int i; const int n = tor->info.fileCount; tr_time_t * m = calloc( n, sizeof( tr_time_t ) ); for( i = 0; i < n; ++i ) { struct stat sb; char * fname = tr_buildPath( tor->downloadDir, tor->info.files[i].name, NULL ); if( !stat( fname, &sb ) && S_ISREG( sb.st_mode ) ) { #ifdef SYS_DARWIN m[i] = sb.st_mtimespec.tv_sec; #else m[i] = sb.st_mtime; #endif } tr_free( fname ); } *setme_n = n; return m; }
int tr_blocklistSetContent( tr_session * session, const char * contentFilename ) { tr_list * l; tr_blocklist * b; const char * defaultName = "level1.bin"; assert( tr_isSession( session ) ); for( b = NULL, l = session->blocklists; !b && l; l = l->next ) if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ), defaultName ) ) b = l->data; if( !b ) { char * path = tr_buildPath( session->configDir, "blocklists", defaultName, NULL ); b = _tr_blocklistNew( path, session->isBlocklistEnabled ); tr_list_append( &session->blocklists, b ); tr_free( path ); } return _tr_blocklistSetContent( b, contentFilename ); }
void tr_sessionLoadSettings( tr_benc * d, const char * configDir, const char * appName ) { char * filename; tr_benc fileSettings; tr_benc sessionDefaults; tr_benc tmp; assert( tr_bencIsDict( d ) ); /* initializing the defaults: caller may have passed in some app-level defaults. * preserve those and use the session defaults to fill in any missing gaps. */ tr_bencInitDict( &sessionDefaults, 0 ); tr_sessionGetDefaultSettings( &sessionDefaults ); tr_bencMergeDicts( &sessionDefaults, d ); tmp = *d; *d = sessionDefaults; sessionDefaults = tmp; /* if caller didn't specify a config dir, use the default */ if( !configDir || !*configDir ) configDir = tr_getDefaultConfigDir( appName ); /* file settings override the defaults */ filename = tr_buildPath( configDir, "settings.json", NULL ); if( !tr_bencLoadJSONFile( filename, &fileSettings ) ) { tr_bencMergeDicts( d, &fileSettings ); tr_bencFree( &fileSettings ); } /* cleanup */ tr_bencFree( &sessionDefaults ); tr_free( filename ); }
static void rm_rf (const char * killme) { tr_sys_path_info info; if (tr_sys_path_get_info (killme, 0, &info, NULL)) { tr_sys_dir_t odir; if (info.type == TR_SYS_PATH_IS_DIRECTORY && (odir = tr_sys_dir_open (killme, NULL)) != TR_BAD_SYS_DIR) { const char * name; while ((name = tr_sys_dir_read_name (odir, NULL)) != NULL) { if (strcmp (name, ".") != 0 && strcmp (name, "..") != 0) { char * tmp = tr_buildPath (killme, name, NULL); rm_rf (tmp); tr_free (tmp); } } tr_sys_dir_close (odir, NULL); } if (verbose) fprintf (stderr, "cleanup: removing %s\n", killme); tr_sys_path_remove (killme, NULL); } }
static char * create_test_dir (const char * name) { char * const test_dir = tr_buildPath (tr_sessionGetConfigDir (session), name, NULL); tr_sys_dir_create (test_dir, 0, 0777, NULL); return test_dir; }
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 ); }
void tr_dhtUninit (tr_session *ss) { if (session != ss) return; tr_logAddNamedDbg ("DHT", "Uninitializing DHT"); if (dht_timer != NULL) { event_free (dht_timer); dht_timer = NULL; } /* Since we only save known good nodes, avoid erasing older data if we don't know enough nodes. */ if ((tr_dhtStatus (ss, AF_INET, NULL) < TR_DHT_FIREWALLED) && (tr_dhtStatus (ss, AF_INET6, NULL) < TR_DHT_FIREWALLED)) { tr_logAddNamedInfo ("DHT", "Not saving nodes, DHT not ready"); } else { tr_variant benc; struct sockaddr_in sins[300]; struct sockaddr_in6 sins6[300]; char compact[300 * 6], compact6[300 * 18]; char *dat_file; int i, j, num = 300, num6 = 300; int n = dht_get_nodes (sins, &num, sins6, &num6); tr_logAddNamedInfo ("DHT", "Saving %d (%d + %d) nodes", n, num, num6); j = 0; for (i=0; i<num; ++i) { memcpy (compact + j, &sins[i].sin_addr, 4); memcpy (compact + j + 4, &sins[i].sin_port, 2); j += 6; } j = 0; for (i=0; i<num6; ++i) { memcpy (compact6 + j, &sins6[i].sin6_addr, 16); memcpy (compact6 + j + 16, &sins6[i].sin6_port, 2); j += 18; } tr_variantInitDict (&benc, 3); tr_variantDictAddRaw (&benc, TR_KEY_id, myid, 20); if (num > 0) tr_variantDictAddRaw (&benc, TR_KEY_nodes, compact, num * 6); if (num6 > 0) tr_variantDictAddRaw (&benc, TR_KEY_nodes6, compact6, num6 * 18); dat_file = tr_buildPath (ss->configDir, "dht.dat", NULL); tr_variantToFile (&benc, TR_VARIANT_FMT_BENC, dat_file); tr_variantFree (&benc); tr_free (dat_file); } dht_uninit (); tr_logAddNamedDbg ("DHT", "Done uninitializing DHT"); session = NULL; }
static tr_watchdir_status onFileAdded(tr_watchdir_t dir, char const* name, void* context) { tr_session* session = context; if (!tr_str_has_suffix(name, ".torrent")) { return TR_WATCHDIR_IGNORE; } char* filename = tr_buildPath(tr_watchdir_get_path(dir), name, NULL); tr_ctor* ctor = tr_ctorNew(session); int err = tr_ctorSetMetainfoFromFile(ctor, filename); if (err == 0) { tr_torrentNew(ctor, &err, NULL); if (err == TR_PARSE_ERR) { tr_logAddError("Error parsing .torrent file \"%s\"", name); } else { bool trash = false; bool const test = tr_ctorGetDeleteSource(ctor, &trash); tr_logAddInfo("Parsing .torrent file successful \"%s\"", name); if (test && trash) { tr_error* error = NULL; tr_logAddInfo("Deleting input .torrent file \"%s\"", name); if (!tr_sys_path_remove(filename, &error)) { tr_logAddError("Error deleting .torrent file: %s", error->message); tr_error_free(error); } } else { char* new_filename = tr_strdup_printf("%s.added", filename); tr_sys_path_rename(filename, new_filename, NULL); tr_free(new_filename); } } } else { err = TR_PARSE_ERR; } tr_ctorFree(ctor); tr_free(filename); return err == TR_PARSE_ERR ? TR_WATCHDIR_RETRY : TR_WATCHDIR_ACCEPT; }
/** * 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 ); }
static const char * getOldCacheDir( void ) { static char * path = NULL; if( !path ) { #if defined( __BEOS__ ) || defined( WIN32 ) path = tr_buildPath( getOldConfigDir( ), "Cache", NULL ); #elif defined( SYS_DARWIN ) path = tr_buildPath( getHomeDir( ), "Library", "Caches", "Transmission", NULL ); #else path = tr_buildPath( getOldConfigDir( ), "cache", NULL ); #endif } return path; }
char * libtest_sandbox_create (void) { char * path = tr_getcwd (); char * sandbox = tr_buildPath (path, "sandbox-XXXXXX", NULL); tr_free (path); tr_mkdtemp (sandbox); return sandbox; }
static void metainfoLookupRescan( tr_session * session ) { int i; int n; struct stat sb; const char * dirname = tr_getTorrentDir( session ); DIR * odir = NULL; tr_ctor * ctor = NULL; tr_list * list = NULL; assert( tr_isSession( session ) ); /* walk through the directory and find the mappings */ ctor = tr_ctorNew( session ); tr_ctorSetSave( ctor, FALSE ); /* since we already have them */ if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && ( ( odir = opendir( dirname ) ) ) ) { struct dirent *d; for( d = readdir( odir ); d != NULL; d = readdir( odir ) ) { if( d->d_name && d->d_name[0] != '.' ) /* skip dotfiles, ., and .. */ { tr_info inf; char * path = tr_buildPath( dirname, d->d_name, NULL ); tr_ctorSetMetainfoFromFile( ctor, path ); if( !tr_torrentParse( session, ctor, &inf ) ) { tr_list_append( &list, tr_strdup( inf.hashString ) ); tr_list_append( &list, tr_strdup( path ) ); tr_metainfoFree( &inf ); } tr_free( path ); } } closedir( odir ); } tr_ctorFree( ctor ); n = tr_list_size( list ) / 2; session->metainfoLookup = tr_new0( struct tr_metainfo_lookup, n ); session->metainfoLookupCount = n; for( i = 0; i < n; ++i ) { char * hashString = tr_list_pop_front( &list ); char * filename = tr_list_pop_front( &list ); memcpy( session->metainfoLookup[i].hashString, hashString, 2 * SHA_DIGEST_LENGTH + 1 ); tr_free( hashString ); session->metainfoLookup[i].filename = filename; } metainfoLookupResort( session ); tr_dbg( "Found %d torrents in \"%s\"", n, dirname ); }
static int test_path_resolve (void) { char * const test_dir = create_test_dir (__FUNCTION__); tr_error * err = NULL; char * path1, * path2; path1 = tr_buildPath (test_dir, "a", NULL); path2 = tr_buildPath (test_dir, "b", NULL); libtest_create_file_with_string_contents (path1, "test"); if (create_symlink (path2, path1, false)) { char * tmp; tmp = tr_sys_path_resolve (path2, &err); check (tmp != NULL); check (err == NULL); check (path_contains_no_symlinks (tmp)); tr_free (tmp); tr_sys_path_remove (path1, NULL); tr_sys_dir_create (path1, 0, 0755, NULL); tmp = tr_sys_path_resolve (path2, &err); check (tmp != NULL); check (err == NULL); check (path_contains_no_symlinks (tmp)); tr_free (tmp); } else { fprintf (stderr, "WARNING: [%s] unable to run symlink tests\n", __FUNCTION__); } tr_sys_path_remove (path2, NULL); tr_sys_path_remove (path1, NULL); tr_free (path2); tr_free (path1); tr_free (test_dir); return 0; }
static int checkFile( tr_torrent * tor, tr_file_index_t fileIndex, int * abortFlag ) { tr_piece_index_t i; int changed = FALSE; int nofile; struct stat sb; char * path; const tr_file * file = &tor->info.files[fileIndex]; path = tr_buildPath( tor->downloadDir, file->name, NULL ); nofile = stat( path, &sb ) || !S_ISREG( sb.st_mode ); for( i = file->firstPiece; i <= file->lastPiece && i < tor->info.pieceCount && ( !*abortFlag ); ++i ) { if( nofile ) { tr_torrentSetHasPiece( tor, i, 0 ); } else if( !tr_torrentIsPieceChecked( tor, i ) ) { const int wasComplete = tr_cpPieceIsComplete( tor->completion, i ); if( tr_ioTestPiece( tor, i ) ) /* yay */ { tr_torrentSetHasPiece( tor, i, TRUE ); if( !wasComplete ) changed = TRUE; } else { /* if we were wrong about it being complete, * reset and start again. if we were right about * it being incomplete, do nothing -- we don't * want to lose blocks in those incomplete pieces */ if( wasComplete ) { tr_torrentSetHasPiece( tor, i, FALSE ); changed = TRUE; } } } tr_torrentSetPieceChecked( tor, i, TRUE ); } tr_free( path ); return changed; }
static const char * getOldTorrentsDir( void ) { static char * path = NULL; if( !path ) path = tr_buildPath( getOldConfigDir( ), TORRENT_SUBDIR, NULL ); return path; }
static int isClutchDir( const char * path ) { struct stat sb; char * tmp = tr_buildPath( path, "javascript", "transmission.js", NULL ); const int ret = !stat( tmp, &sb ); tr_inf( _( "Searching for web interface file \"%s\"" ), tmp ); tr_free( tmp ); return ret; }
static int isWebClientDir( const char * path ) { struct stat sb; char * tmp = tr_buildPath( path, "index.html", NULL ); const int ret = !stat( tmp, &sb ); tr_inf( _( "Searching for web interface file \"%s\"" ), tmp ); tr_free( tmp ); return ret; }
/* returns 0 on success, or an errno on failure */ static int readOrWriteBytes( const tr_torrent * tor, int ioMode, tr_file_index_t fileIndex, uint64_t fileOffset, void * buf, size_t buflen ) { const tr_info * info = &tor->info; const tr_file * file = &info->files[fileIndex]; typedef size_t ( *iofunc )( int, void *, size_t ); iofunc func = ioMode == TR_IO_READ ? (iofunc)read : (iofunc)write; char * path; struct stat sb; int fd = -1; int err; int fileExists; assert( tor->downloadDir && *tor->downloadDir ); assert( fileIndex < info->fileCount ); assert( !file->length || ( fileOffset < file->length ) ); assert( fileOffset + buflen <= file->length ); path = tr_buildPath( tor->downloadDir, file->name, NULL ); fileExists = !stat( path, &sb ); tr_free( path ); if( !file->length ) return 0; if( ( ioMode == TR_IO_READ ) && !fileExists ) /* does file exist? */ err = errno; else if( ( fd = tr_fdFileCheckout ( tor->downloadDir, file->name, ioMode == TR_IO_WRITE, !file->dnd, file->length ) ) < 0 ) err = errno; else if( tr_lseek( fd, (int64_t)fileOffset, SEEK_SET ) == -1 ) err = errno; else if( func( fd, buf, buflen ) != buflen ) err = errno; else err = 0; if( ( !err ) && ( !fileExists ) && ( ioMode == TR_IO_WRITE ) ) tr_statsFileCreated( tor->session ); if( fd >= 0 ) tr_fdFileReturn( fd ); return err; }
const char* tr_getDefaultConfigDir( const char * appname ) { static char * s = NULL; if( !appname || !*appname ) appname = "Transmission"; if( !s ) { if( ( s = getenv( "TRANSMISSION_HOME" ) ) ) { s = tr_strdup( s ); } else { #ifdef SYS_DARWIN s = tr_buildPath( getHomeDir( ), "Library", "Application Support", appname, NULL ); #elif defined( WIN32 ) char appdata[MAX_PATH]; /* SHGetFolderPath() requires MAX_PATH */ SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, appdata ); s = tr_buildPath( appdata, appname, NULL ); #elif defined( __HAIKU__ ) char buf[MAX_PATH_LENGTH]; find_directory( B_USER_SETTINGS_DIRECTORY, -1, true, buf, sizeof(buf) ); s = tr_buildPath( buf, appname, NULL ); #else if( ( s = getenv( "XDG_CONFIG_HOME" ) ) ) s = tr_buildPath( s, appname, NULL ); else s = tr_buildPath( getHomeDir( ), ".config", appname, NULL ); #endif } } return s; }
static CURL * createEasy( tr_session * s, struct tr_web_task * task ) { const tr_address * addr; tr_bool is_default_value; CURL * e = curl_easy_init( ); const long verbose = getenv( "TR_CURL_VERBOSE" ) != NULL; char * cookie_filename = tr_buildPath( s->configDir, "cookies.txt", NULL ); task->timeout_secs = getTimeoutFromURL( task ); curl_easy_setopt( e, CURLOPT_AUTOREFERER, 1L ); curl_easy_setopt( e, CURLOPT_COOKIEFILE, cookie_filename ); curl_easy_setopt( e, CURLOPT_ENCODING, "gzip;q=1.0, deflate, identity" ); curl_easy_setopt( e, CURLOPT_FOLLOWLOCATION, 1L ); curl_easy_setopt( e, CURLOPT_MAXREDIRS, -1L ); curl_easy_setopt( e, CURLOPT_NOSIGNAL, 1L ); curl_easy_setopt( e, CURLOPT_PRIVATE, task ); #ifdef USE_LIBCURL_SOCKOPT curl_easy_setopt( e, CURLOPT_SOCKOPTFUNCTION, sockoptfunction ); curl_easy_setopt( e, CURLOPT_SOCKOPTDATA, task ); #endif curl_easy_setopt( e, CURLOPT_SSL_VERIFYHOST, 0L ); curl_easy_setopt( e, CURLOPT_SSL_VERIFYPEER, 0L ); curl_easy_setopt( e, CURLOPT_TIMEOUT, task->timeout_secs ); curl_easy_setopt( e, CURLOPT_URL, task->url ); curl_easy_setopt( e, CURLOPT_USERAGENT, TR_NAME "/" SHORT_VERSION_STRING ); curl_easy_setopt( e, CURLOPT_VERBOSE, verbose ); curl_easy_setopt( e, CURLOPT_WRITEDATA, task ); curl_easy_setopt( e, CURLOPT_WRITEFUNCTION, writeFunc ); if((( addr = tr_sessionGetPublicAddress( s, TR_AF_INET, &is_default_value ))) && !is_default_value ) curl_easy_setopt( e, CURLOPT_INTERFACE, tr_ntop_non_ts( addr ) ); else if ((( addr = tr_sessionGetPublicAddress( s, TR_AF_INET6, &is_default_value ))) && !is_default_value ) curl_easy_setopt( e, CURLOPT_INTERFACE, tr_ntop_non_ts( addr ) ); if( task->range ) curl_easy_setopt( e, CURLOPT_RANGE, task->range ); if( s->curl_easy_config_func != NULL ) s->curl_easy_config_func( s, e, task->url ); tr_free( cookie_filename ); return e; }