Beispiel #1
0
    def __init__(self, storage, config, hashes, piece_size, finished,
            statusfunc, flag, data_flunked, infohash, errorfunc, resumefile):
        self.numpieces = len(hashes)
        self.storage = storage
        self.config = config
        check_hashes = config['check_hashes']
        self.hashes = hashes
        self.piece_size = piece_size
        self.data_flunked = data_flunked
        self.errorfunc = errorfunc
        self.total_length = storage.get_total_length()
        self.amount_left = self.total_length
        self.partial_mark = "BitTorrent - this part has not been "+\
                            "downloaded yet."+infohash+\
                            tobinary(config['download_slice_size'])
        if self.total_length <= piece_size * (self.numpieces - 1):
            raise BTFailure, _("bad data in responsefile - total too small")
        if self.total_length > piece_size * self.numpieces:
            raise BTFailure, _("bad data in responsefile - total too big")
        self.finished = finished
        self.numactive = array('H', [0] * self.numpieces)
        self.inactive_requests = [1] * self.numpieces
        self.amount_inactive = self.total_length
        self.endgame = False
        self.have = Bitfield(self.numpieces)
        self.waschecked = Bitfield(self.numpieces)
        if self.numpieces < 32768:
            typecode = 'h'
        else:
            typecode = 'l'
        self.places = array(typecode, [NO_PLACE] * self.numpieces)
        if not check_hashes:
            self.rplaces = array(typecode, range(self.numpieces))
            fastresume = True
        else:
            self.rplaces = self._load_fastresume(resumefile, typecode)
            if self.rplaces is not None:
                fastresume = True
            else:
                self.rplaces = array(typecode, [UNALLOCATED] * self.numpieces)
                fastresume = False
        self.holepos = 0
        self.stat_numfound = 0
        self.stat_numflunked = 0
        self.stat_numdownloaded = 0
        self.stat_active = {}
        self.stat_new = {}
        self.stat_dirty = {}
        self.download_history = {}
        self.failed_pieces = {}

        if self.numpieces == 0:
            return
        targets = {}
        total = 0
        if not fastresume:
            for i in xrange(self.numpieces):
                if self._waspre(i):
                    self.rplaces[i] = ALLOCATED
                    total += 1
                else:
                    targets[hashes[i]] = i
        if total and check_hashes:
            statusfunc(_("checking existing file"), 0)
        def markgot(piece, pos):
            if self.have[piece]:
                if piece != pos:
                    return
                self.rplaces[self.places[pos]] = ALLOCATED
                self.places[pos] = self.rplaces[pos] = pos
                return
            self.places[piece] = pos
            self.rplaces[pos] = piece
            self.have[piece] = True
            self.amount_left -= self._piecelen(piece)
            self.amount_inactive -= self._piecelen(piece)
            self.inactive_requests[piece] = None
            if not fastresume:
                self.waschecked[piece] = True
            self.stat_numfound += 1
        lastlen = self._piecelen(self.numpieces - 1)
        partials = {}
        for i in xrange(self.numpieces):
            if not self._waspre(i):
                if self.rplaces[i] != UNALLOCATED:
                    raise BTFailure(_("--check_hashes 0 or fastresume info "
                                      "doesn't match file state (missing data)"))
                continue
            elif fastresume:
                t = self.rplaces[i]
                if t >= 0:
                    markgot(t, i)
                    continue
                if t == UNALLOCATED:
                    raise BTFailure(_("Bad fastresume info (files contain more "
                                      "data)"))
                if t == ALLOCATED:
                    continue
                if t!= FASTRESUME_PARTIAL:
                    raise BTFailure(_("Bad fastresume info (illegal value)"))
                data = self.storage.read(self.piece_size * i,
                                         self._piecelen(i))
                self._check_partial(i, partials, data)
                self.rplaces[i] = ALLOCATED
            else:
                data = self.storage.read(piece_size * i, self._piecelen(i))
                sh = sha(buffer(data, 0, lastlen))
                sp = sh.digest()
                sh.update(buffer(data, lastlen))
                s = sh.digest()
                if s == hashes[i]:
                    markgot(i, i)
                elif s in targets and self._piecelen(i) == self._piecelen(targets[s]):
                    markgot(targets[s], i)
                elif not self.have[self.numpieces - 1] and sp == hashes[-1] and (i == self.numpieces - 1 or not self._waspre(self.numpieces - 1)):
                    markgot(self.numpieces - 1, i)
                else:
                    self._check_partial(i, partials, data)
                statusfunc(fractionDone = 1 - self.amount_left /
                           self.total_length)
            if flag.isSet():
                return
        self.amount_left_with_partials = self.amount_left
        for piece in partials:
            if self.places[piece] < 0:
                pos = partials[piece][0]
                self.places[piece] = pos
                self.rplaces[pos] = piece
                self._make_partial(piece, partials[piece][1])
        for i in xrange(self.numpieces):
            if self.rplaces[i] != UNALLOCATED:
                self.storage.allocated(piece_size * i, self._piecelen(i))
            if self.have[i]:
                self.storage.downloaded(piece_size * i, self._piecelen(i))
