python shutil_Python shutil模块

1 classTarFile(object):2 """The TarFile Class provides an interface to tar archives.3 """

4

5 debug = 0 #May be set from 0 (no msgs) to 3 (all msgs)

6

7 dereference = False #If true, add content of linked file to the

8 #tar file, else the link.

9

10 ignore_zeros = False #If true, skips empty or invalid blocks and

11 #continues processing.

12

13 errorlevel = 1 #If 0, fatal errors only appear in debug

14 #messages (if debug >= 0). If > 0, errors

15 #are passed to the caller as exceptions.

16

17 format = DEFAULT_FORMAT #The format to use when creating an archive.

18

19 encoding = ENCODING #Encoding for 8-bit character strings.

20

21 errors = None #Error handler for unicode conversion.

22

23 tarinfo = TarInfo #The default TarInfo class to use.

24

25 fileobject = ExFileObject #The default ExFileObject class to use.

26

27 def __init__(self, name=None, mode="r", fileobj=None, format=None,28 tarinfo=None, dereference=None, ignore_zeros=None, encoding=None,29 errors=None, pax_headers=None, debug=None, errorlevel=None):30 """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to31 read from an existing archive, 'a' to append data to an existing32 file or 'w' to create a new file overwriting an existing one. `mode'33 defaults to 'r'.34 If `fileobj' is given, it is used for reading or writing data. If it35 can be determined, `mode' is overridden by `fileobj's mode.36 `fileobj' is not closed, when TarFile is closed.37 """

38 modes = {"r": "rb", "a": "r+b", "w": "wb"}39 if mode not inmodes:40 raise ValueError("mode must be 'r', 'a' or 'w'")41 self.mode =mode42 self._mode =modes[mode]43

44 if notfileobj:45 if self.mode == "a" and notos.path.exists(name):46 #Create nonexistent files in append mode.

47 self.mode = "w"

48 self._mode = "wb"

49 fileobj =bltn_open(name, self._mode)50 self._extfileobj =False51 else:52 if name is None and hasattr(fileobj, "name"):53 name =fileobj.name54 if hasattr(fileobj, "mode"):55 self._mode =fileobj.mode56 self._extfileobj =True57 self.name = os.path.abspath(name) if name elseNone58 self.fileobj =fileobj59

60 #Init attributes.

61 if format is notNone:62 self.format =format63 if tarinfo is notNone:64 self.tarinfo =tarinfo65 if dereference is notNone:66 self.dereference =dereference67 if ignore_zeros is notNone:68 self.ignore_zeros =ignore_zeros69 if encoding is notNone:70 self.encoding =encoding71

72 if errors is notNone:73 self.errors =errors74 elif mode == "r":75 self.errors = "utf-8"

76 else:77 self.errors = "strict"

78

79 if pax_headers is not None and self.format ==PAX_FORMAT:80 self.pax_headers =pax_headers81 else:82 self.pax_headers ={}83

84 if debug is notNone:85 self.debug =debug86 if errorlevel is notNone:87 self.errorlevel =errorlevel88

89 #Init datastructures.

90 self.closed =False91 self.members = [] #list of members as TarInfo objects

92 self._loaded = False #flag if all members have been read

93 self.offset =self.fileobj.tell()94 #current position in the archive file

95 self.inodes = {} #dictionary caching the inodes of

96 #archive members already added

97

98 try:99 if self.mode == "r":100 self.firstmember =None101 self.firstmember =self.next()102

103 if self.mode == "a":104 #Move to the end of the archive,

105 #before the first empty block.

106 whileTrue:107 self.fileobj.seek(self.offset)108 try:109 tarinfo =self.tarinfo.fromtarfile(self)110 self.members.append(tarinfo)111 exceptEOFHeaderError:112 self.fileobj.seek(self.offset)113 break

114 exceptHeaderError, e:115 raiseReadError(str(e))116

117 if self.mode in "aw":118 self._loaded =True119

120 ifself.pax_headers:121 buf =self.tarinfo.create_pax_global_header(self.pax_headers.copy())122 self.fileobj.write(buf)123 self.offset +=len(buf)124 except:125 if notself._extfileobj:126 self.fileobj.close()127 self.closed =True128 raise

