Example #1
0
static uint64_t
loadProgress (tr_variant * dict, tr_torrent * tor)
{
  size_t i, n;
  uint64_t ret = 0;
  tr_variant * prog;
  const tr_info * inf = tr_torrentInfo (tor);

  for (i=0, n=inf->pieceCount; i<n; ++i)
    inf->pieces[i].timeChecked = 0;

  if (tr_variantDictFindDict (dict, TR_KEY_progress, &prog))
    {
      const char * err;
      const char * str;
      const uint8_t * raw;
      size_t rawlen;
      tr_variant * l;
      tr_variant * b;
      struct tr_bitfield blocks = TR_BITFIELD_INIT;

      if (tr_variantDictFindList (prog, TR_KEY_time_checked, &l))
        {
          /* per-piece timestamps were added in 2.20.

             If some of a file's pieces have been checked more recently than
             the file's mtime, and some lest recently, then that file will
             have a list containing timestamps for each piece.

             However, the most common use case is that the file doesn't change
             after it's downloaded. To reduce overhead in the .resume file,
             only a single timestamp is saved for the file if *all* or *none*
             of the pieces were tested more recently than the file's mtime. */

          tr_file_index_t fi;

          for (fi=0; fi<inf->fileCount; ++fi)
            {
              tr_variant * b = tr_variantListChild (l, fi);
              const tr_file * f = &inf->files[fi];
              tr_piece * p = &inf->pieces[f->firstPiece];
              const tr_piece * pend = &inf->pieces[f->lastPiece]+1;

              if (tr_variantIsInt (b))
                {
                  int64_t t;
                  tr_variantGetInt (b, &t);
                  for (; p!=pend; ++p)
                    p->timeChecked = (time_t)t;
                }
              else if (tr_variantIsList (b))
                {
                  int i = 0;
                  int64_t offset = 0;
                  const int pieces = f->lastPiece + 1 - f->firstPiece;

                  tr_variantGetInt (tr_variantListChild (b, 0), &offset);

                  for (i=0; i<pieces; ++i)
                    {
                      int64_t t = 0;
                      tr_variantGetInt (tr_variantListChild (b, i+1), &t);
                      inf->pieces[f->firstPiece+i].timeChecked = (time_t)(t ? t + offset : 0);
                    }
                }
            }
        }
      else if (tr_variantDictFindList (prog, TR_KEY_mtimes, &l))
        {
          tr_file_index_t fi;

          /* Before 2.20, we stored the files' mtimes in the .resume file.
             When loading the .resume file, a torrent's file would be flagged
             as untested if its stored mtime didn't match its real mtime. */

          for (fi=0; fi<inf->fileCount; ++fi)
            {
              int64_t t;

              if (tr_variantGetInt (tr_variantListChild (l, fi), &t))
                {
                  const tr_file * f = &inf->files[fi];
                  tr_piece * p = &inf->pieces[f->firstPiece];
                  const tr_piece * pend = &inf->pieces[f->lastPiece];
                  const time_t mtime = tr_torrentGetFileMTime (tor, fi);
                  const time_t timeChecked = mtime==t ? mtime : 0;

                  for (; p!=pend; ++p)
                    p->timeChecked = timeChecked;
                }
            }
        }

      err = NULL;
      tr_bitfieldConstruct (&blocks, tor->blockCount);

      if ((b = tr_variantDictFind (prog, TR_KEY_blocks)))
        {
          size_t buflen;
          const uint8_t * buf;

          if (!tr_variantGetRaw (b, &buf, &buflen))
            err = "Invalid value for \"blocks\"";
          else if ((buflen == 3) && !memcmp (buf, "all", 3))
            tr_bitfieldSetHasAll (&blocks);
          else if ((buflen == 4) && !memcmp (buf, "none", 4))
            tr_bitfieldSetHasNone (&blocks);
          else
            tr_bitfieldSetRaw (&blocks, buf, buflen, true);
        }
      else if (tr_variantDictFindStr (prog, TR_KEY_have, &str, NULL))
        {
          if (!strcmp (str, "all"))
            tr_bitfieldSetHasAll (&blocks);
          else
            err = "Invalid value for HAVE";
        }
      else if (tr_variantDictFindRaw (prog, TR_KEY_bitfield, &raw, &rawlen))
        {
          tr_bitfieldSetRaw (&blocks, raw, rawlen, true);
        }
      else err = "Couldn't find 'pieces' or 'have' or 'bitfield'";

      if (err != NULL)
        tr_logAddTorDbg (tor, "Torrent needs to be verified - %s", err);
      else
        tr_cpBlockInit (&tor->completion, &blocks);

      tr_bitfieldDestruct (&blocks);
      ret = TR_FR_PROGRESS;
    }

  return ret;
}
Example #2
0
static char const* parseFiles(tr_info* inf, tr_variant* files, tr_variant const* length)
{
    int64_t len;

    inf->totalSize = 0;

    if (tr_variantIsList(files)) /* multi-file mode */
    {
        struct evbuffer* buf;
        char const* result;

        if (path_component_is_suspicious(inf->name))
        {
            return "path";
        }

        buf = evbuffer_new();
        result = NULL;

        inf->isFolder = true;
        inf->fileCount = tr_variantListSize(files);
        inf->files = tr_new0(tr_file, inf->fileCount);

        for (tr_file_index_t i = 0; i < inf->fileCount; i++)
        {
            tr_variant* file;
            tr_variant* path;

            file = tr_variantListChild(files, i);

            if (!tr_variantIsDict(file))
            {
                result = "files";
                break;
            }

            if (!tr_variantDictFindList(file, TR_KEY_path_utf_8, &path))
            {
                if (!tr_variantDictFindList(file, TR_KEY_path, &path))
                {
                    result = "path";
                    break;
                }
            }

            if (!getfile(&inf->files[i].name, inf->name, path, buf))
            {
                result = "path";
                break;
            }

            if (!tr_variantDictFindInt(file, TR_KEY_length, &len))
            {
                result = "length";
                break;
            }

            inf->files[i].length = len;
            inf->totalSize += len;
        }

        evbuffer_free(buf);
        return result;
    }
    else if (tr_variantGetInt(length, &len)) /* single-file mode */
    {
        if (path_component_is_suspicious(inf->name))
        {
            return "path";
        }

        inf->isFolder = false;
        inf->fileCount = 1;
        inf->files = tr_new0(tr_file, 1);
        inf->files[0].name = tr_strdup(inf->name);
        inf->files[0].length = len;
        inf->totalSize += len;
    }
    else
    {
        return "length";
    }

    return NULL;
}