Beispiel #2
0
def make_meta_files(url,
                    files,
                    flag=Event(),
                    progressfunc=dummy,
                    filefunc=dummy,
                    piece_len_pow2=None,
                    target=None,
                    comment=None,
                    filesystem_encoding=None,
                    use_tracker=True,
                    data_dir=None):
    if len(files) > 1 and target:
        raise BTFailure(
            _("You can't specify the name of the .torrent file "
              "when generating multiple torrents at once"))

    if not filesystem_encoding:
        try:
            getattr(sys, 'getfilesystemencoding')
        except AttributeError:
            pass
        else:
            filesystem_encoding = sys.getfilesystemencoding()
        if not filesystem_encoding:
            filesystem_encoding = 'ascii'
    try:
        'a1'.decode(filesystem_encoding)
    except:
        raise BTFailure(
            _('Filesystem encoding "%s" is not supported in this version') %
            filesystem_encoding)
    files.sort()
    ext = '.torrent'

    togen = []
    for f in files:
        if not f.endswith(ext):
            togen.append(f)

    total = 0
    for f in togen:
        total += calcsize(f)

    subtotal = [0]

    def callback(x):
        subtotal[0] += x
        progressfunc(subtotal[0] / total)

    for f in togen:
        if flag.isSet():
            break
        t = os.path.split(f)
        if t[1] == '':
            f = t[0]
        filefunc(f)
        if use_tracker:
            make_meta_file(f,
                           url,
                           flag=flag,
                           progress=callback,
                           piece_len_exp=piece_len_pow2,
                           target=target,
                           comment=comment,
                           encoding=filesystem_encoding)
        else:
            make_meta_file_dht(f,
                               url,
                               flag=flag,
                               progress=callback,
                               piece_len_exp=piece_len_pow2,
                               target=target,
                               comment=comment,
                               encoding=filesystem_encoding,
                               data_dir=data_dir)
Beispiel #3
0
        # defaultargs.py is even more annoying.  --Dave
        ddir = os.path.join( platform.get_dot_dir(), "launchmany-console" )
        ddir = decode_from_filesystem(ddir)
        modify_default(defaults, 'data_dir', ddir)
        config, args = configfile.parse_configuration_and_args(defaults,
                                      uiname, sys.argv[1:], 0, 1)

        # returned from here config['save_in'] is /home/dave/Desktop/...
        if args:
            torrent_dir = args[0]
            config['torrent_dir'] = torrent_dir
        else:
            torrent_dir = config['torrent_dir']
            torrent_dir,bad = encode_for_filesystem(torrent_dir)
            if bad:
              raise BTFailure(_("Warning: ")+config['torrent_dir']+
                              _(" is not a directory"))

        if not os.path.isdir(torrent_dir):
            raise BTFailure(_("Warning: ")+torrent_dir+
                            _(" is not a directory"))

        # the default behavior is to save_in files to the platform
        # get_save_dir.  For launchmany, if no command-line argument
        # changed the save directory then use the torrent directory.
        #if config['save_in'] == platform.get_save_dir():
        #    config['save_in'] = config['torrent_dir']
        if '--save_in' in sys.argv:
            print "Don't use --save_in for launchmany-console.  Saving files from " \
                  "many torrents in the same directory can result in filename collisions."
            sys.exit(1)
        # The default 'save_in' is likely to be something like /home/myname/BitTorrent Downloads