129

130 def_getposix(self):131 return self.format ==USTAR_FORMAT132 def_setposix(self, value):133 importwarnings134 warnings.warn("use the format attribute instead", DeprecationWarning,135 2)136 ifvalue:137 self.format =USTAR_FORMAT138 else:139 self.format =GNU_FORMAT140 posix =property(_getposix, _setposix)141

142 #--------------------------------------------------------------------------

143 #Below are the classmethods which act as alternate constructors to the

144 #TarFile class. The open() method is the only one that is needed for

145 #public use; it is the "super"-constructor and is able to select an

146 #adequate "sub"-constructor for a particular compression using the mapping

147 #from OPEN_METH.

148 #149 #This concept allows one to subclass TarFile without losing the comfort of

150 #the super-constructor. A sub-constructor is registered and made available

151 #by adding it to the mapping in OPEN_METH.

152

153 @classmethod154 def open(cls, name=None, mode="r", fileobj=None, bufsize=RECORDSIZE, **kwargs):155 """Open a tar archive for reading, writing or appending. Return156 an appropriate TarFile class.157

158 mode:159 'r' or 'r:*' open for reading with transparent compression160 'r:' open for reading exclusively uncompressed161 'r:gz' open for reading with gzip compression162 'r:bz2' open for reading with bzip2 compression163 'a' or 'a:' open for appending, creating the file if necessary164 'w' or 'w:' open for writing without compression165 'w:gz' open for writing with gzip compression166 'w:bz2' open for writing with bzip2 compression167

168 'r|*' open a stream of tar blocks with transparent compression169 'r|' open an uncompressed stream of tar blocks for reading170 'r|gz' open a gzip compressed stream of tar blocks171 'r|bz2' open a bzip2 compressed stream of tar blocks172 'w|' open an uncompressed stream for writing173 'w|gz' open a gzip compressed stream for writing174 'w|bz2' open a bzip2 compressed stream for writing175 """

176

177 if not name and notfileobj:178 raise ValueError("nothing to open")179

180 if mode in ("r", "r:*"):181 #Find out which *open() is appropriate for opening the file.

182 for comptype incls.OPEN_METH:183 func =getattr(cls, cls.OPEN_METH[comptype])184 if fileobj is notNone:185 saved_pos =fileobj.tell()186 try:187 return func(name, "r", fileobj, **kwargs)188 except(ReadError, CompressionError), e:189 if fileobj is notNone:190 fileobj.seek(saved_pos)191 continue

192 raise ReadError("file could not be opened successfully")193

194 elif ":" inmode:195 filemode, comptype = mode.split(":", 1)196 filemode = filemode or "r"

197 comptype = comptype or "tar"

198

199 #Select the *open() function according to

200 #given compression.

201 if comptype incls.OPEN_METH:202 func =getattr(cls, cls.OPEN_METH[comptype])203 else:204 raise CompressionError("unknown compression type %r" %comptype)205 return func(name, filemode, fileobj, **kwargs)206

207 elif "|" inmode:208 filemode, comptype = mode.split("|", 1)209 filemode = filemode or "r"

210 comptype = comptype or "tar"

211

212 if filemode not in ("r", "w"):213 raise ValueError("mode must be 'r' or 'w'")214

215 stream =_Stream(name, filemode, comptype, fileobj, bufsize)216 try:217 t = cls(name, filemode, stream, **kwargs)218 except:219 stream.close()220 raise

221 t._extfileobj =False222 returnt223

224 elif mode in ("a", "w"):225 return cls.taropen(name, mode, fileobj, **kwargs)226

227 raise ValueError("undiscernible mode")228

229 @classmethod230 def taropen(cls, name, mode="r", fileobj=None, **kwargs):231 """Open uncompressed tar archive name for reading or writing.232 """

233 if mode not in ("r", "a", "w"):234 raise ValueError("mode must be 'r', 'a' or 'w'")235 return cls(name, mode, fileobj, **kwargs)236

