Exemple #1
0
def bdecode(x):
    try:
        r, l = decode_func[x[0]](x, 0)
    except (IndexError, KeyError, ValueError):
        raise BTFailure("not a valid bencoded string")
    if l != len(x):
        raise BTFailure("invalid bencoded value (data after valid prefix)")
    return r
Exemple #2
0
 def add_files(self, files, torrent):
     for filename in files:
         if filename in self.file_to_torrent:
             raise BTFailure(_("File %s belongs to another running torrent")
                             % filename)
     for filename in files:
         self.file_to_torrent[filename] = torrent
Exemple #3
0
    def _batch_read(self, pos, amount):
        dfs = []
        r = []

        # queue all the reads
        for filename, pos, end in self._intervals(pos, amount):
            df = self._file_op(filename, pos, end - pos, write=False)
            dfs.append(df)

        # yield on all the reads in order - they complete in any order
        exc = None
        for df in dfs:
            yield df
            try:
                r.append(df.getResult())
            except:
                exc = exc or sys.exc_info()
        if exc:
            raise exc[0], exc[1], exc[2]

        r = ''.join(r)

        if len(r) != amount:
            raise BTFailure(_("Short read (%d of %d) - "
                              "something truncated files?") %
                            (len(r), amount))

        yield r
Exemple #4
0
class IcmpIPC(object):
    def __init__(self, rawserver):
        self.rawserver = rawserver

    def create(self):
        self.filename = os.path.join(get_dot_dir(), "xicmp-unix-socket")

        if os.path.exists(self.filename):
            # HEREDAVE. I might add this check back later. --Dave
            #try:
            #    self.write_message(tobinary(0))
            #except BTFailure:
            #    pass
            #else:
            #    raise BTFailure(_("Could not create icmp unix socket: already in use"))
            try:
                os.unlink(self.filename)
            except OSError, e:
                raise BTFailure(
                    _("Could not remove old icmp socket filename:") +
                    unicode(e.args[0]))
        try:
            icmp_socket = self.rawserver.create_unixserversocket(self.filename)
        except socket.error, e:
            raise BTFailure(
                _("Could not create icmp socket: ") + unicode(e.args[0]))
Exemple #5
0
def check_info(info, check_paths=True):
    if not isinstance(info, dict):
        raise BTFailure, _("bad metainfo - not a dictionary")
    pieces = info.get('pieces')
    if type(pieces) != str or len(pieces) % 20 != 0 or len(pieces) == 0:
        raise BTFailure, _("bad metainfo - bad pieces key")
    piecelength = info.get('piece length')
    if type(piecelength) not in ints or piecelength <= 0:
        raise BTFailure, _("bad metainfo - illegal piece length")
    name = info.get('name')
    if not isinstance(name, str):
        raise BTFailure, _("bad metainfo - bad name")
    #if not allowed_path_re.match(name):
    #    raise BTFailure, _("name %s disallowed for security reasons") % name
    if info.has_key('files') == info.has_key('length'):
        raise BTFailure, _("single/multiple file mix")
    if info.has_key('length'):
        length = info.get('length')
        if type(length) not in ints or length < 0:
            raise BTFailure, _("bad metainfo - bad length")
    else:
        files = info.get('files')
        if type(files) != list:
            raise BTFailure, _('bad metainfo - "files" is not a list of files')
        for f in files:
            if type(f) != dict:
                raise BTFailure, _("bad metainfo - file entry must be a dict")
            length = f.get('length')
            if type(length) not in ints or length < 0:
                raise BTFailure, _("bad metainfo - bad length")
            path = f.get('path')
            if type(path) != list or path == []:
                raise BTFailure, _("bad metainfo - bad path")
            for p in path:
                if type(p) != str:
                    raise BTFailure, _("bad metainfo - bad path dir")
                if check_paths and not allowed_path_re.match(p):
                    raise BTFailure, _(
                        "path %s disallowed for security reasons") % p
        f = ['/'.join(x['path']) for x in files]
        f.sort()
        i = iter(f)
        try:
            name2 = i.next()
            while True:
                name1 = name2
                name2 = i.next()
                if name2.startswith(name1):
                    if name1 == name2:
                        raise BTFailure, _("bad metainfo - duplicate path")
                    elif name2[len(name1)] == '/':
                        raise BTFailure(
                            _("bad metainfo - name used as both"
                              "file and subdirectory name"))
        except StopIteration:
            pass
