示例#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);
}
示例#2
0
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;
      tr_sys_file_t fd;
      char * path;
      char * dirname;
      const tr_file * file = &tor->info.files[i];

      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_sys_path_dirname (path, NULL);
      tr_sys_dir_create (dirname, TR_SYS_DIR_CREATE_PARENTS, 0700, NULL);
      fd = tr_sys_file_open (path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0600, NULL);
      for (j=0; j<file->length; ++j)
        tr_sys_file_write (fd, ((!complete) && (i==0) && (j<tor->info.pieceSize)) ? "\1" : "\0", 1, NULL, NULL);
      tr_sys_file_close (fd, NULL);

      tr_free (dirname);
      tr_free (path);

      path = tr_torrentFindFile (tor, i);
      assert (path != NULL);
      err = errno;
      assert (tr_sys_path_exists (path, NULL));
      errno = err;
      tr_free (path);
    }

  libttest_sync ();
  libttest_blockingTorrentVerify (tor);

  if (complete)
    assert (tr_torrentStat(tor)->leftUntilDone == 0);
  else
    assert (tr_torrentStat(tor)->leftUntilDone == tor->info.pieceSize);
}
示例#3
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;
}
示例#4
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;
    }
示例#5
0
static bool verifyTorrent(tr_torrent* tor, bool* stopFlag)
{
    time_t end;
    tr_sha1_ctx_t sha;
    tr_sys_file_t fd = TR_BAD_SYS_FILE;
    uint64_t filePos = 0;
    bool changed = false;
    bool hadPiece = false;
    time_t lastSleptAt = 0;
    uint32_t piecePos = 0;
    tr_file_index_t fileIndex = 0;
    tr_file_index_t prevFileIndex = !fileIndex;
    tr_piece_index_t pieceIndex = 0;
    time_t const begin = tr_time();
    size_t const buflen = 1024 * 128; /* 128 KiB buffer */
    uint8_t* buffer = tr_valloc(buflen);

    sha = tr_sha1_init();

    tr_logAddTorDbg(tor, "%s", "verifying torrent...");
    tr_torrentSetChecked(tor, 0);

    while (!*stopFlag && pieceIndex < tor->info.pieceCount)
    {
        uint64_t leftInPiece;
        uint64_t bytesThisPass;
        uint64_t leftInFile;
        tr_file const* file = &tor->info.files[fileIndex];

        /* if we're starting a new piece... */
        if (piecePos == 0)
        {
            hadPiece = tr_torrentPieceIsComplete(tor, pieceIndex);
        }

        /* if we're starting a new file... */
        if (filePos == 0 && fd == TR_BAD_SYS_FILE && fileIndex != prevFileIndex)
        {
            char* filename = tr_torrentFindFile(tor, fileIndex);
            fd = filename == NULL ? TR_BAD_SYS_FILE : tr_sys_file_open(filename, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0,
                NULL);
            tr_free(filename);
            prevFileIndex = fileIndex;
        }

        /* figure out how much we can read this pass */
        leftInPiece = tr_torPieceCountBytes(tor, pieceIndex) - piecePos;
        leftInFile = file->length - filePos;
        bytesThisPass = MIN(leftInFile, leftInPiece);
        bytesThisPass = MIN(bytesThisPass, buflen);

        /* read a bit */
        if (fd != TR_BAD_SYS_FILE)
        {
            uint64_t numRead;

            if (tr_sys_file_read_at(fd, buffer, bytesThisPass, filePos, &numRead, NULL) && numRead > 0)
            {
                bytesThisPass = numRead;
                tr_sha1_update(sha, buffer, bytesThisPass);
#if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED
                (void)posix_fadvise(fd, filePos, bytesThisPass, POSIX_FADV_DONTNEED);
#endif
            }
        }

        /* move our offsets */
        leftInPiece -= bytesThisPass;
        leftInFile -= bytesThisPass;
        piecePos += bytesThisPass;
        filePos += bytesThisPass;

        /* if we're finishing a piece... */
        if (leftInPiece == 0)
        {
            time_t now;
            bool hasPiece;
            uint8_t hash[SHA_DIGEST_LENGTH];

            tr_sha1_final(sha, hash);
            hasPiece = memcmp(hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH) == 0;

            if (hasPiece || hadPiece)
            {
                tr_torrentSetHasPiece(tor, pieceIndex, hasPiece);
                changed |= hasPiece != hadPiece;
            }

            tr_torrentSetPieceChecked(tor, pieceIndex);
            now = tr_time();
            tor->anyDate = now;

            /* sleeping even just a few msec per second goes a long
             * way towards reducing IO load... */
            if (lastSleptAt != now)
            {
                lastSleptAt = now;
                tr_wait_msec(MSEC_TO_SLEEP_PER_SECOND_DURING_VERIFY);
            }

            sha = tr_sha1_init();
            pieceIndex++;
            piecePos = 0;
        }

        /* if we're finishing a file... */
        if (leftInFile == 0)
        {
            if (fd != TR_BAD_SYS_FILE)
            {
                tr_sys_file_close(fd, NULL);
                fd = TR_BAD_SYS_FILE;
            }

            fileIndex++;
            filePos = 0;
        }
    }

    /* cleanup */
    if (fd != TR_BAD_SYS_FILE)
    {
        tr_sys_file_close(fd, NULL);
    }

    tr_sha1_final(sha, NULL);
    free(buffer);

    /* stopwatch */
    end = tr_time();
    tr_logAddTorDbg(tor, "Verification is done. It took %d seconds to verify %" PRIu64 " bytes (%" PRIu64 " bytes per second)",
        (int)(end - begin), tor->info.totalSize, (uint64_t)(tor->info.totalSize / (1 + (end - begin))));

    return changed;
}
示例#6
0
static void
dht_bootstrap (void *closure)
{
    struct bootstrap_closure *cl = closure;
    int i;
    int num = cl->len / 6, num6 = cl->len6 / 18;

    if (session != cl->session)
        return;

    if (cl->len > 0)
        tr_logAddNamedInfo ("DHT", "Bootstrapping from %d IPv4 nodes", num);

    if (cl->len6 > 0)
        tr_logAddNamedInfo ("DHT", "Bootstrapping from %d IPv6 nodes", num6);


    for (i = 0; i < MAX (num, num6); i++) {
        if (i < num && !bootstrap_done (cl->session, AF_INET)) {
            tr_port port;
            struct tr_address addr;

            memset (&addr, 0, sizeof (addr));
            addr.type = TR_AF_INET;
            memcpy (&addr.addr.addr4, &cl->nodes[i * 6], 4);
            memcpy (&port, &cl->nodes[i * 6 + 4], 2);
            port = ntohs (port);
            tr_dhtAddNode (cl->session, &addr, port, 1);
        }
        if (i < num6 && !bootstrap_done (cl->session, AF_INET6)) {
            tr_port port;
            struct tr_address addr;

            memset (&addr, 0, sizeof (addr));
            addr.type = TR_AF_INET6;
            memcpy (&addr.addr.addr6, &cl->nodes6[i * 18], 16);
            memcpy (&port, &cl->nodes6[i * 18 + 16], 2);
            port = ntohs (port);
            tr_dhtAddNode (cl->session, &addr, port, 1);
        }

        /* Our DHT code is able to take up to 9 nodes in a row without
           dropping any. After that, it takes some time to split buckets.
           So ping the first 8 nodes quickly, then slow down. */
        if (i < 8)
            nap (2);
        else
            nap (15);

        if (bootstrap_done (session, 0))
            break;
    }

    if (!bootstrap_done (cl->session, 0)) {
        char *bootstrap_file;
        tr_sys_file_t f = TR_BAD_SYS_FILE;

        bootstrap_file =
            tr_buildPath (cl->session->configDir, "dht.bootstrap", NULL);

        if (bootstrap_file)
            f = tr_sys_file_open (bootstrap_file, TR_SYS_FILE_READ, 0, NULL);
        if (f != TR_BAD_SYS_FILE) {
            tr_logAddNamedInfo ("DHT", "Attempting manual bootstrap");
            for (;;) {
                char buf[201];
                char *p;
                int port = 0;

                if (!tr_sys_file_read_line (f, buf, 200, NULL))
                    break;

                p = memchr (buf, ' ', strlen (buf));
                if (p != NULL)
                    port = atoi (p + 1);
                if (p == NULL || port <= 0 || port >= 0x10000) {
                    tr_logAddNamedError ("DHT", "Couldn't parse %s", buf);
                    continue;
                }

                *p = '\0';

                bootstrap_from_name (buf, port, bootstrap_af (session));

                if (bootstrap_done (cl->session, 0))
                    break;
            }
            tr_sys_file_close (f, NULL);
        }

        tr_free (bootstrap_file);
    }

    if (!bootstrap_done (cl->session, 0)) {
        for (i = 0; i < 6; i++) {
            /* We don't want to abuse our bootstrap nodes, so be very
               slow.  The initial wait is to give other nodes a chance
               to contact us before we attempt to contact a bootstrap
               node, for example because we've just been restarted. */
            nap (40);
            if (bootstrap_done (cl->session, 0))
                break;
            if (i == 0)
                tr_logAddNamedInfo ("DHT",
                        "Attempting bootstrap from dht.transmissionbt.com");
            bootstrap_from_name ("dht.transmissionbt.com", 6881,
                                 bootstrap_af (session));
        }
    }

    if (cl->nodes)
        tr_free (cl->nodes);
    if (cl->nodes6)
        tr_free (cl->nodes6);
    tr_free (closure);
    tr_logAddNamedDbg ("DHT", "Finished bootstrapping");
}
示例#7
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;
  }
}
示例#8
0
static int
test_get_info (void)
{
  char * const test_dir = create_test_dir (__FUNCTION__);
  tr_sys_path_info info;
  tr_sys_file_t fd;
  tr_error * err = NULL;
  char * path1, * path2;
  time_t t;

  path1 = tr_buildPath (test_dir, "a", NULL);
  path2 = tr_buildPath (test_dir, "b", NULL);

  /* Can't get info of non-existent file/directory */
  check (!tr_sys_path_get_info (path1, 0, &info, &err));
  check (err != NULL);
  tr_error_clear (&err);

  t = time (NULL);
  libtest_create_file_with_string_contents (path1, "test");

  /* Good file info */
  clear_path_info (&info);
  check (tr_sys_path_get_info (path1, 0, &info, &err));
  check (err == NULL);
  check_int_eq (TR_SYS_PATH_IS_FILE, info.type);
  check_int_eq (4, info.size);
  check (info.last_modified_at >= t && info.last_modified_at <= time (NULL));

  /* Good file info (by handle) */
  fd = tr_sys_file_open (path1, TR_SYS_FILE_READ, 0, NULL);
  clear_path_info (&info);
  check (tr_sys_file_get_info (fd, &info, &err));
  check (err == NULL);
  check_int_eq (TR_SYS_PATH_IS_FILE, info.type);
  check_int_eq (4, info.size);
  check (info.last_modified_at >= t && info.last_modified_at <= time (NULL));
  tr_sys_file_close (fd, NULL);

  tr_sys_path_remove (path1, NULL);

  /* Good directory info */
  t = time (NULL);
  tr_sys_dir_create (path1, 0, 0777, NULL);
  clear_path_info (&info);
  check (tr_sys_path_get_info (path1, 0, &info, &err));
  check (err == NULL);
  check_int_eq (TR_SYS_PATH_IS_DIRECTORY, info.type);
  check (info.size != (uint64_t) -1);
  check (info.last_modified_at >= t && info.last_modified_at <= time (NULL));
  tr_sys_path_remove (path1, NULL);

  if (create_symlink (path1, path2, false))
    {
      /* Can't get info of non-existent file/directory */
      check (!tr_sys_path_get_info (path1, 0, &info, &err));
      check (err != NULL);
      tr_error_clear (&err);

      t = time (NULL);
      libtest_create_file_with_string_contents (path2, "test");

      /* Good file info */
      clear_path_info (&info);
      check (tr_sys_path_get_info (path1, 0, &info, &err));
      check (err == NULL);
      check_int_eq (TR_SYS_PATH_IS_FILE, info.type);
      check_int_eq (4, info.size);
      check (info.last_modified_at >= t && info.last_modified_at <= time (NULL));

      /* Good file info (by handle) */
      fd = tr_sys_file_open (path1, TR_SYS_FILE_READ, 0, NULL);
      clear_path_info (&info);
      check (tr_sys_file_get_info (fd, &info, &err));
      check (err == NULL);
      check_int_eq (TR_SYS_PATH_IS_FILE, info.type);
      check_int_eq (4, info.size);
      check (info.last_modified_at >= t && info.last_modified_at <= time (NULL));
      tr_sys_file_close (fd, NULL);

      tr_sys_path_remove (path2, NULL);

      /* Good directory info */
      t = time (NULL);
      tr_sys_dir_create (path2, 0, 0777, NULL);
      clear_path_info (&info);
      check (tr_sys_path_get_info (path1, 0, &info, &err));
      check (err == NULL);
      check_int_eq (TR_SYS_PATH_IS_DIRECTORY, info.type);
      check (info.size != (uint64_t) -1);
      check (info.last_modified_at >= t && info.last_modified_at <= time (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;
}