237 @classmethod238 def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs):239 """Open gzip compressed tar archive name for reading or writing.240 Appending is not allowed.241 """

242 if mode not in ("r", "w"):243 raise ValueError("mode must be 'r' or 'w'")244

245 try:246 importgzip247 gzip.GzipFile248 except(ImportError, AttributeError):249 raise CompressionError("gzip module is not available")250

251 try:252 fileobj =gzip.GzipFile(name, mode, compresslevel, fileobj)253 exceptOSError:254 if fileobj is not None and mode == 'r':255 raise ReadError("not a gzip file")256 raise

257

258 try:259 t = cls.taropen(name, mode, fileobj, **kwargs)260 exceptIOError:261 fileobj.close()262 if mode == 'r':263 raise ReadError("not a gzip file")264 raise

265 except:266 fileobj.close()267 raise

268 t._extfileobj =False269 returnt270

271 @classmethod272 def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs):273 """Open bzip2 compressed tar archive name for reading or writing.274 Appending is not allowed.275 """

276 if mode not in ("r", "w"):277 raise ValueError("mode must be 'r' or 'w'.")278

279 try:280 importbz2281 exceptImportError:282 raise CompressionError("bz2 module is not available")283

284 if fileobj is notNone:285 fileobj =_BZ2Proxy(fileobj, mode)286 else:287 fileobj = bz2.BZ2File(name, mode, compresslevel=compresslevel)288

289 try:290 t = cls.taropen(name, mode, fileobj, **kwargs)291 except(IOError, EOFError):292 fileobj.close()293 if mode == 'r':294 raise ReadError("not a bzip2 file")295 raise

296 except:297 fileobj.close()298 raise

299 t._extfileobj =False300 returnt301

302 #All *open() methods are registered here.

303 OPEN_METH ={304 "tar": "taropen", #uncompressed tar

305 "gz": "gzopen", #gzip compressed tar

306 "bz2": "bz2open" #bzip2 compressed tar

307 }308

309 #--------------------------------------------------------------------------

310 #The public methods which TarFile provides:

311

312 defclose(self):313 """Close the TarFile. In write-mode, two finishing zero blocks are314 appended to the archive.315 """

316 ifself.closed:317 return

318

319 if self.mode in "aw":320 self.fileobj.write(NUL * (BLOCKSIZE * 2))321 self.offset += (BLOCKSIZE * 2)322 #fill up the end with zero-blocks

323 #(like option -b20 for tar does)

324 blocks, remainder =divmod(self.offset, RECORDSIZE)325 if remainder >0:326 self.fileobj.write(NUL * (RECORDSIZE -remainder))327

328 if notself._extfileobj:329 self.fileobj.close()330 self.closed =True331

332 defgetmember(self, name):333 """Return a TarInfo object for member `name'. If `name' can not be334 found in the archive, KeyError is raised. If a member occurs more335 than once in the archive, its last occurrence is assumed to be the336 most up-to-date version.337 """

338 tarinfo =self._getmember(name)339 if tarinfo isNone:340 raise KeyError("filename %r not found" %name)341 returntarinfo342

343 defgetmembers(self):344 """Return the members of the archive as a list of TarInfo objects. The345 list has the same order as the members in the archive.346 """

347 self._check()348 if not self._loaded: #if we want to obtain a list of

349 self._load() #all members, we first have to

350 #scan the whole archive.

351 returnself.members352

353 defgetnames(self):354 """Return the members of the archive as a list of their names. It has355 the same order as the list returned by getmembers().356 """

357 return [tarinfo.name for tarinfo inself.getmembers()]358

359 def gettarinfo(self, name=None, arcname=None, fileobj=None):360 """Create a TarInfo object for either the file `name' or the file361 object `fileobj' (using os.fstat on its file descriptor). You can362 modify some of the TarInfo's attributes before you add it using363 addfile(). If given, `arcname' specifies an alternative name for the364 file in the archive.365 """

366 self._check("aw")367

368 #When fileobj is given, replace name by

369 #fileobj's real name.

370 if fileobj is notNone:371 name =fileobj.name372