Beispiel #4
0
                    t.working_path = encode_for_filesystem(t.working_path)[0]
                    t.destination_path = t.working_path
                elif version == 3:
                    up, down, working_path = line[41:-1].split(' ', 2)
                    t.uptotal = t.uptotal_old = int(up)
                    t.downtotal = t.downtotal_old = int(down)
                    t.working_path = working_path.decode('string_escape')
                    t.working_path = t.working_path.decode('utf-8')
                    t.working_path = encode_for_filesystem(t.working_path)[0]
                    t.destination_path = t.working_path
                elif version >= 4:
                    up, down = line[41:-1].split(' ', 1)
                    t.uptotal = t.uptotal_old = int(up)
                    t.downtotal = t.downtotal_old = int(down)
            except ValueError:  # unpack, int(), decode()
                raise BTFailure(_("Invalid state file (bad entry)"))

            torrent_config = self.config
            try:
                if version < 5:
                    torrent_config = configfile.read_torrent_config(
                                                           self.config,
                                                           self.data_dir,
                                                           infohash,
                                                           lambda s : self.global_error(logging.ERROR, s))
                else:
                    torrent_config = self._read_torrent_config(infohash)
                t.update_config(torrent_config)
            except BTFailure, e:
                self.logger.error("Read torrent config failed",
                                  exc_info=sys.exc_info())
Beispiel #5
0
 def __init__(self, *args):
     IPCSocketBase.__init__(self, *args)
     data_dir, bad = encode_for_filesystem(self.config['data_dir'])
     if bad:
         raise BTFailure(_("Invalid path encoding."))
     self.socket_filename = os.path.join(data_dir, self.name)
    def message(self, s):
        print "### "+s

    def exception(self, s):
        exceptions.append(s)
        self.message(_("SYSTEM ERROR - EXCEPTION GENERATED"))


if __name__ == '__main__':
    uiname = 'launchmany-console'
    defaults = get_defaults(uiname)
    try:
        if len(sys.argv) < 2:
            printHelp(uiname, defaults)
            sys.exit(1)
        config, args = configfile.parse_configuration_and_args(defaults,
                                      uiname, sys.argv[1:], 0, 1)
        if args:
            config['torrent_dir'] = args[0]
        if not os.path.isdir(config['torrent_dir']):
            raise BTFailure(_("Warning: ")+args[0]+_(" is not a directory"))
    except BTFailure, e:
        print _("error: %s\nrun with no args for parameter explanations") % str(e) 
        sys.exit(1)

    LaunchMany(config, HeadlessDisplayer(), 'launchmany-console')
    if exceptions:
        print _("\nEXCEPTION:")
        print exceptions[0]
        if args:
            if config['responsefile']:
                raise BTFailure, 'must have responsefile as arg or ' \
                      'parameter, not both'
            config['responsefile'] = args[0]
        try:
            if config['responsefile']:
                h = file(config['responsefile'], 'rb')
                metainfo = h.read()
                h.close()
            elif config['url']:
                h = urlopen(config['url'])
                metainfo = h.read()
                h.close()
            else:
                raise BTFailure('you need to specify a .torrent file')
        except IOError, e:
            raise BTFailure('Error reading .torrent file: ', str(e))
    except BTFailure, e:
        print str(e)
        sys.exit(1)

    errlist = []
    dl = DL(metainfo, config, errlist)
    curses_wrapper(dl.run)

    if errlist:
       print "These errors occurred during execution:"
       for error in errlist:
          print error