#5908: Check for tr_loadFile return value instead of errno in tr_variantFromFile

Seems like there could be a defect in uClibc making errno not
thread-local. Don't rely on errno value but check function return value
instead which is a better failure indicator.

Return errors from `tr_loadFile` and `tr_variantFromFile` via tr_error.
Fix `tr_sessionLoadSettings` to not fail on Windows if settings.json
does not exist.
This commit is contained in:
Mike Gelfand
2015-04-11 10:51:59 +00:00
parent 99e0f5bd63
commit 3b129a72d8
19 changed files with 91 additions and 81 deletions
+1 -1
View File
@@ -287,7 +287,7 @@ main (int argc, char ** argv)
ctor = tr_ctorNew (h);
fileContents = tr_loadFile (torrentPath, &fileLength);
fileContents = tr_loadFile (torrentPath, &fileLength, NULL);
tr_ctorSetPaused (ctor, TR_FORCE, false);
if (fileContents != NULL)
{
+1 -1
View File
@@ -532,7 +532,7 @@ getEncodedMetainfo (const char * filename)
{
size_t len = 0;
char * b64 = NULL;
uint8_t * buf = tr_loadFile (filename, &len);
uint8_t * buf = tr_loadFile (filename, &len, NULL);
if (buf)
{
+5
View File
@@ -14,17 +14,22 @@
#include <windows.h>
#define TR_ERROR_IS_ENOENT(code) ((code) == ERROR_FILE_NOT_FOUND || \
(code) == ERROR_PATH_NOT_FOUND)
#define TR_ERROR_IS_ENOSPC(code) ((code) == ERROR_DISK_FULL)
#define TR_ERROR_EINVAL ERROR_INVALID_PARAMETER
#define TR_ERROR_EISDIR ERROR_DIRECTORY_NOT_SUPPORTED
#else /* _WIN32 */
#include <errno.h>
#define TR_ERROR_IS_ENOENT(code) ((code) == ENOENT)
#define TR_ERROR_IS_ENOSPC(code) ((code) == ENOSPC)
#define TR_ERROR_EINVAL EINVAL
#define TR_ERROR_EISDIR EISDIR
#endif /* _WIN32 */
+1 -1
View File
@@ -375,7 +375,7 @@ tr_getDefaultDownloadDir (void)
tr_free (config_home);
/* read in user-dirs.dirs and look for the download dir entry */
content = (char *) tr_loadFile (config_file, &content_len);
content = (char *) tr_loadFile (config_file, &content_len, NULL);
if (content && content_len>0)
{
const char * key = "XDG_DOWNLOAD_DIR=\"";
+3 -2
View File
@@ -53,9 +53,10 @@ testFileExistsAndConsistsOfThisString (const tr_torrent * tor, tr_file_index_t f
assert (tr_sys_path_exists (path, NULL));
contents = tr_loadFile (path, &contents_len);
contents = tr_loadFile (path, &contents_len, NULL);
success = (str_len == contents_len)
success = contents != NULL
&& (str_len == contents_len)
&& (!memcmp (contents, str, contents_len));
tr_free (contents);
+5 -2
View File
@@ -11,6 +11,7 @@
#include "transmission.h"
#include "completion.h"
#include "error.h"
#include "file.h"
#include "log.h"
#include "metainfo.h" /* tr_metainfoGetBasename () */
@@ -706,14 +707,16 @@ loadFromFile (tr_torrent * tor, uint64_t fieldsToLoad)
bool boolVal;
uint64_t fieldsLoaded = 0;
const bool wasDirty = tor->isDirty;
tr_error * error = NULL;
assert (tr_isTorrent (tor));
filename = getResumeFilename (tor);
if (tr_variantFromFile (&top, TR_VARIANT_FMT_BENC, filename))
if (!tr_variantFromFile (&top, TR_VARIANT_FMT_BENC, filename, &error))
{
tr_logAddTorDbg (tor, "Couldn't read \"%s\"", filename);
tr_logAddTorDbg (tor, "Couldn't read \"%s\": %s", filename, error->message);
tr_error_free (error);
tr_free (filename);
return fieldsLoaded;
+10 -11
View File
@@ -429,27 +429,27 @@ serve_file (struct evhttp_request * req,
{
void * file;
size_t file_len;
struct evbuffer * content;
const int error = errno;
tr_error * error = NULL;
errno = 0;
file_len = 0;
file = tr_loadFile (filename, &file_len);
content = evbuffer_new ();
evbuffer_add_reference (content, file, file_len, evbuffer_ref_cleanup_tr_free, file);
file = tr_loadFile (filename, &file_len, &error);
if (errno)
if (file == NULL)
{
char * tmp = tr_strdup_printf ("%s (%s)", filename, tr_strerror (errno));
char * tmp = tr_strdup_printf ("%s (%s)", filename, error->message);
send_simple_response (req, HTTP_NOTFOUND, tmp);
tr_free (tmp);
tr_error_free (error);
}
else
{
struct evbuffer * content;
struct evbuffer * out;
const time_t now = tr_time ();
errno = error;
content = evbuffer_new ();
evbuffer_add_reference (content, file, file_len, evbuffer_ref_cleanup_tr_free, file);
out = evbuffer_new ();
evhttp_add_header (req->output_headers, "Content-Type", mimetype_guess (filename));
add_time_header (req->output_headers, "Date", now);
@@ -458,9 +458,8 @@ serve_file (struct evhttp_request * req,
evhttp_send_reply (req, HTTP_OK, "OK", out);
evbuffer_free (out);
evbuffer_free (content);
}
evbuffer_free (content);
}
}
+12 -7
View File
@@ -32,6 +32,8 @@
#include "blocklist.h"
#include "cache.h"
#include "crypto-utils.h"
#include "error.h"
#include "error-types.h"
#include "fdlimit.h"
#include "file.h"
#include "list.h"
@@ -456,12 +458,12 @@ tr_sessionGetSettings (tr_session * s, tr_variant * d)
bool
tr_sessionLoadSettings (tr_variant * dict, const char * configDir, const char * appName)
{
int err = 0;
char * filename;
tr_variant fileSettings;
tr_variant sessionDefaults;
tr_variant tmp;
bool success = false;
bool success;
tr_error * error = NULL;
assert (tr_variantIsDict (dict));
@@ -480,17 +482,21 @@ tr_sessionLoadSettings (tr_variant * dict, const char * configDir, const char *
/* file settings override the defaults */
filename = tr_buildPath (configDir, "settings.json", NULL);
err = tr_variantFromFile (&fileSettings, TR_VARIANT_FMT_JSON, filename);
if (!err)
if (tr_variantFromFile (&fileSettings, TR_VARIANT_FMT_JSON, filename, &error))
{
tr_variantMergeDicts (dict, &fileSettings);
tr_variantFree (&fileSettings);
success = true;
}
else
{
success = TR_ERROR_IS_ENOENT (error->code);
tr_error_free (error);
}
/* cleanup */
tr_variantFree (&sessionDefaults);
tr_free (filename);
success = (err==0) || (err==ENOENT);
return success;
}
@@ -509,8 +515,7 @@ tr_sessionSaveSettings (tr_session * session,
/* the existing file settings are the fallback values */
{
tr_variant fileSettings;
const int err = tr_variantFromFile (&fileSettings, TR_VARIANT_FMT_JSON, filename);
if (!err)
if (tr_variantFromFile (&fileSettings, TR_VARIANT_FMT_JSON, filename, NULL))
{
tr_variantMergeDicts (&settings, &fileSettings);
tr_variantFree (&fileSettings);
+2 -2
View File
@@ -50,13 +50,13 @@ loadCumulativeStats (const tr_session * session, tr_session_stats * setme)
bool loaded = false;
filename = getFilename (session);
loaded = !tr_variantFromFile (&top, TR_VARIANT_FMT_JSON, filename);
loaded = tr_variantFromFile (&top, TR_VARIANT_FMT_JSON, filename, NULL);
tr_free (filename);
if (!loaded)
{
filename = getOldFilename (session);
loaded = !tr_variantFromFile (&top, TR_VARIANT_FMT_BENC, filename);
loaded = tr_variantFromFile (&top, TR_VARIANT_FMT_BENC, filename, NULL);
tr_free (filename);
}
+1 -1
View File
@@ -135,7 +135,7 @@ tr_ctorSetMetainfoFromFile (tr_ctor * ctor,
size_t len;
int err;
metainfo = tr_loadFile (filename, &len);
metainfo = tr_loadFile (filename, &len, NULL);
if (metainfo && len)
err = tr_ctorSetMetainfo (ctor, metainfo, len);
else
+2 -2
View File
@@ -106,7 +106,7 @@ findInfoDictOffset (const tr_torrent * tor)
int offset = 0;
/* load the file, and find the info dict's offset inside the file */
if ((fileContents = tr_loadFile (tor->info.torrent, &fileLen)))
if ((fileContents = tr_loadFile (tor->info.torrent, &fileLen, NULL)))
{
tr_variant top;
@@ -253,7 +253,7 @@ tr_torrentSetMetadataPiece (tr_torrent * tor, int piece, const void * data, in
tr_variant newMetainfo;
char * path = tr_strdup (tor->info.torrent);
if (!tr_variantFromFile (&newMetainfo, TR_VARIANT_FMT_BENC, path))
if (tr_variantFromFile (&newMetainfo, TR_VARIANT_FMT_BENC, path, NULL))
{
bool hasInfo;
tr_info info;
+1 -1
View File
@@ -2660,7 +2660,7 @@ tr_torrentSetAnnounceList (tr_torrent * tor,
ok = false;
/* save to the .torrent file */
if (ok && !tr_variantFromFile (&metainfo, TR_VARIANT_FMT_BENC, tor->info.torrent))
if (ok && tr_variantFromFile (&metainfo, TR_VARIANT_FMT_BENC, tor->info.torrent, NULL))
{
bool hasInfo;
tr_info tmpInfo;
+1 -1
View File
@@ -281,7 +281,7 @@ tr_dhtInit (tr_session *ss)
dht_debug = stderr;
dat_file = tr_buildPath (ss->configDir, "dht.dat", NULL);
rc = tr_variantFromFile (&benc, TR_VARIANT_FMT_BENC, dat_file);
rc = tr_variantFromFile (&benc, TR_VARIANT_FMT_BENC, dat_file, NULL) ? 0 : -1;
tr_free (dat_file);
if (rc == 0) {
have_id = tr_variantDictFindRaw (&benc, TR_KEY_id, &raw, &len);
+16 -27
View File
@@ -213,29 +213,28 @@ tr_timerAddMsec (struct event * timer, int msec)
**/
uint8_t *
tr_loadFile (const char * path,
size_t * size)
tr_loadFile (const char * path,
size_t * size,
tr_error ** error)
{
uint8_t * buf;
tr_sys_path_info info;
tr_sys_file_t fd;
tr_error * error = NULL;
tr_error * my_error = NULL;
const char * const err_fmt = _("Couldn't read \"%1$s\": %2$s");
/* try to stat the file */
if (!tr_sys_path_get_info (path, 0, &info, &error))
if (!tr_sys_path_get_info (path, 0, &info, &my_error))
{
const int err = error->code;
tr_logAddDebug (err_fmt, path, error->message);
tr_error_free (error);
errno = err;
tr_logAddDebug (err_fmt, path, my_error->message);
tr_error_propagate (error, &my_error);
return NULL;
}
if (info.type != TR_SYS_PATH_IS_FILE)
{
tr_logAddError (err_fmt, path, _("Not a regular file"));
errno = EISDIR;
tr_error_set_literal (error, TR_ERROR_EISDIR, _("Not a regular file"));
return NULL;
}
@@ -244,32 +243,22 @@ tr_loadFile (const char * path,
assert (info.size <= SIZE_MAX);
/* Load the torrent file into our buffer */
fd = tr_sys_file_open (path, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &error);
fd = tr_sys_file_open (path, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &my_error);
if (fd == TR_BAD_SYS_FILE)
{
const int err = error->code;
tr_logAddError (err_fmt, path, error->message);
tr_error_free (error);
errno = err;
tr_logAddError (err_fmt, path, my_error->message);
tr_error_propagate (error, &my_error);
return NULL;
}
buf = tr_malloc (info.size + 1);
if (!buf)
if (!tr_sys_file_read (fd, buf, info.size, NULL, &my_error))
{
const int err = errno;
tr_logAddError (err_fmt, path, _("Memory allocation failed"));
tr_sys_file_close (fd, NULL);
errno = err;
return NULL;
}
if (!tr_sys_file_read (fd, buf, info.size, NULL, &error))
{
const int err = error->code;
tr_logAddError (err_fmt, path, error->message);
tr_logAddError (err_fmt, path, my_error->message);
tr_sys_file_close (fd, NULL);
free (buf);
tr_error_free (error);
errno = err;
tr_error_propagate (error, &my_error);
return NULL;
}
+3 -2
View File
@@ -132,8 +132,9 @@ bool tr_wildmat (const char * text, const char * pattern) TR_GNUC_NONNULL (1,2);
* @brief Loads a file and returns its contents.
* On failure, NULL is returned and errno is set.
*/
uint8_t* tr_loadFile (const char * filename, size_t * size) TR_GNUC_MALLOC
TR_GNUC_NONNULL (1);
uint8_t * tr_loadFile (const char * filename,
size_t * size,
tr_error ** error) TR_GNUC_MALLOC TR_GNUC_NONNULL (1);
/** @brief build a filename from a series of elements using the
+15 -14
View File
@@ -1218,27 +1218,28 @@ tr_variantToFile (const tr_variant * v,
****
***/
int
bool
tr_variantFromFile (tr_variant * setme,
tr_variant_fmt fmt,
const char * filename)
const char * filename,
tr_error ** error)
{
int err;
size_t buflen;
bool ret = false;
uint8_t * buf;
const int old_errno = errno;
size_t buflen;
errno = 0;
buf = tr_loadFile (filename, &buflen);
buf = tr_loadFile (filename, &buflen, error);
if (buf != NULL)
{
if (tr_variantFromBuf (setme, fmt, buf, buflen, filename, NULL) == 0)
ret = true;
else
tr_error_set_literal (error, 0, _("Unable to parse file content"));
if (errno)
err = errno;
else
err = tr_variantFromBuf (setme, fmt, buf, buflen, filename, NULL);
tr_free (buf);
}
tr_free (buf);
errno = old_errno;
return err;
return ret;
}
int
+6 -3
View File
@@ -19,6 +19,8 @@ extern "C" {
struct evbuffer;
struct tr_error;
/**
* @addtogroup tr_variant Variant
*
@@ -120,9 +122,10 @@ struct evbuffer * tr_variantToBuf (const tr_variant * variant,
tr_variant_fmt fmt);
/* TR_VARIANT_FMT_JSON_LEAN and TR_VARIANT_FMT_JSON are equivalent here. */
int tr_variantFromFile (tr_variant * setme,
tr_variant_fmt fmt,
const char * filename);
bool tr_variantFromFile (tr_variant * setme,
tr_variant_fmt fmt,
const char * filename,
struct tr_error ** error);
/* TR_VARIANT_FMT_JSON_LEAN and TR_VARIANT_FMT_JSON are equivalent here. */
int tr_variantFromBuf (tr_variant * setme,
+1 -1
View File
@@ -258,7 +258,7 @@ Prefs::~Prefs ()
// update settings.json with our settings
tr_variant file_settings;
const QFile file (QDir(myConfigDir).absoluteFilePath(QLatin1String ("settings.json")));
if (tr_variantFromFile (&file_settings, TR_VARIANT_FMT_JSON, file.fileName().toUtf8().constData()))
if (!tr_variantFromFile (&file_settings, TR_VARIANT_FMT_JSON, file.fileName().toUtf8().constData(), NULL))
tr_variantInitDict (&file_settings, PREFS_COUNT);
tr_variantMergeDicts (&file_settings, &current_settings);
tr_variantToFile (&file_settings, TR_VARIANT_FMT_JSON, file.fileName().toUtf8().constData());
+5 -2
View File
@@ -14,6 +14,7 @@
#include <event2/buffer.h>
#include <libtransmission/transmission.h>
#include <libtransmission/error.h>
#include <libtransmission/tr-getopt.h>
#include <libtransmission/utils.h>
#include <libtransmission/variant.h>
@@ -328,12 +329,14 @@ main (int argc, char * argv[])
tr_variant top;
bool changed = false;
const char * filename = files[i];
tr_error * error = NULL;
printf ("%s\n", filename);
if (tr_variantFromFile (&top, TR_VARIANT_FMT_BENC, filename))
if (!tr_variantFromFile (&top, TR_VARIANT_FMT_BENC, filename, &error))
{
printf ("\tError reading file\n");
printf ("\tError reading file: %s\n", error->message);
tr_error_free (error);
continue;
}