373 #Building the name of the member in the archive.

374 #Backward slashes are converted to forward slashes,

375 #Absolute paths are turned to relative paths.

376 if arcname isNone:377 arcname =name378 drv, arcname =os.path.splitdrive(arcname)379 arcname = arcname.replace(os.sep, "/")380 arcname = arcname.lstrip("/")381

382 #Now, fill the TarInfo object with

383 #information specific for the file.

384 tarinfo =self.tarinfo()385 tarinfo.tarfile =self386

387 #Use os.stat or os.lstat, depending on platform

388 #and if symlinks shall be resolved.

389 if fileobj isNone:390 if hasattr(os, "lstat") and notself.dereference:391 statres =os.lstat(name)392 else:393 statres =os.stat(name)394 else:395 statres =os.fstat(fileobj.fileno())396 linkname = ""

397

398 stmd =statres.st_mode399 ifstat.S_ISREG(stmd):400 inode =(statres.st_ino, statres.st_dev)401 if not self.dereference and statres.st_nlink > 1 and\402 inode in self.inodes and arcname !=self.inodes[inode]:403 #Is it a hardlink to an already

404 #archived file?

405 type =LNKTYPE406 linkname =self.inodes[inode]407 else:408 #The inode is added only if its valid.

409 #For win32 it is always 0.

410 type =REGTYPE411 ifinode[0]:412 self.inodes[inode] =arcname413 elifstat.S_ISDIR(stmd):414 type =DIRTYPE415 elifstat.S_ISFIFO(stmd):416 type =FIFOTYPE417 elifstat.S_ISLNK(stmd):418 type =SYMTYPE419 linkname =os.readlink(name)420 elifstat.S_ISCHR(stmd):421 type =CHRTYPE422 elifstat.S_ISBLK(stmd):423 type =BLKTYPE424 else:425 returnNone426

427 #Fill the TarInfo object with all

428 #information we can get.

429 tarinfo.name =arcname430 tarinfo.mode =stmd431 tarinfo.uid =statres.st_uid432 tarinfo.gid =statres.st_gid433 if type ==REGTYPE:434 tarinfo.size =statres.st_size435 else:436 tarinfo.size =0L437 tarinfo.mtime =statres.st_mtime438 tarinfo.type =type439 tarinfo.linkname =linkname440 ifpwd:441 try:442 tarinfo.uname =pwd.getpwuid(tarinfo.uid)[0]443 exceptKeyError:444 pass

445 ifgrp:446 try:447 tarinfo.gname =grp.getgrgid(tarinfo.gid)[0]448 exceptKeyError:449 pass

450

451 if type in(CHRTYPE, BLKTYPE):452 if hasattr(os, "major") and hasattr(os, "minor"):453 tarinfo.devmajor =os.major(statres.st_rdev)454 tarinfo.devminor =os.minor(statres.st_rdev)455 returntarinfo456

457 def list(self, verbose=True):458 """Print a table of contents to sys.stdout. If `verbose' is False, only459 the names of the members are printed. If it is True, an `ls -l'-like460 output is produced.461 """

462 self._check()463

464 for tarinfo inself:465 ifverbose:466 printfilemode(tarinfo.mode),467 print "%s/%s" % (tarinfo.uname ortarinfo.uid,468 tarinfo.gname ortarinfo.gid),469 if tarinfo.ischr() ortarinfo.isblk():470 print "%10s" % ("%d,%d"\471 %(tarinfo.devmajor, tarinfo.devminor)),472 else:473 print "%10d" %tarinfo.size,474 print "%d-%02d-%02d %02d:%02d:%02d"\475 % time.localtime(tarinfo.mtime)[:6],476

477 print tarinfo.name + ("/" if tarinfo.isdir() else ""),478

479 ifverbose:480 iftarinfo.issym():481 print "->", tarinfo.linkname,482 iftarinfo.islnk():483 print "link to", tarinfo.linkname,484 print

485

