Changeset 388 for python/vendor/current/Lib/tarfile.py
- Timestamp:
- Mar 19, 2014, 11:11:30 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
python/vendor/current/Lib/tarfile.py
r2 r388 31 31 """ 32 32 33 __version__ = "$Revision: 76386$"33 __version__ = "$Revision: 85213 $" 34 34 # $Source$ 35 35 36 36 version = "0.9.0" 37 37 __author__ = "Lars Gustäbel (lars@gustaebel.de)" 38 __date__ = "$Date : 2009-11-18 16:09:35 -0500 (Wed, 18 Nov 2009)$"39 __cvsid__ = "$Id : tarfile.py 76386 2009-11-18 21:09:35Z lars.gustaebel$"38 __date__ = "$Date$" 39 __cvsid__ = "$Id$" 40 40 __credits__ = "Gustavo Niemeyer, Niels Gustäbel, Richard Townsend." 41 41 … … 54 54 import operator 55 55 56 if sys.platform == 'mac':57 # This module needs work for MacOS9, especially in the area of pathname58 # handling. In many places it is assumed a simple substitution of / by the59 # local os.path.sep is good enough to convert pathnames, but this does not60 # work with the mac rooted:path:name versus :nonrooted:path:name syntax61 raise ImportError, "tarfile does not work for platform==mac"62 63 56 try: 64 57 import grp, pwd … … 196 189 n = int(nts(s) or "0", 8) 197 190 except ValueError: 198 raise HeaderError("invalid header")191 raise InvalidHeaderError("invalid header") 199 192 else: 200 193 n = 0L … … 331 324 return "".join(perm) 332 325 333 if os.sep != "/":334 normpath = lambda path: os.path.normpath(path).replace(os.sep, "/")335 else:336 normpath = os.path.normpath337 338 326 class TarError(Exception): 339 327 """Base exception.""" … … 343 331 pass 344 332 class ReadError(TarError): 345 """Exception for unread ble tar archives."""333 """Exception for unreadable tar archives.""" 346 334 pass 347 335 class CompressionError(TarError): … … 352 340 pass 353 341 class HeaderError(TarError): 342 """Base exception for header errors.""" 343 pass 344 class EmptyHeaderError(HeaderError): 345 """Exception for empty headers.""" 346 pass 347 class TruncatedHeaderError(HeaderError): 348 """Exception for truncated headers.""" 349 pass 350 class EOFHeaderError(HeaderError): 351 """Exception for end of file headers.""" 352 pass 353 class InvalidHeaderError(HeaderError): 354 354 """Exception for invalid headers.""" 355 pass 356 class SubsequentHeaderError(HeaderError): 357 """Exception for missing and invalid extended headers.""" 355 358 pass 356 359 … … 371 374 if hasattr(os, "O_BINARY"): 372 375 mode |= os.O_BINARY 373 self.fd = os.open(name, mode )376 self.fd = os.open(name, mode, 0666) 374 377 375 378 def close(self): … … 452 455 timestamp = struct.pack("<L", long(time.time())) 453 456 self.__write("\037\213\010\010%s\002\377" % timestamp) 457 if type(self.name) is unicode: 458 self.name = self.name.encode("iso-8859-1", "replace") 454 459 if self.name.endswith(".gz"): 455 460 self.name = self.name[:-3] … … 625 630 if self.buf.startswith("\037\213\010"): 626 631 return "gz" 627 if self.buf .startswith("BZh91"):632 if self.buf[0:3] == "BZh" and self.buf[4:10] == "1AY&SY": 628 633 return "bz2" 629 634 return "tar" … … 666 671 if not raw: 667 672 break 668 try: 669 data = self.bz2obj.decompress(raw) 670 except EOFError: 671 break 673 data = self.bz2obj.decompress(raw) 672 674 b.append(data) 673 675 x += len(data) … … 929 931 self.type = REGTYPE # member type 930 932 self.linkname = "" # link name 931 self.uname = " root"# user name932 self.gname = " root"# group name933 self.uname = "" # user name 934 self.gname = "" # group name 933 935 self.devmajor = 0 # device major number 934 936 self.devminor = 0 # device minor number … … 960 962 """ 961 963 info = { 962 "name": normpath(self.name),964 "name": self.name, 963 965 "mode": self.mode & 07777, 964 966 "uid": self.uid, … … 968 970 "chksum": self.chksum, 969 971 "type": self.type, 970 "linkname": normpath(self.linkname) if self.linkname else "",972 "linkname": self.linkname, 971 973 "uname": self.uname, 972 974 "gname": self.gname, … … 1113 1115 stn(info.get("linkname", ""), 100), 1114 1116 stn(info.get("magic", POSIX_MAGIC), 8), 1115 stn(info.get("uname", " root"), 32),1116 stn(info.get("gname", " root"), 32),1117 stn(info.get("uname", ""), 32), 1118 stn(info.get("gname", ""), 32), 1117 1119 itn(info.get("devmajor", 0), 8, format), 1118 1120 itn(info.get("devminor", 0), 8, format), … … 1188 1190 """Construct a TarInfo object from a 512 byte string buffer. 1189 1191 """ 1192 if len(buf) == 0: 1193 raise EmptyHeaderError("empty header") 1190 1194 if len(buf) != BLOCKSIZE: 1191 raise HeaderError("truncated header")1195 raise TruncatedHeaderError("truncated header") 1192 1196 if buf.count(NUL) == BLOCKSIZE: 1193 raise HeaderError("emptyheader")1197 raise EOFHeaderError("end of file header") 1194 1198 1195 1199 chksum = nti(buf[148:156]) 1196 1200 if chksum not in calc_chksums(buf): 1197 raise HeaderError("bad checksum")1201 raise InvalidHeaderError("bad checksum") 1198 1202 1199 1203 obj = cls() … … 1234 1238 """ 1235 1239 buf = tarfile.fileobj.read(BLOCKSIZE) 1236 if not buf:1237 return1238 1240 obj = cls.frombuf(buf) 1239 1241 obj.offset = tarfile.fileobj.tell() - BLOCKSIZE … … 1288 1290 1289 1291 # Fetch the next header and process it. 1290 next = self.fromtarfile(tarfile) 1291 if next is None: 1292 raise HeaderError("missing subsequent header") 1292 try: 1293 next = self.fromtarfile(tarfile) 1294 except HeaderError: 1295 raise SubsequentHeaderError("missing or bad subsequent header") 1293 1296 1294 1297 # Patch the TarInfo object from the next header with … … 1395 1398 1396 1399 # Fetch the next header. 1397 next = self.fromtarfile(tarfile) 1400 try: 1401 next = self.fromtarfile(tarfile) 1402 except HeaderError: 1403 raise SubsequentHeaderError("missing or bad subsequent header") 1398 1404 1399 1405 if self.type in (XHDTYPE, SOLARIS_XHDTYPE): 1400 if next is None:1401 raise HeaderError("missing subsequent header")1402 1403 1406 # Patch the TarInfo object with the extended header info. 1404 1407 next._apply_pax_info(pax_headers, tarfile.encoding, tarfile.errors) … … 1482 1485 # continues processing. 1483 1486 1484 errorlevel = 0# If 0, fatal errors only appear in debug1487 errorlevel = 1 # If 0, fatal errors only appear in debug 1485 1488 # messages (if debug >= 0). If > 0, errors 1486 1489 # are passed to the caller as exceptions. … … 1574 1577 # Move to the end of the archive, 1575 1578 # before the first empty block. 1576 self.firstmember = None1577 1579 while True: 1578 if self.next() is None: 1579 if self.offset > 0: 1580 self.fileobj.seek(- BLOCKSIZE, 1) 1580 self.fileobj.seek(self.offset) 1581 try: 1582 tarinfo = self.tarinfo.fromtarfile(self) 1583 self.members.append(tarinfo) 1584 except EOFHeaderError: 1585 self.fileobj.seek(self.offset) 1581 1586 break 1587 except HeaderError, e: 1588 raise ReadError(str(e)) 1582 1589 1583 1590 if self.mode in "aw": … … 1744 1751 try: 1745 1752 t = cls.taropen(name, mode, fileobj, **kwargs) 1746 except IOError:1753 except (IOError, EOFError): 1747 1754 raise ReadError("not a bzip2 file") 1748 1755 t._extfileobj = False … … 1825 1832 if arcname is None: 1826 1833 arcname = name 1827 arcname = normpath(arcname)1828 1834 drv, arcname = os.path.splitdrive(arcname) 1829 while arcname[0:1] == "/":1830 arcname = arcname[1:]1835 arcname = arcname.replace(os.sep, "/") 1836 arcname = arcname.lstrip("/") 1831 1837 1832 1838 # Now, fill the TarInfo object with … … 1881 1887 tarinfo.uid = statres.st_uid 1882 1888 tarinfo.gid = statres.st_gid 1883 if stat.S_ISREG(stmd):1889 if type == REGTYPE: 1884 1890 tarinfo.size = statres.st_size 1885 1891 else: … … 1934 1940 print 1935 1941 1936 def add(self, name, arcname=None, recursive=True, exclude=None ):1942 def add(self, name, arcname=None, recursive=True, exclude=None, filter=None): 1937 1943 """Add the file `name' to the archive. `name' may be any type of file 1938 1944 (directory, fifo, symbolic link, etc.). If given, `arcname' … … 1940 1946 Directories are added recursively by default. This can be avoided by 1941 1947 setting `recursive' to False. `exclude' is a function that should 1942 return True for each filename to be excluded. 1948 return True for each filename to be excluded. `filter' is a function 1949 that expects a TarInfo object argument and returns the changed 1950 TarInfo object, if it returns None the TarInfo object will be 1951 excluded from the archive. 1943 1952 """ 1944 1953 self._check("aw") … … 1948 1957 1949 1958 # Exclude pathnames. 1950 if exclude is not None and exclude(name): 1951 self._dbg(2, "tarfile: Excluded %r" % name) 1952 return 1959 if exclude is not None: 1960 import warnings 1961 warnings.warn("use the filter argument instead", 1962 DeprecationWarning, 2) 1963 if exclude(name): 1964 self._dbg(2, "tarfile: Excluded %r" % name) 1965 return 1953 1966 1954 1967 # Skip if somebody tries to archive the archive... … … 1957 1970 return 1958 1971 1959 # Special case: The user wants to add the current1960 # working directory.1961 if name == ".":1962 if recursive:1963 if arcname == ".":1964 arcname = ""1965 for f in os.listdir(name):1966 self.add(f, os.path.join(arcname, f), recursive, exclude)1967 return1968 1969 1972 self._dbg(1, name) 1970 1973 … … 1976 1979 return 1977 1980 1981 # Change or exclude the TarInfo object. 1982 if filter is not None: 1983 tarinfo = filter(tarinfo) 1984 if tarinfo is None: 1985 self._dbg(2, "tarfile: Excluded %r" % name) 1986 return 1987 1978 1988 # Append the tar header and data to the archive. 1979 1989 if tarinfo.isreg(): 1980 f = bltn_open(name, "rb") 1981 self.addfile(tarinfo, f) 1982 f.close() 1990 with bltn_open(name, "rb") as f: 1991 self.addfile(tarinfo, f) 1983 1992 1984 1993 elif tarinfo.isdir(): … … 1986 1995 if recursive: 1987 1996 for f in os.listdir(name): 1988 self.add(os.path.join(name, f), os.path.join(arcname, f), recursive, exclude) 1997 self.add(os.path.join(name, f), os.path.join(arcname, f), 1998 recursive, exclude, filter) 1989 1999 1990 2000 else: … … 2119 2129 else: 2120 2130 # A (sym)link's file object is its target's file object. 2121 return self.extractfile(self._getmember(tarinfo.linkname, 2122 tarinfo)) 2131 return self.extractfile(self._find_link_target(tarinfo)) 2123 2132 else: 2124 2133 # If there's no data associated with the member (directory, chrdev, … … 2133 2142 # and build the destination pathname, replacing 2134 2143 # forward slashes to platform specific separators. 2135 if targetpath[-1:] == "/": 2136 targetpath = targetpath[:-1] 2137 targetpath = os.path.normpath(targetpath) 2144 targetpath = targetpath.rstrip("/") 2145 targetpath = targetpath.replace("/", os.sep) 2138 2146 2139 2147 # Create all upper directories. … … 2189 2197 """ 2190 2198 source = self.extractfile(tarinfo) 2191 target = bltn_open(targetpath, "wb") 2192 copyfileobj(source, target) 2193 source.close() 2194 target.close() 2199 try: 2200 with bltn_open(targetpath, "wb") as target: 2201 copyfileobj(source, target) 2202 finally: 2203 source.close() 2195 2204 2196 2205 def makeunknown(self, tarinfo, targetpath): … … 2230 2239 instead of a link. 2231 2240 """ 2232 linkpath = tarinfo.linkname2233 try:2241 if hasattr(os, "symlink") and hasattr(os, "link"): 2242 # For systems that support symbolic and hard links. 2234 2243 if tarinfo.issym(): 2235 os.symlink(linkpath, targetpath) 2244 if os.path.lexists(targetpath): 2245 os.unlink(targetpath) 2246 os.symlink(tarinfo.linkname, targetpath) 2236 2247 else: 2237 2248 # See extract(). 2238 os.link(tarinfo._link_target, targetpath)2239 except AttributeError:2240 if tarinfo.issym():2241 linkpath = os.path.join(os.path.dirname(tarinfo.name),2242 linkpath)2243 linkpath = normpath(linkpath)2244 2249 if os.path.exists(tarinfo._link_target): 2250 if os.path.lexists(targetpath): 2251 os.unlink(targetpath) 2252 os.link(tarinfo._link_target, targetpath) 2253 else: 2254 self._extract_member(self._find_link_target(tarinfo), targetpath) 2255 else: 2245 2256 try: 2246 self._extract_member(self.getmember(linkpath), targetpath) 2247 except (EnvironmentError, KeyError), e: 2248 linkpath = os.path.normpath(linkpath) 2249 try: 2250 shutil.copy2(linkpath, targetpath) 2251 except EnvironmentError, e: 2252 raise IOError("link could not be created") 2257 self._extract_member(self._find_link_target(tarinfo), targetpath) 2258 except KeyError: 2259 raise ExtractError("unable to resolve link inside archive") 2253 2260 2254 2261 def chown(self, tarinfo, targetpath): … … 2260 2267 g = grp.getgrnam(tarinfo.gname)[2] 2261 2268 except KeyError: 2262 try: 2263 g = grp.getgrgid(tarinfo.gid)[2] 2264 except KeyError: 2265 g = os.getgid() 2269 g = tarinfo.gid 2266 2270 try: 2267 2271 u = pwd.getpwnam(tarinfo.uname)[2] 2268 2272 except KeyError: 2269 try: 2270 u = pwd.getpwuid(tarinfo.uid)[2] 2271 except KeyError: 2272 u = os.getuid() 2273 u = tarinfo.uid 2273 2274 try: 2274 2275 if tarinfo.issym() and hasattr(os, "lchown"): … … 2313 2314 # Read the next block. 2314 2315 self.fileobj.seek(self.offset) 2316 tarinfo = None 2315 2317 while True: 2316 2318 try: 2317 2319 tarinfo = self.tarinfo.fromtarfile(self) 2318 if tarinfo is None: 2319 return 2320 self.members.append(tarinfo) 2321 2322 except HeaderError, e: 2320 except EOFHeaderError, e: 2323 2321 if self.ignore_zeros: 2324 2322 self._dbg(2, "0x%X: %s" % (self.offset, e)) 2325 2323 self.offset += BLOCKSIZE 2326 2324 continue 2327 else: 2328 if self.offset == 0: 2329 raise ReadError(str(e)) 2330 return None 2325 except InvalidHeaderError, e: 2326 if self.ignore_zeros: 2327 self._dbg(2, "0x%X: %s" % (self.offset, e)) 2328 self.offset += BLOCKSIZE 2329 continue 2330 elif self.offset == 0: 2331 raise ReadError(str(e)) 2332 except EmptyHeaderError: 2333 if self.offset == 0: 2334 raise ReadError("empty file") 2335 except TruncatedHeaderError, e: 2336 if self.offset == 0: 2337 raise ReadError(str(e)) 2338 except SubsequentHeaderError, e: 2339 raise ReadError(str(e)) 2331 2340 break 2341 2342 if tarinfo is not None: 2343 self.members.append(tarinfo) 2344 else: 2345 self._loaded = True 2332 2346 2333 2347 return tarinfo … … 2336 2350 # Little helper methods: 2337 2351 2338 def _getmember(self, name, tarinfo=None ):2352 def _getmember(self, name, tarinfo=None, normalize=False): 2339 2353 """Find an archive member by name from bottom to top. 2340 2354 If tarinfo is given, it is used as the starting point. … … 2343 2357 members = self.getmembers() 2344 2358 2345 if tarinfo is None: 2346 end = len(members) 2347 else: 2348 end = members.index(tarinfo) 2349 2350 for i in xrange(end - 1, -1, -1): 2351 if name == members[i].name: 2352 return members[i] 2359 # Limit the member search list up to tarinfo. 2360 if tarinfo is not None: 2361 members = members[:members.index(tarinfo)] 2362 2363 if normalize: 2364 name = os.path.normpath(name) 2365 2366 for member in reversed(members): 2367 if normalize: 2368 member_name = os.path.normpath(member.name) 2369 else: 2370 member_name = member.name 2371 2372 if name == member_name: 2373 return member 2353 2374 2354 2375 def _load(self): … … 2371 2392 raise IOError("bad operation for mode %r" % self.mode) 2372 2393 2394 def _find_link_target(self, tarinfo): 2395 """Find the target member of a symlink or hardlink member in the 2396 archive. 2397 """ 2398 if tarinfo.issym(): 2399 # Always search the entire archive. 2400 linkname = "/".join(filter(None, (os.path.dirname(tarinfo.name), tarinfo.linkname))) 2401 limit = None 2402 else: 2403 # Search the archive before the link, because a hard link is 2404 # just a reference to an already archived file. 2405 linkname = tarinfo.linkname 2406 limit = tarinfo 2407 2408 member = self._getmember(linkname, tarinfo=limit, normalize=True) 2409 if member is None: 2410 raise KeyError("linkname %r not found" % linkname) 2411 return member 2412 2373 2413 def __iter__(self): 2374 2414 """Provide an iterator object. … … 2384 2424 if level <= self.debug: 2385 2425 print >> sys.stderr, msg 2426 2427 def __enter__(self): 2428 self._check() 2429 return self 2430 2431 def __exit__(self, type, value, traceback): 2432 if type is None: 2433 self.close() 2434 else: 2435 # An exception occurred. We must not call close() because 2436 # it would try to write end-of-archive blocks and padding. 2437 if not self._extfileobj: 2438 self.fileobj.close() 2439 self.closed = True 2386 2440 # class TarFile 2387 2441 … … 2409 2463 # happen that getmembers() is called during iteration, 2410 2464 # which will cause TarIter to stop prematurely. 2411 if not self.tarfile._loaded: 2465 2466 if self.index == 0 and self.tarfile.firstmember is not None: 2467 tarinfo = self.tarfile.next() 2468 elif self.index < len(self.tarfile.members): 2469 tarinfo = self.tarfile.members[self.index] 2470 elif not self.tarfile._loaded: 2412 2471 tarinfo = self.tarfile.next() 2413 2472 if not tarinfo: … … 2415 2474 raise StopIteration 2416 2475 else: 2417 try: 2418 tarinfo = self.tarfile.members[self.index] 2419 except IndexError: 2420 raise StopIteration 2476 raise StopIteration 2421 2477 self.index += 1 2422 2478 return tarinfo
Note:
See TracChangeset
for help on using the changeset viewer.