Exemple #6
0
def bdecode(x):
    try:
        r, l = decode_func[x[0]](x, 0)
    except (IndexError, KeyError, ValueError):
        raise BTFailure("not a valid bencoded string")

    # GAIA
    # Files downloaded through the Gaia API Flare cause an exception here although they are valid.
    # Ignore this exception for now.
    #if l != len(x):
    #    raise BTFailure("invalid bencoded value (data after valid prefix)")

    return r
Exemple #7
0
    def _build_file_structs(self, filepool, files):
        total = 0
        for filename, length in files:
            # we're shutting down, abort.
            if self.doneflag.isSet():
                return False

            self.undownloaded[filename] = length
            if length > 0:
                self.ranges.append((total, total + length, filename))

            self.range_by_name[filename] = (total, total + length)

            if os.path.exists(filename):
                if not os.path.isfile(filename):
                    raise BTFailure(
                        _("File %s already exists, but is not a "
                          "regular file") % filename)
                l = os.path.getsize(filename)
                if l > length:
                    # This is the truncation Bram was talking about that no one
                    # else thinks is a good idea.
                    #h = file(filename, 'rb+')
                    #make_file_sparse(filename, h, length)
                    #h.truncate(length)
                    #h.close()
                    l = length

                a = get_allocated_regions(filename, begin=0, length=l)
                if a is not None:
                    a.offset(total)
                else:
                    a = SparseSet()
                    if l > 0:
                        a.add(total, total + l)
                self.allocated_regions += a
            total += length
        self.total_length = total
        self.initialized = True
        return True