486 def add(self, name, arcname=None, recursive=True, exclude=None, filter=None):487 """Add the file `name' to the archive. `name' may be any type of file488 (directory, fifo, symbolic link, etc.). If given, `arcname'489 specifies an alternative name for the file in the archive.490 Directories are added recursively by default. This can be avoided by491 setting `recursive' to False. `exclude' is a function that should492 return True for each filename to be excluded. `filter' is a function493 that expects a TarInfo object argument and returns the changed494 TarInfo object, if it returns None the TarInfo object will be495 excluded from the archive.496 """

497 self._check("aw")498

499 if arcname isNone:500 arcname =name501

502 #Exclude pathnames.

503 if exclude is notNone:504 importwarnings505 warnings.warn("use the filter argument instead",506 DeprecationWarning, 2)507 ifexclude(name):508 self._dbg(2, "tarfile: Excluded %r" %name)509 return

510

511 #Skip if somebody tries to archive the archive...

512 if self.name is not None and os.path.abspath(name) ==self.name:513 self._dbg(2, "tarfile: Skipped %r" %name)514 return

515

516 self._dbg(1, name)517

518 #Create a TarInfo object from the file.

519 tarinfo =self.gettarinfo(name, arcname)520

521 if tarinfo isNone:522 self._dbg(1, "tarfile: Unsupported type %r" %name)523 return

524

525 #Change or exclude the TarInfo object.

526 if filter is notNone:527 tarinfo =filter(tarinfo)528 if tarinfo isNone:529 self._dbg(2, "tarfile: Excluded %r" %name)530 return

531

532 #Append the tar header and data to the archive.

533 iftarinfo.isreg():534 with bltn_open(name, "rb") as f:535 self.addfile(tarinfo, f)536

537 eliftarinfo.isdir():538 self.addfile(tarinfo)539 ifrecursive:540 for f inos.listdir(name):541 self.add(os.path.join(name, f), os.path.join(arcname, f),542 recursive, exclude, filter)543

544 else:545 self.addfile(tarinfo)546

547 def addfile(self, tarinfo, fileobj=None):548 """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is549 given, tarinfo.size bytes are read from it and added to the archive.550 You can create TarInfo objects using gettarinfo().551 On Windows platforms, `fileobj' should always be opened with mode552 'rb' to avoid irritation about the file size.553 """

554 self._check("aw")555

556 tarinfo =copy.copy(tarinfo)557

558 buf =tarinfo.tobuf(self.format, self.encoding, self.errors)559 self.fileobj.write(buf)560 self.offset +=len(buf)561

562 #If there's data to follow, append it.

563 if fileobj is notNone:564 copyfileobj(fileobj, self.fileobj, tarinfo.size)565 blocks, remainder =divmod(tarinfo.size, BLOCKSIZE)566 if remainder >0:567 self.fileobj.write(NUL * (BLOCKSIZE -remainder))568 blocks += 1

569 self.offset += blocks *BLOCKSIZE570

571 self.members.append(tarinfo)572

573 def extractall(self, path=".", members=None):574 """Extract all members from the archive to the current working575 directory and set owner, modification time and permissions on576 directories afterwards. `path' specifies a different directory577 to extract to. `members' is optional and must be a subset of the578 list returned by getmembers().579 """

580 directories =[]581

582 if members isNone:583 members =self584

585 for tarinfo inmembers:586 iftarinfo.isdir():587 #Extract directories with a safe mode.

588 directories.append(tarinfo)589 tarinfo =copy.copy(tarinfo)590 tarinfo.mode = 0700

591 self.extract(tarinfo, path)592

593 #Reverse sort directories.

594 directories.sort(key=operator.attrgetter('name'))595 directories.reverse()596

597 #Set correct owner, mtime and filemode on directories.

598 for tarinfo indirectories:599 dirpath =os.path.join(path, tarinfo.name)600 try:601 self.chown(tarinfo, dirpath)602 self.utime(tarinfo, dirpath)603 self.chmod(tarinfo, dirpath)604 exceptExtractError, e:605 if self.errorlevel > 1:606 raise

607 else:608 self._dbg(1, "tarfile: %s" %e)609

