Example #1
0
static void blocklistLoad(tr_blocklistFile* b)
{
    tr_sys_file_t fd;
    uint64_t byteCount;
    tr_sys_path_info info;
    char* base;
    tr_error* error = NULL;
    char const* err_fmt = _("Couldn't read \"%1$s\": %2$s");

    blocklistClose(b);

    if (!tr_sys_path_get_info(b->filename, 0, &info, NULL))
    {
        return;
    }

    byteCount = info.size;

    if (byteCount == 0)
    {
        return;
    }

    fd = tr_sys_file_open(b->filename, TR_SYS_FILE_READ, 0, &error);

    if (fd == TR_BAD_SYS_FILE)
    {
        tr_logAddError(err_fmt, b->filename, error->message);
        tr_error_free(error);
        return;
    }

    b->rules = tr_sys_file_map_for_reading(fd, 0, byteCount, &error);

    if (b->rules == NULL)
    {
        tr_logAddError(err_fmt, b->filename, error->message);
        tr_sys_file_close(fd, NULL);
        tr_error_free(error);
        return;
    }

    b->fd = fd;
    b->byteCount = byteCount;
    b->ruleCount = byteCount / sizeof(struct tr_ipv4_range);

    base = tr_sys_path_basename(b->filename, NULL);
    tr_logAddInfo(_("Blocklist \"%s\" contains %zu entries"), base, b->ruleCount);
    tr_free(base);
}
Example #2
0
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;
}
Example #3
0
static int
test_error_set (void)
{
  tr_error * err = NULL;

  tr_error_prefix (&err, "error: ");
  check (err == NULL);

  tr_error_set (&err, 1, "error: %s (%d)", "oops", 2);
  check (err != NULL);
  check_int_eq (1, err->code);
  check_streq ("error: oops (2)", err->message);
  tr_error_clear (&err);
  check (err == NULL);

  tr_error_set_literal (&err, 2, "oops");
  check (err != NULL);
  check_int_eq (2, err->code);
  check_streq ("oops", err->message);

  tr_error_prefix (&err, "error: ");
  check (err != NULL);
  check_int_eq (2, err->code);
  check_streq ("error: oops", err->message);

  tr_error_free (err);

  return 0;
}
Example #4
0
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;
}
static char*
tr_getcwd (void)
{
  char * result;
  tr_error * error = NULL;

  result = tr_sys_dir_get_current (&error);

  if (result == NULL)
    {
      fprintf (stderr, "getcwd error: \"%s\"", error->message);
      tr_error_free (error);
      result = tr_strdup ("");
    }

  return result;
}
Example #6
0
static bool
reopen_log_file (const char *filename)
{
    tr_error * error = NULL;
    const tr_sys_file_t old_log_file = logfile;
    const tr_sys_file_t new_log_file = tr_sys_file_open (filename,
                                                         TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_APPEND,
                                                         0666, &error);

    if (new_log_file == TR_BAD_SYS_FILE)
    {
        fprintf (stderr, "Couldn't (re)open log file \"%s\": %s\n", filename, error->message);
        tr_error_free (error);
        return false;
    }

    logfile = new_log_file;

    if (old_log_file != TR_BAD_SYS_FILE)
        tr_sys_file_close (old_log_file, NULL);

    return true;
}
Example #7
0
int
tr_blocklistFileSetContent (tr_blocklistFile * b, const char * filename)
{
  tr_sys_file_t in;
  tr_sys_file_t out;
  int inCount = 0;
  char line[2048];
  const char * err_fmt = _("Couldn't read \"%1$s\": %2$s");
  struct tr_ipv4_range * ranges = NULL;
  size_t ranges_alloc = 0;
  size_t ranges_count = 0;
  tr_error * error = NULL;

  if (!filename)
    {
      blocklistDelete (b);
      return 0;
    }

  in = tr_sys_file_open (filename, TR_SYS_FILE_READ, 0, &error);
  if (in == TR_BAD_SYS_FILE)
    {
      tr_logAddError (err_fmt, filename, error->message);
      tr_error_free (error);
      return 0;
    }

  blocklistClose (b);

  out = tr_sys_file_open (b->filename,
                          TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE,
                          0666, &error);
  if (out == TR_BAD_SYS_FILE)
    {
      tr_logAddError (err_fmt, b->filename, error->message);
      tr_error_free (error);
      tr_sys_file_close (in, NULL);
      return 0;
    }

  /* load the rules into memory */
  while (tr_sys_file_read_line (in, line, sizeof (line), NULL))
    {
      struct tr_ipv4_range range;

      ++inCount;

      if (!parseLine (line, &range))
        {
          /* don't try to display the actual lines - it causes issues */
          tr_logAddError (_("blocklist skipped invalid address at line %d"), inCount);
          continue;
        }

      if (ranges_alloc == ranges_count)
        {
          ranges_alloc += 4096; /* arbitrary */
          ranges = tr_renew (struct tr_ipv4_range, ranges, ranges_alloc);
        }

      ranges[ranges_count++] = range;
    }
Example #8
0
static uint64_t loadFromFile(tr_torrent* tor, uint64_t fieldsToLoad)
{
    TR_ASSERT(tr_isTorrent(tor));

    size_t len;
    int64_t i;
    char const* str;
    char* filename;
    tr_variant top;
    bool boolVal;
    uint64_t fieldsLoaded = 0;
    bool const wasDirty = tor->isDirty;
    tr_error* error = NULL;

    filename = getResumeFilename(tor);

    if (!tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, filename, &error))
    {
        tr_logAddTorDbg(tor, "Couldn't read \"%s\": %s", filename, error->message);
        tr_error_free(error);

        tr_free(filename);
        return fieldsLoaded;
    }

    tr_logAddTorDbg(tor, "Read resume file \"%s\"", filename);

    if ((fieldsToLoad & TR_FR_CORRUPT) != 0 && tr_variantDictFindInt(&top, TR_KEY_corrupt, &i))
    {
        tor->corruptPrev = i;
        fieldsLoaded |= TR_FR_CORRUPT;
    }

    if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR)) != 0 &&
        tr_variantDictFindStr(&top, TR_KEY_destination, &str, &len) && str != NULL && *str != '\0')
    {
        bool const is_current_dir = tor->currentDir == tor->downloadDir;
        tr_free(tor->downloadDir);
        tor->downloadDir = tr_strndup(str, len);

        if (is_current_dir)
        {
            tor->currentDir = tor->downloadDir;
        }

        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
    }

    if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR)) != 0 &&
        tr_variantDictFindStr(&top, TR_KEY_incomplete_dir, &str, &len) && str != NULL && *str != '\0')
    {
        bool const is_current_dir = tor->currentDir == tor->incompleteDir;
        tr_free(tor->incompleteDir);
        tor->incompleteDir = tr_strndup(str, len);

        if (is_current_dir)
        {
            tor->currentDir = tor->incompleteDir;
        }

        fieldsLoaded |= TR_FR_INCOMPLETE_DIR;
    }

    if ((fieldsToLoad & TR_FR_DOWNLOADED) != 0 && tr_variantDictFindInt(&top, TR_KEY_downloaded, &i))
    {
        tor->downloadedPrev = i;
        fieldsLoaded |= TR_FR_DOWNLOADED;
    }

    if ((fieldsToLoad & TR_FR_UPLOADED) != 0 && tr_variantDictFindInt(&top, TR_KEY_uploaded, &i))
    {
        tor->uploadedPrev = i;
        fieldsLoaded |= TR_FR_UPLOADED;
    }

    if ((fieldsToLoad & TR_FR_MAX_PEERS) != 0 && tr_variantDictFindInt(&top, TR_KEY_max_peers, &i))
    {
        tor->maxConnectedPeers = i;
        fieldsLoaded |= TR_FR_MAX_PEERS;
    }

    if ((fieldsToLoad & TR_FR_RUN) != 0 && tr_variantDictFindBool(&top, TR_KEY_paused, &boolVal))
    {
        tor->isRunning = !boolVal;
        fieldsLoaded |= TR_FR_RUN;
    }

    if ((fieldsToLoad & TR_FR_ADDED_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_added_date, &i))
    {
        tor->addedDate = i;
        fieldsLoaded |= TR_FR_ADDED_DATE;
    }

    if ((fieldsToLoad & TR_FR_DONE_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_done_date, &i))
    {
        tor->doneDate = i;
        fieldsLoaded |= TR_FR_DONE_DATE;
    }

    if ((fieldsToLoad & TR_FR_ACTIVITY_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_activity_date, &i))
    {
        tr_torrentSetActivityDate(tor, i);
        fieldsLoaded |= TR_FR_ACTIVITY_DATE;
    }

    if ((fieldsToLoad & TR_FR_TIME_SEEDING) != 0 && tr_variantDictFindInt(&top, TR_KEY_seeding_time_seconds, &i))
    {
        tor->secondsSeeding = i;
        fieldsLoaded |= TR_FR_TIME_SEEDING;
    }

    if ((fieldsToLoad & TR_FR_TIME_DOWNLOADING) != 0 && tr_variantDictFindInt(&top, TR_KEY_downloading_time_seconds, &i))
    {
        tor->secondsDownloading = i;
        fieldsLoaded |= TR_FR_TIME_DOWNLOADING;
    }

    if ((fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY) != 0 &&
        tr_variantDictFindInt(&top, TR_KEY_bandwidth_priority, &i) && tr_isPriority(i))
    {
        tr_torrentSetPriority(tor, i);
        fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY;
    }

    if ((fieldsToLoad & TR_FR_PEERS) != 0)
    {
        fieldsLoaded |= loadPeers(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_FILE_PRIORITIES) != 0)
    {
        fieldsLoaded |= loadFilePriorities(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_PROGRESS) != 0)
    {
        fieldsLoaded |= loadProgress(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_DND) != 0)
    {
        fieldsLoaded |= loadDND(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_SPEEDLIMIT) != 0)
    {
        fieldsLoaded |= loadSpeedLimits(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_RATIOLIMIT) != 0)
    {
        fieldsLoaded |= loadRatioLimits(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_IDLELIMIT) != 0)
    {
        fieldsLoaded |= loadIdleLimits(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_FILENAMES) != 0)
    {
        fieldsLoaded |= loadFilenames(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_NAME) != 0)
    {
        fieldsLoaded |= loadName(&top, tor);
    }

    /* loading the resume file triggers of a lot of changes,
     * but none of them needs to trigger a re-saving of the
     * same resume information... */
    tor->isDirty = wasDirty;

    tr_variantFree(&top);
    tr_free(filename);
    return fieldsLoaded;
}
Example #9
0
/**
 * 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_sys_dir_create () and tr_sys_file_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;
  tr_sys_path_info info;
  bool already_existed;
  bool resize_needed;
  tr_sys_file_t fd = TR_BAD_SYS_FILE;
  tr_error * error = NULL;

  /* create subfolders, if any */
  if (writable)
    {
      char * dir = tr_sys_path_dirname (filename, NULL);
      if (!tr_sys_dir_create (dir, TR_SYS_DIR_CREATE_PARENTS, 0777, &error))
        {
          tr_logAddError (_("Couldn't create \"%1$s\": %2$s"), dir, error->message);
          tr_free (dir);
          goto fail;
        }
      tr_free (dir);
    }

  already_existed = tr_sys_path_get_info (filename, 0, &info, NULL) && info.type == TR_SYS_PATH_IS_FILE;

  /* we can't resize the file w/o write permissions */
  resize_needed = already_existed && (file_size < info.size);
  writable |= resize_needed;

  /* open the file */
  flags = writable ? (TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE) : 0;
  flags |= TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL;
  fd = tr_sys_file_open (filename, flags, 0666, &error);

  if (fd == TR_BAD_SYS_FILE)
    {
      tr_logAddError (_("Couldn't open \"%1$s\": %2$s"), filename, error->message);
      goto fail;
    }

  if (writable && !already_existed && allocation != TR_PREALLOCATE_NONE)
    {
      bool success = false;
      const char * type = NULL;

      if (allocation == TR_PREALLOCATE_FULL)
        {
          success = preallocate_file_full (fd, file_size, &error);
          type = _("full");
        }
      else if (allocation == TR_PREALLOCATE_SPARSE)
        {
          success = preallocate_file_sparse (fd, file_size, &error);
          type = _("sparse");
        }

      assert (type != NULL);

      if (!success)
        {
          tr_logAddError (_("Couldn't preallocate file \"%1$s\" (%2$s, size: %3$"PRIu64"): %4$s"),
            filename, type, file_size, error->message);
          goto fail;
        }

      tr_logAddDebug (_("Preallocated file \"%1$s\" (%2$s, size: %3$"PRIu64")"), filename, type, file_size);
    }

  /* 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 (resize_needed && !tr_sys_file_truncate (fd, file_size, &error))
    {
      tr_logAddError (_("Couldn't truncate \"%1$s\": %2$s"), filename, error->message);
      goto fail;
    }

  o->fd = fd;
  return 0;

fail:
  {
    const int err = error->code;
    tr_error_free (error);

    if (fd != TR_BAD_SYS_FILE)
      tr_sys_file_close (fd, NULL);

    return err;
  }
}
Example #10
0
/* returns 0 on success, or an errno on failure */
static int
readOrWriteBytes (tr_session       * session,
                  tr_torrent       * tor,
                  int                ioMode,
                  tr_file_index_t    fileIndex,
                  uint64_t           fileOffset,
                  void             * buf,
                  size_t             buflen)
{
  tr_sys_file_t fd;
  int err = 0;
  const bool doWrite = ioMode >= TR_IO_WRITE;
  const tr_info * const info = &tor->info;
  const tr_file * const file = &info->files[fileIndex];

  assert (fileIndex < info->fileCount);
  assert (!file->length || (fileOffset < file->length));
  assert (fileOffset + buflen <= file->length);

  if (!file->length)
    return 0;

  /***
  ****  Find the fd
  ***/

  fd = tr_fdFileGetCached (session, tr_torrentId (tor), fileIndex, doWrite);
  if (fd == TR_BAD_SYS_FILE)
    {
      /* it's not cached, so open/create it now */
      char * subpath;
      const char * base;

      /* see if the file exists... */
      if (!tr_torrentFindFile2 (tor, fileIndex, &base, &subpath, NULL))
        {
          /* we can't read a file that doesn't exist... */
          if (!doWrite)
            err = ENOENT;

          /* figure out where the file should go, so we can create it */
          base = tr_torrentGetCurrentDir (tor);
          subpath = tr_sessionIsIncompleteFileNamingEnabled (tor->session)
                  ? tr_torrentBuildPartial (tor, fileIndex)
                  : tr_strdup (file->name);

        }

      if (!err)
        {
          /* open (and maybe create) the file */
          char * filename = tr_buildPath (base, subpath, NULL);
          const int prealloc = file->dnd || !doWrite
                             ? TR_PREALLOCATE_NONE
                             : tor->session->preallocationMode;
          if (((fd = tr_fdFileCheckout (session, tor->uniqueId, fileIndex,
                                        filename, doWrite,
                                        prealloc, file->length))) == TR_BAD_SYS_FILE)
            {
              err = errno;
              tr_logAddTorErr (tor, "tr_fdFileCheckout failed for \"%s\": %s",
                         filename, tr_strerror (err));
            }
          else if (doWrite)
            {
              /* make a note that we just created a file */
              tr_statsFileCreated (tor->session);
            }

          tr_free (filename);
        }

      tr_free (subpath);
    }

  /***
  ****  Use the fd
  ***/

  if (!err)
    {
      tr_error * error = NULL;

      if (ioMode == TR_IO_READ)
        {
          if (!tr_sys_file_read_at (fd, buf, buflen, fileOffset, NULL, &error))
            {
              err = error->code;
              tr_logAddTorErr (tor, "read failed for \"%s\": %s", file->name, error->message);
              tr_error_free (error);
            }
        }
      else if (ioMode == TR_IO_WRITE)
        {
          if (!tr_sys_file_write_at (fd, buf, buflen, fileOffset, NULL, &error))
            {
              err = error->code;
              tr_logAddTorErr (tor, "write failed for \"%s\": %s", file->name, error->message);
              tr_error_free (error);
            }
        }
      else if (ioMode == TR_IO_PREFETCH)
        {
          tr_sys_file_prefetch (fd, fileOffset, buflen, NULL);
        }
      else
        {
          abort ();
        }
    }

  return err;
}
Example #11
0
int
main (int argc, char * argv[])
{
  int i;
  int changedCount = 0;

#ifdef _WIN32
  tr_win32_make_args_utf8 (&argc, &argv);
#endif

  files = tr_new0 (const char*, argc);

  tr_logSetLevel (TR_LOG_ERROR);

  if (parseCommandLine (argc, (const char**)argv))
    return EXIT_FAILURE;

  if (showVersion)
    {
      fprintf (stderr, MY_NAME" "LONG_VERSION_STRING"\n");
      return EXIT_SUCCESS;
    }

  if (fileCount < 1)
    {
      fprintf (stderr, "ERROR: No torrent files specified.\n");
      tr_getopt_usage (MY_NAME, getUsage (), options);
      fprintf (stderr, "\n");
      return EXIT_FAILURE;
    }

  if (!add && !deleteme && !replace[0])
    {
      fprintf (stderr, "ERROR: Must specify -a, -d or -r\n");
      tr_getopt_usage (MY_NAME, getUsage (), options);
      fprintf (stderr, "\n");
      return EXIT_FAILURE;
    }

  for (i=0; i<fileCount; ++i)
    {
      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, &error))
        {
          printf ("\tError reading file: %s\n", error->message);
          tr_error_free (error);
          continue;
        }

      if (deleteme != NULL)
        changed |= removeURL (&top, deleteme);

      if (add != NULL)
        changed = addURL (&top, add);

      if (replace[0] && replace[1])
        changed |= replaceURL (&top, replace[0], replace[1]);

      if (changed)
        {
          ++changedCount;
          tr_variantToFile (&top, TR_VARIANT_FMT_BENC, filename);
        }

      tr_variantFree (&top);
    }

  printf ("Changed %d files\n", changedCount);

  tr_free (files);
  return EXIT_SUCCESS;
}