Exemple #8
0
    def __init__(self, metainfo):
        """metainfo is a dict.  When read from a metainfo (i.e.,
           .torrent file), the file must first be bdecoded before
           being passed to ConvertedMetainfo."""
        self.bad_torrent_wrongfield = False
        self.bad_torrent_unsolvable = False
        self.bad_torrent_noncharacter = False
        self.bad_conversion = False
        self.bad_windows = False
        self.bad_path = False
        self.reported_errors = False

        # All of the following values should be considered READONLY.
        # Modifications to the metainfo that should be written should
        # occur to the underlying metainfo dict directly.
        self.is_batch = False
        self.orig_files = None
        self.files_fs = None
        self.total_bytes = 0
        self.sizes = []
        self.comment = None
        self.title = None          # descriptive title text for whole torrent
        self.creation_date = None
        self.metainfo = metainfo
        self.encoding = None
        self.caches = None
        #EZ micropayments are used 
        self.micropayments = False

        btformats.check_message(metainfo, check_paths=False)
        info = metainfo['info']
        self.is_private = info.has_key("private") and info['private']
        if 'encoding' in metainfo:
            self.encoding = metainfo['encoding']
        elif 'codepage' in metainfo:
            self.encoding = 'cp%s' % metainfo['codepage']
        if self.encoding is not None:
            try:
                for s in u'this is a test', u'these should also work in any encoding: 0123456789\0':
                    assert s.encode(self.encoding).decode(self.encoding) == s
            except:
                self.encoding = 'iso-8859-1'
                self.bad_torrent_unsolvable = True
        if info.has_key('length'):
            self.total_bytes = info['length']
            self.sizes.append(self.total_bytes)
            if info.has_key('content_type'):
                self.content_type = info['content_type']
            else:
                self.content_type = None  # hasattr or None.  Which is better?
        else:
            self.is_batch = True
            r = []
            self.orig_files = []
            self.sizes = []
            self.content_types = []
            i = 0
            # info['files'] is a list of dicts containing keys:
            # 'length', 'path', and 'content_type'.  The 'content_type'
            # key is optional.
            for f in info['files']:
                l = f['length']
                self.total_bytes += l
                self.sizes.append(l)
                self.content_types.append(f.get('content_type'))
                path = self._get_attr(f, 'path')
                if len(path[-1]) == 0:
                    if l > 0:
                        raise BTFailure(_("Bad file path component: ")+x)
                    # BitComet makes .torrent files with directories
                    # listed along with the files, which we don't support
                    # yet, in part because some idiot interpreted this as
                    # a bug in BitComet rather than a feature.
                    path.pop(-1)

                for x in path:
                    if not btformats.allowed_path_re.match(x):
                        raise BTFailure(_("Bad file path component: ")+x)

                self.orig_files.append('/'.join(path))
                k = []
                for u in path:
                    tf2 = self._to_fs_2(u)
                    k.append((tf2, u))
                r.append((k,i))
                i += 1
            # If two or more file/subdirectory names in the same directory
            # would map to the same name after encoding conversions + Windows
            # workarounds, change them. Files are changed as
            # 'a.b.c'->'a.b.0.c', 'a.b.1.c' etc, directories or files without
            # '.' as 'a'->'a.0', 'a.1' etc. If one of the multiple original
            # names was a "clean" conversion, that one is always unchanged
            # and the rest are adjusted.
            r.sort()
            self.files_fs = [None] * len(r)
            prev = [None]
            res = []
            stack = [{}]
            for x in r:
                j = 0
                x, i = x
                while x[j] == prev[j]:
                    j += 1
                del res[j:]
                del stack[j+1:]
                name = x[j][0][1]
                if name in stack[-1]:
                    for name in generate_names(x[j][1], j != len(x) - 1):
                        name = self._to_fs(name)
                        if name not in stack[-1]:
                            break
                stack[-1][name] = None
                res.append(name)
                for j in xrange(j + 1, len(x)):
                    name = x[j][0][1]
                    stack.append({name: None})
                    res.append(name)
                self.files_fs[i] = os.path.join(*res)
                prev = x

        self.name = self._get_attr(info, 'name')
        self.name_fs = self._to_fs(self.name)
        self.piece_length = info['piece length']

        self.announce = metainfo.get('announce')
        self.announce_list = metainfo.get('announce-list')
        if 'announce-list' not in metainfo and 'announce' not in metainfo:
            self.is_trackerless = True
        else:
            self.is_trackerless = False
        #EZ
        if 'micropayments' in metainfo and metainfo['micropayments'] == True:
            print "found micropayments ==true in metafile"
            self.micropayments = True    
        

        self.nodes = metainfo.get('nodes', [('router.bittorrent.com', 6881)])

        self.title = metainfo.get('title')
        self.comment = metainfo.get('comment')
        self.creation_date = metainfo.get('creation date')
        self.locale = metainfo.get('locale')

        self.safe = metainfo.get('safe')

        self.url_list = metainfo.get('url-list', [])
        if not isinstance(self.url_list, list):
            self.url_list = [self.url_list, ]

        self.caches = metainfo.get('caches')

        self.hashes = [info['pieces'][x:x+20] for x in xrange(0,
            len(info['pieces']), 20)]
        self.infohash = InfoHashType(sha(bencode(info)).digest())
def bdecode_len(x):
    try:
        return decode_func[x[0]](x, 0)
    except (IndexError, KeyError, ValueError):
        trace.print_exc()
        raise BTFailure("not a valid bencoded string")
def bdecode(x):
    r, l = bdecode_len(x)
    if l != len(x):
        raise BTFailure("invalid bencoded value (data after valid prefix)")
    return r