610 def extract(self, member, path=""):611 """Extract a member from the archive to the current working directory,612 using its full name. Its file information is extracted as accurately613 as possible. `member' may be a filename or a TarInfo object. You can614 specify a different directory using `path'.615 """

616 self._check("r")617

618 ifisinstance(member, basestring):619 tarinfo =self.getmember(member)620 else:621 tarinfo =member622

623 #Prepare the link target for makelink().

624 iftarinfo.islnk():625 tarinfo._link_target =os.path.join(path, tarinfo.linkname)626

627 try:628 self._extract_member(tarinfo, os.path.join(path, tarinfo.name))629 exceptEnvironmentError, e:630 if self.errorlevel >0:631 raise

632 else:633 if e.filename isNone:634 self._dbg(1, "tarfile: %s" %e.strerror)635 else:636 self._dbg(1, "tarfile: %s %r" %(e.strerror, e.filename))637 exceptExtractError, e:638 if self.errorlevel > 1:639 raise

640 else:641 self._dbg(1, "tarfile: %s" %e)642

643 defextractfile(self, member):644 """Extract a member from the archive as a file object. `member' may be645 a filename or a TarInfo object. If `member' is a regular file, a646 file-like object is returned. If `member' is a link, a file-like647 object is constructed from the link's target. If `member' is none of648 the above, None is returned.649 The file-like object is read-only and provides the following650 methods: read(), readline(), readlines(), seek() and tell()651 """

652 self._check("r")653

654 ifisinstance(member, basestring):655 tarinfo =self.getmember(member)656 else:657 tarinfo =member658

659 iftarinfo.isreg():660 returnself.fileobject(self, tarinfo)661

662 elif tarinfo.type not inSUPPORTED_TYPES:663 #If a member's type is unknown, it is treated as a

664 #regular file.

665 returnself.fileobject(self, tarinfo)666

667 elif tarinfo.islnk() ortarinfo.issym():668 ifisinstance(self.fileobj, _Stream):669 #A small but ugly workaround for the case that someone tries

670 #to extract a (sym)link as a file-object from a non-seekable

671 #stream of tar blocks.

672 raise StreamError("cannot extract (sym)link as file object")673 else:674 #A (sym)link's file object is its target's file object.

675 returnself.extractfile(self._find_link_target(tarinfo))676 else:677 #If there's no data associated with the member (directory, chrdev,

678 #blkdev, etc.), return None instead of a file object.

679 returnNone680

681 def_extract_member(self, tarinfo, targetpath):682 """Extract the TarInfo object tarinfo to a physical683 file called targetpath.684 """

685 #Fetch the TarInfo object for the given name

686 #and build the destination pathname, replacing

687 #forward slashes to platform specific separators.

688 targetpath = targetpath.rstrip("/")689 targetpath = targetpath.replace("/", os.sep)690

691 #Create all upper directories.

692 upperdirs =os.path.dirname(targetpath)693 if upperdirs and notos.path.exists(upperdirs):694 #Create directories that are not part of the archive with

695 #default permissions.

696 os.makedirs(upperdirs)697

698 if tarinfo.islnk() ortarinfo.issym():699 self._dbg(1, "%s -> %s" %(tarinfo.name, tarinfo.linkname))700 else:701 self._dbg(1, tarinfo.name)702

703 iftarinfo.isreg():704 self.makefile(tarinfo, targetpath)705 eliftarinfo.isdir():706 self.makedir(tarinfo, targetpath)707 eliftarinfo.isfifo():708 self.makefifo(tarinfo, targetpath)709 elif tarinfo.ischr() ortarinfo.isblk():710 self.makedev(tarinfo, targetpath)711 elif tarinfo.islnk() ortarinfo.issym():712 self.makelink(tarinfo, targetpath)713 elif tarinfo.type not inSUPPORTED_TYPES:714 self.makeunknown(tarinfo, targetpath)715 else:716 self.makefile(tarinfo, targetpath)717

718 self.chown(tarinfo, targetpath)719 if nottarinfo.issym():720 self.chmod(tarinfo, targetpath)721 self.utime(tarinfo, targetpath)722

