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
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
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
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]))
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
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
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
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