static int test_error_propagate (void) { tr_error * err = NULL; tr_error * err2 = NULL; tr_error_set_literal (&err, 1, "oops"); check (err != NULL); check_int_eq (1, err->code); check_streq ("oops", err->message); tr_error_propagate (&err2, &err); check (err2 != NULL); check_int_eq (1, err2->code); check_streq ("oops", err2->message); check (err == NULL); tr_error_propagate_prefixed (&err, &err2, "error: "); check (err != NULL); check_int_eq (1, err->code); check_streq ("error: oops", err->message); check (err2 == NULL); tr_error_propagate (NULL, &err); check (err == NULL); tr_error_free (err2); return 0; }
static bool preallocate_file_sparse (tr_sys_file_t fd, uint64_t length, tr_error ** error) { tr_error * my_error = NULL; if (length == 0) return true; if (tr_sys_file_preallocate (fd, length, TR_SYS_FILE_PREALLOC_SPARSE, &my_error)) return true; dbgmsg ("Preallocating (sparse, normal) failed (%d): %s", my_error->code, my_error->message); if (!TR_ERROR_IS_ENOSPC (my_error->code)) { const char zero = '\0'; tr_error_clear (&my_error); /* fallback: the old-style seek-and-write */ if (tr_sys_file_write_at (fd, &zero, 1, length - 1, NULL, &my_error) && tr_sys_file_truncate (fd, length, &my_error)) return true; dbgmsg ("Preallocating (sparse, fallback) failed (%d): %s", my_error->code, my_error->message); } tr_error_propagate (error, &my_error); return false; }
bool tr_sys_path_get_info(char const* path, int flags, tr_sys_path_info* info, tr_error** error) { TR_ASSERT(path != NULL); TR_ASSERT(info != NULL); bool ret = false; wchar_t* wide_path = path_to_native_path(path); if ((flags & TR_SYS_PATH_NO_FOLLOW) == 0) { HANDLE handle = INVALID_HANDLE_VALUE; if (wide_path != NULL) { handle = CreateFileW(wide_path, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); } if (handle != INVALID_HANDLE_VALUE) { tr_error* my_error = NULL; ret = tr_sys_file_get_info(handle, info, &my_error); if (!ret) { tr_error_propagate(error, &my_error); } CloseHandle(handle); } else { set_system_error(error, GetLastError()); } } else { WIN32_FILE_ATTRIBUTE_DATA attributes; if (wide_path != NULL) { ret = GetFileAttributesExW(wide_path, GetFileExInfoStandard, &attributes); } if (ret) { stat_to_sys_path_info(attributes.dwFileAttributes, attributes.nFileSizeLow, attributes.nFileSizeHigh, &attributes.ftLastWriteTime, info); } else { set_system_error(error, GetLastError()); } } tr_free(wide_path); return ret; }
static void create_temp_path (char * path_template, void (* callback) (const char * path, void * param, tr_error ** error), void * callback_param, tr_error ** error) { char * path; size_t path_size; int attempt; tr_error * my_error = NULL; assert (path_template != NULL); assert (callback != NULL); path = tr_strdup (path_template); path_size = strlen (path); assert (path_size > 0); for (attempt = 0; attempt < 100; ++attempt) { size_t i = path_size; while (i > 0 && path_template[i - 1] == 'X') { const int c = tr_rand_int (26 + 26 + 10); path[i - 1] = c < 26 ? c + 'A' : (c < 26 + 26 ? (c - 26) + 'a' : (c - 26 - 26) + '0'); --i; } assert (path_size >= i + 6); tr_error_clear (&my_error); (*callback) (path, callback_param, &my_error); if (my_error == NULL) break; } if (my_error != NULL) tr_error_propagate(error, &my_error); else memcpy (path_template, path, path_size); tr_free (path); }
static bool preallocate_file_full (tr_sys_file_t fd, uint64_t length, tr_error ** error) { tr_error * my_error = NULL; if (length == 0) return true; if (tr_sys_file_preallocate (fd, length, 0, &my_error)) return true; dbgmsg ("Preallocating (full, normal) failed (%d): %s", my_error->code, my_error->message); if (!TR_ERROR_IS_ENOSPC (my_error->code)) { uint8_t buf[4096]; bool success = true; memset (buf, 0, sizeof (buf)); tr_error_clear (&my_error); /* fallback: the old-fashioned way */ while (success && length > 0) { const uint64_t thisPass = MIN (length, sizeof (buf)); uint64_t bytes_written; success = tr_sys_file_write (fd, buf, thisPass, &bytes_written, &my_error); length -= bytes_written; } if (success) return true; dbgmsg ("Preallocating (full, fallback) failed (%d): %s", my_error->code, my_error->message); } tr_error_propagate (error, &my_error); return false; }
static bool create_path (const char * path_in, int permissions, tr_error ** error) { char * p; char * pp; bool done; int tmperr; int rv; struct stat sb; char * path; /* make a temporary copy of path */ path = tr_strdup (path_in); /* walk past the root */ p = path; while (*p == TR_PATH_DELIMITER) ++p; pp = p; done = false; while ((p = strchr (pp, TR_PATH_DELIMITER)) || (p = strchr (pp, '\0'))) { if (!*p) done = true; else *p = '\0'; tmperr = errno; rv = stat (path, &sb); errno = tmperr; if (rv) { tr_error * my_error = NULL; /* Folder doesn't exist yet */ if (!tr_sys_dir_create (path, 0, permissions, &my_error)) { tr_logAddError (_ ("Couldn't create \"%1$s\": %2$s"), path, my_error->message); tr_free (path); tr_error_propagate (error, &my_error); return false; } } else if ((sb.st_mode & S_IFMT) != S_IFDIR) { /* Node exists but isn't a folder */ char * const buf = tr_strdup_printf (_ ("File \"%s\" is in the way"), path); tr_logAddError (_ ("Couldn't create \"%1$s\": %2$s"), path_in, buf); tr_free (buf); tr_free (path); set_system_error (error, ENOTDIR); return false; } if (done) break; *p = TR_PATH_DELIMITER; p++; pp = p; } tr_free (path); return true; }