723 #--------------------------------------------------------------------------

724 #Below are the different file methods. They are called via

725 #_extract_member() when extract() is called. They can be replaced in a

726 #subclass to implement other functionality.

727

728 defmakedir(self, tarinfo, targetpath):729 """Make a directory called targetpath.730 """

731 try:732 #Use a safe mode for the directory, the real mode is set

733 #later in _extract_member().

734 os.mkdir(targetpath, 0700)735 exceptEnvironmentError, e:736 if e.errno !=errno.EEXIST:737 raise

738

739 defmakefile(self, tarinfo, targetpath):740 """Make a file called targetpath.741 """

742 source =self.extractfile(tarinfo)743 try:744 with bltn_open(targetpath, "wb") as target:745 copyfileobj(source, target)746 finally:747 source.close()748

749 defmakeunknown(self, tarinfo, targetpath):750 """Make a file from a TarInfo object with an unknown type751 at targetpath.752 """

753 self.makefile(tarinfo, targetpath)754 self._dbg(1, "tarfile: Unknown file type %r,"\755 "extracted as regular file." %tarinfo.type)756

757 defmakefifo(self, tarinfo, targetpath):758 """Make a fifo called targetpath.759 """

760 if hasattr(os, "mkfifo"):761 os.mkfifo(targetpath)762 else:763 raise ExtractError("fifo not supported by system")764

765 defmakedev(self, tarinfo, targetpath):766 """Make a character or block device called targetpath.767 """

768 if not hasattr(os, "mknod") or not hasattr(os, "makedev"):769 raise ExtractError("special devices not supported by system")770

771 mode =tarinfo.mode772 iftarinfo.isblk():773 mode |=stat.S_IFBLK774 else:775 mode |=stat.S_IFCHR776

777 os.mknod(targetpath, mode,778 os.makedev(tarinfo.devmajor, tarinfo.devminor))779

780 defmakelink(self, tarinfo, targetpath):781 """Make a (symbolic) link called targetpath. If it cannot be created782 (platform limitation), we try to make a copy of the referenced file783 instead of a link.784 """

785 if hasattr(os, "symlink") and hasattr(os, "link"):786 #For systems that support symbolic and hard links.

787 iftarinfo.issym():788 ifos.path.lexists(targetpath):789 os.unlink(targetpath)790 os.symlink(tarinfo.linkname, targetpath)791 else:792 #See extract().

793 ifos.path.exists(tarinfo._link_target):794 ifos.path.lexists(targetpath):795 os.unlink(targetpath)796 os.link(tarinfo._link_target, targetpath)797 else:798 self._extract_member(self._find_link_target(tarinfo), targetpath)799 else:800 try:801 self._extract_member(self._find_link_target(tarinfo), targetpath)802 exceptKeyError:803 raise ExtractError("unable to resolve link inside archive")804

805 defchown(self, tarinfo, targetpath):806 """Set owner of targetpath according to tarinfo.807 """

808 if pwd and hasattr(os, "geteuid") and os.geteuid() ==0:809 #We have to be root to do so.

810 try:811 g = grp.getgrnam(tarinfo.gname)[2]812 exceptKeyError:813 g =tarinfo.gid814 try:815 u = pwd.getpwnam(tarinfo.uname)[2]816 exceptKeyError:817 u =tarinfo.uid818 try:819 if tarinfo.issym() and hasattr(os, "lchown"):820 os.lchown(targetpath, u, g)821 else:822 if sys.platform != "os2emx":823 os.chown(targetpath, u, g)824 exceptEnvironmentError, e:825 raise ExtractError("could not change owner")826

827 defchmod(self, tarinfo, targetpath):828 """Set file permissions of targetpath according to tarinfo.829 """

830 if hasattr(os, 'chmod'):831 try:832 os.chmod(targetpath, tarinfo.mode)833 exceptEnvironmentError, e:834 raise ExtractError("could not change mode")835

836 defutime(self, tarinfo, targetpath):837 """Set modification time of targetpath according to tarinfo.838 """

839 if not hasattr(os, 'utime'):840 return

841 try:842 os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime))843 exceptEnvironmentError, e:844 raise ExtractError("could not change modification time")845

846 #--------------------------------------------------------------------------

847 defnext(self):848 """Return the next member of the archive as a TarInfo object, when849 TarFile is opened for reading. Return None if there is no more850 available.851 """

852 self._check("ra")853 if self.firstmember is notNone:854 m =self.firstmember855 self.firstmember =None856 returnm857

858 #Read the next block.

859 self.fileobj.seek(self.offset)860 tarinfo =None861 whileTrue:862 try:863 tarinfo =self.tarinfo.fromtarfile(self)864 exceptEOFHeaderError, e:865 ifself.ignore_zeros:866 self._dbg(2, "0x%X: %s" %(self.offset, e))867 self.offset +=BLOCKSIZE868 continue

869 exceptInvalidHeaderError, e:870 ifself.ignore_zeros:871 self._dbg(2, "0x%X: %s" %(self.offset, e))872 self.offset +=BLOCKSIZE873 continue

874 elif self.offset ==0:875 raiseReadError(str(e))876 exceptEmptyHeaderError:877 if self.offset ==0:878 raise ReadError("empty file")879 exceptTruncatedHeaderError, e:880 if self.offset ==0:881 raiseReadError(str(e))882 exceptSubsequentHeaderError, e:883 raiseReadError(str(e))884 break

885

886 if tarinfo is notNone:887 self.members.append(tarinfo)888 else:889 self._loaded =True890

891 returntarinfo892

893 #--------------------------------------------------------------------------

894 #Little helper methods:

895

896 def _getmember(self, name, tarinfo=None, normalize=False):897 """Find an archive member by name from bottom to top.898 If tarinfo is given, it is used as the starting point.899 """

900 #Ensure that all members have been loaded.

901 members =self.getmembers()902

903 #Limit the member search list up to tarinfo.

904 if tarinfo is notNone:905 members =members[:members.index(tarinfo)]906

907 ifnormalize:908 name =os.path.normpath(name)909

910 for member inreversed(members):911 ifnormalize:912 member_name =os.path.normpath(member.name)913 else:914 member_name =member.name915

916 if name ==member_name:917 returnmember918

919 def_load(self):920 """Read through the entire archive file and look for readable921 members.922 """

923 whileTrue:924 tarinfo =self.next()925 if tarinfo isNone:926 break

927 self._loaded =True928

929 def _check(self, mode=None):930 """Check if TarFile is still open, and if the operation's mode931 corresponds to TarFile's mode.932 """

933 ifself.closed:934 raise IOError("%s is closed" % self.__class__.__name__)935 if mode is not None and self.mode not inmode:936 raise IOError("bad operation for mode %r" %self.mode)937

938 def_find_link_target(self, tarinfo):939 """Find the target member of a symlink or hardlink member in the940 archive.941 """

942 iftarinfo.issym():943 #Always search the entire archive.

944 linkname = "/".join(filter(None, (os.path.dirname(tarinfo.name), tarinfo.linkname)))945 limit =None946 else:947 #Search the archive before the link, because a hard link is

948 #just a reference to an already archived file.

949 linkname =tarinfo.linkname950 limit =tarinfo951

952 member = self._getmember(linkname, tarinfo=limit, normalize=True)953 if member isNone:954 raise KeyError("linkname %r not found" %linkname)955 returnmember956

957 def __iter__(self):958 """Provide an iterator object.959 """

960 ifself._loaded:961 returniter(self.members)962 else:963 returnTarIter(self)964

965 def_dbg(self, level, msg):966 """Write debugging output to sys.stderr.967 """

968 if level <=self.debug:969 print >>sys.stderr, msg970

971 def __enter__(self):972 self._check()973 returnself974

975 def __exit__(self, type, value, traceback):976 if type isNone:977 self.close()978 else:979 #An exception occurred. We must not call close() because

980 #it would try to write end-of-archive blocks and padding.

981 if notself._extfileobj:982 self.fileobj.close()983 self.closed =True984 #class TarFile

985

986 TarFile

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值