SILENT KILLERPanel

Current Path: > > opt > alt > python27 > lib64 > > > python2.7


Operation   : Linux premium131.web-hosting.com 4.18.0-553.44.1.lve.el8.x86_64 #1 SMP Thu Mar 13 14:29:12 UTC 2025 x86_64
Software     : Apache
Server IP    : 162.0.232.56 | Your IP: 216.73.216.111
Domains      : 1034 Domain(s)
Permission   : [ 0755 ]

Files and Folders in: //opt/alt/python27/lib64///python2.7

NameTypeSizeLast ModifiedActions
bsddb Directory - -
compiler Directory - -
config Directory - -
ctypes Directory - -
curses Directory - -
distutils Directory - -
email Directory - -
encodings Directory - -
ensurepip Directory - -
hotshot Directory - -
idlelib Directory - -
importlib Directory - -
json Directory - -
lib-dynload Directory - -
lib2to3 Directory - -
logging Directory - -
multiprocessing Directory - -
plat-linux2 Directory - -
pydoc_data Directory - -
site-packages Directory - -
sqlite3 Directory - -
test Directory - -
unittest Directory - -
wsgiref Directory - -
xml Directory - -
BaseHTTPServer.py File 22747 bytes January 08 2025 10:43:40.
BaseHTTPServer.pyc File 21982 bytes January 08 2025 10:43:03.
BaseHTTPServer.pyo File 21982 bytes January 08 2025 10:43:03.
Bastion.py File 5744 bytes January 08 2025 10:43:11.
Bastion.pyc File 6855 bytes January 08 2025 10:42:51.
Bastion.pyo File 6855 bytes January 08 2025 10:42:51.
CGIHTTPServer.py File 13089 bytes January 08 2025 10:43:27.
CGIHTTPServer.pyc File 11187 bytes January 08 2025 10:43:39.
CGIHTTPServer.pyo File 11187 bytes January 08 2025 10:43:39.
ConfigParser.py File 27746 bytes January 08 2025 10:43:11.
ConfigParser.pyc File 25980 bytes January 08 2025 10:43:11.
ConfigParser.pyo File 25980 bytes January 08 2025 10:43:11.
Cookie.py File 26538 bytes January 08 2025 10:43:04.
Cookie.pyc File 23152 bytes January 08 2025 10:43:41.
Cookie.pyo File 23152 bytes January 08 2025 10:43:41.
DocXMLRPCServer.py File 10768 bytes January 08 2025 10:43:11.
DocXMLRPCServer.pyc File 10442 bytes January 08 2025 10:43:35.
DocXMLRPCServer.pyo File 10333 bytes January 08 2025 10:43:08.
HTMLParser.py File 17171 bytes January 08 2025 10:42:55.
HTMLParser.pyc File 14143 bytes January 08 2025 10:42:55.
HTMLParser.pyo File 13838 bytes January 08 2025 10:43:35.
MimeWriter.py File 6482 bytes January 08 2025 10:42:52.
MimeWriter.pyc File 7481 bytes January 08 2025 10:43:04.
MimeWriter.pyo File 7481 bytes January 08 2025 10:43:04.
Queue.py File 8577 bytes January 08 2025 10:43:11.
Queue.pyc File 9788 bytes January 08 2025 10:43:04.
Queue.pyo File 9788 bytes January 08 2025 10:43:04.
SimpleHTTPServer.py File 7997 bytes January 08 2025 10:43:03.
SimpleHTTPServer.pyc File 8153 bytes January 08 2025 10:42:51.
SimpleHTTPServer.pyo File 8153 bytes January 08 2025 10:42:51.
SimpleXMLRPCServer.py File 25812 bytes January 08 2025 10:43:42.
SimpleXMLRPCServer.pyc File 23331 bytes January 08 2025 10:43:05.
SimpleXMLRPCServer.pyo File 23331 bytes January 08 2025 10:43:05.
SocketServer.py File 23948 bytes January 08 2025 10:43:28.
SocketServer.pyc File 24828 bytes January 08 2025 10:43:04.
SocketServer.pyo File 24828 bytes January 08 2025 10:43:04.
StringIO.py File 10662 bytes January 08 2025 10:43:31.
StringIO.pyc File 11727 bytes January 08 2025 10:43:39.
StringIO.pyo File 11727 bytes January 08 2025 10:43:39.
UserDict.py File 7060 bytes January 08 2025 10:43:04.
UserDict.pyc File 10296 bytes January 21 2025 11:47:01.
UserDict.pyo File 10296 bytes January 08 2025 10:43:04.
UserList.py File 3644 bytes January 08 2025 10:43:35.
UserList.pyc File 7019 bytes January 08 2025 10:43:31.
UserList.pyo File 7019 bytes January 08 2025 10:43:31.
UserString.py File 9697 bytes January 08 2025 10:43:35.
UserString.pyc File 15748 bytes January 08 2025 10:43:27.
UserString.pyo File 15748 bytes January 08 2025 10:43:27.
_LWPCookieJar.py File 6553 bytes January 08 2025 10:43:41.
_LWPCookieJar.pyc File 5512 bytes January 08 2025 10:43:11.
_LWPCookieJar.pyo File 5512 bytes January 08 2025 10:43:11.
_MozillaCookieJar.py File 5797 bytes January 08 2025 10:42:58.
_MozillaCookieJar.pyc File 4513 bytes January 08 2025 10:43:04.
_MozillaCookieJar.pyo File 4474 bytes January 08 2025 10:43:35.
__future__.py File 4380 bytes January 08 2025 10:43:39.
__future__.pyc File 4301 bytes January 08 2025 10:43:03.
__future__.pyo File 4301 bytes January 08 2025 10:43:03.
__phello__.foo.py File 64 bytes January 08 2025 10:43:35.
__phello__.foo.pyc File 138 bytes January 08 2025 10:43:05.
__phello__.foo.pyo File 138 bytes January 08 2025 10:43:05.
_abcoll.py File 18619 bytes January 08 2025 10:43:11.
_abcoll.pyc File 27034 bytes January 21 2025 11:47:01.
_abcoll.pyo File 27034 bytes January 08 2025 10:43:35.
_osx_support.py File 19100 bytes January 08 2025 10:43:35.
_osx_support.pyc File 12005 bytes January 08 2025 10:43:04.
_osx_support.pyo File 12005 bytes January 08 2025 10:43:04.
_pyio.py File 69630 bytes January 08 2025 10:43:11.
_pyio.pyc File 66976 bytes January 08 2025 10:43:38.
_pyio.pyo File 66976 bytes January 08 2025 10:43:38.
_strptime.py File 20728 bytes January 08 2025 10:43:38.
_strptime.pyc File 15432 bytes January 08 2025 10:43:35.
_strptime.pyo File 15432 bytes January 08 2025 10:43:35.
_sysconfigdata.py File 21163 bytes January 08 2025 10:43:35.
_sysconfigdata.pyc File 24277 bytes January 21 2025 11:47:01.
_sysconfigdata.pyo File 24277 bytes January 08 2025 10:42:56.
_threading_local.py File 7260 bytes January 08 2025 10:43:03.
_threading_local.pyc File 6490 bytes January 08 2025 10:43:11.
_threading_local.pyo File 6490 bytes January 08 2025 10:43:11.
_weakrefset.py File 5911 bytes January 08 2025 10:42:58.
_weakrefset.pyc File 10302 bytes January 21 2025 11:47:01.
_weakrefset.pyo File 10302 bytes January 08 2025 10:43:40.
abc.py File 7145 bytes January 08 2025 10:43:03.
abc.pyc File 6286 bytes January 21 2025 11:47:01.
abc.pyo File 6230 bytes January 08 2025 10:43:04.
aifc.py File 34579 bytes January 08 2025 10:43:39.
aifc.pyc File 31408 bytes January 08 2025 10:43:42.
aifc.pyo File 31408 bytes January 08 2025 10:43:42.
antigravity.py File 60 bytes January 08 2025 10:43:05.
antigravity.pyc File 216 bytes January 08 2025 10:42:55.
antigravity.pyo File 216 bytes January 08 2025 10:42:55.
anydbm.py File 2663 bytes January 08 2025 10:42:56.
anydbm.pyc File 2839 bytes January 08 2025 10:42:51.
anydbm.pyo File 2839 bytes January 08 2025 10:42:51.
argparse.py File 89228 bytes January 08 2025 10:43:35.
argparse.pyc File 66382 bytes January 08 2025 10:43:01.
argparse.pyo File 66217 bytes January 08 2025 10:43:11.
ast.py File 11805 bytes January 08 2025 10:43:35.
ast.pyc File 13250 bytes January 08 2025 10:42:56.
ast.pyo File 13250 bytes January 08 2025 10:42:56.
asynchat.py File 11581 bytes January 08 2025 10:43:27.
asynchat.pyc File 9200 bytes January 08 2025 10:43:01.
asynchat.pyo File 9200 bytes January 08 2025 10:43:01.
asyncore.py File 20943 bytes January 08 2025 10:43:40.
asyncore.pyc File 19660 bytes January 08 2025 10:43:00.
asyncore.pyo File 19660 bytes January 08 2025 10:43:00.
atexit.py File 1705 bytes January 08 2025 10:43:35.
atexit.pyc File 2281 bytes January 08 2025 10:42:55.
atexit.pyo File 2281 bytes January 08 2025 10:42:55.
audiodev.py File 7597 bytes January 08 2025 10:43:35.
audiodev.pyc File 8820 bytes January 08 2025 10:43:42.
audiodev.pyo File 8820 bytes January 08 2025 10:43:42.
base64.py File 11816 bytes January 08 2025 10:43:08.
base64.pyc File 11531 bytes January 08 2025 10:43:41.
base64.pyo File 11531 bytes January 08 2025 10:43:41.
bdb.py File 21714 bytes January 08 2025 10:43:27.
bdb.pyc File 19894 bytes January 08 2025 10:43:08.
bdb.pyo File 19894 bytes January 08 2025 10:43:08.
binhex.py File 14698 bytes January 08 2025 10:43:03.
binhex.pyc File 16123 bytes January 08 2025 10:43:11.
binhex.pyo File 16123 bytes January 08 2025 10:43:11.
bisect.py File 2595 bytes January 08 2025 10:42:51.
bisect.pyc File 3136 bytes January 08 2025 10:43:27.
bisect.pyo File 3136 bytes January 08 2025 10:43:27.
cProfile.py File 6583 bytes January 08 2025 10:42:56.
cProfile.pyc File 6577 bytes January 08 2025 10:42:56.
cProfile.pyo File 6577 bytes January 08 2025 10:42:56.
calendar.py File 23384 bytes January 08 2025 10:43:31.
calendar.pyc File 28940 bytes January 08 2025 10:43:35.
calendar.pyo File 28940 bytes January 08 2025 10:43:35.
cgi.py File 35807 bytes January 08 2025 10:43:35.
cgi.pyc File 34034 bytes January 08 2025 10:43:00.
cgi.pyo File 34034 bytes January 08 2025 10:43:00.
cgitb.py File 12175 bytes January 08 2025 10:43:40.
cgitb.pyc File 12372 bytes January 08 2025 10:43:35.
cgitb.pyo File 12372 bytes January 08 2025 10:43:35.
chunk.py File 5419 bytes January 08 2025 10:43:11.
chunk.pyc File 5745 bytes January 08 2025 10:43:41.
chunk.pyo File 5745 bytes January 08 2025 10:43:41.
cmd.py File 15026 bytes January 08 2025 10:42:55.
cmd.pyc File 14312 bytes January 08 2025 10:43:35.
cmd.pyo File 14312 bytes January 08 2025 10:43:35.
code.py File 10189 bytes January 08 2025 10:43:05.
code.pyc File 10542 bytes January 08 2025 10:43:27.
code.pyo File 10542 bytes January 08 2025 10:43:27.
codecs.py File 36143 bytes January 08 2025 10:43:04.
codecs.pyc File 38046 bytes January 21 2025 11:47:01.
codecs.pyo File 38046 bytes January 08 2025 10:42:56.
codeop.py File 5999 bytes January 08 2025 10:42:59.
codeop.pyc File 6727 bytes January 08 2025 10:43:04.
codeop.pyo File 6727 bytes January 08 2025 10:43:04.
collections.py File 27798 bytes January 08 2025 10:43:04.
collections.pyc File 26839 bytes January 08 2025 10:43:35.
collections.pyo File 26788 bytes January 08 2025 10:43:03.
colorsys.py File 3691 bytes January 08 2025 10:43:03.
colorsys.pyc File 4095 bytes January 08 2025 10:43:09.
colorsys.pyo File 4095 bytes January 08 2025 10:43:09.
commands.py File 2545 bytes January 08 2025 10:42:58.
commands.pyc File 2547 bytes January 08 2025 10:43:00.
commands.pyo File 2547 bytes January 08 2025 10:43:00.
compileall.py File 7763 bytes January 08 2025 10:42:59.
compileall.pyc File 7095 bytes January 08 2025 10:43:35.
compileall.pyo File 7095 bytes January 08 2025 10:43:35.
contextlib.py File 4424 bytes January 08 2025 10:42:59.
contextlib.pyc File 4610 bytes January 08 2025 10:43:35.
contextlib.pyo File 4610 bytes January 08 2025 10:43:35.
cookielib.py File 65486 bytes January 08 2025 10:43:05.
cookielib.pyc File 55986 bytes January 08 2025 10:43:39.
cookielib.pyo File 55798 bytes January 08 2025 10:43:27.
copy.py File 11533 bytes January 08 2025 10:43:03.
copy.pyc File 12508 bytes January 08 2025 10:43:35.
copy.pyo File 12416 bytes January 08 2025 10:43:27.
copy_reg.py File 6974 bytes January 08 2025 10:43:11.
copy_reg.pyc File 5310 bytes January 21 2025 11:47:01.
copy_reg.pyo File 5266 bytes January 08 2025 10:43:35.
crypt.py File 2291 bytes January 08 2025 10:43:03.
crypt.pyc File 3025 bytes January 08 2025 10:43:00.
crypt.pyo File 3025 bytes January 08 2025 10:43:00.
csv.py File 16708 bytes January 08 2025 10:43:04.
csv.pyc File 13884 bytes January 08 2025 10:43:27.
csv.pyo File 13884 bytes January 08 2025 10:43:27.
dbhash.py File 498 bytes January 08 2025 10:42:55.
dbhash.pyc File 744 bytes January 08 2025 10:43:03.
dbhash.pyo File 744 bytes January 08 2025 10:43:03.
decimal.py File 221933 bytes January 08 2025 10:43:28.
decimal.pyc File 175470 bytes January 08 2025 10:42:55.
decimal.pyo File 175470 bytes January 08 2025 10:42:55.
difflib.py File 82325 bytes January 08 2025 10:43:08.
difflib.pyc File 62600 bytes January 08 2025 10:43:05.
difflib.pyo File 62549 bytes January 08 2025 10:43:41.
dircache.py File 1126 bytes January 08 2025 10:42:55.
dircache.pyc File 1628 bytes January 08 2025 10:43:08.
dircache.pyo File 1628 bytes January 08 2025 10:43:08.
dis.py File 6499 bytes January 08 2025 10:43:04.
dis.pyc File 6332 bytes January 08 2025 10:43:31.
dis.pyo File 6332 bytes January 08 2025 10:43:31.
doctest.py File 105095 bytes January 08 2025 10:43:04.
doctest.pyc File 85210 bytes January 08 2025 10:43:03.
doctest.pyo File 84923 bytes January 08 2025 10:42:56.
dumbdbm.py File 9141 bytes January 08 2025 10:43:04.
dumbdbm.pyc File 6993 bytes January 08 2025 10:43:39.
dumbdbm.pyo File 6993 bytes January 08 2025 10:43:39.
dummy_thread.py File 4418 bytes January 08 2025 10:43:05.
dummy_thread.pyc File 5589 bytes January 08 2025 10:43:05.
dummy_thread.pyo File 5589 bytes January 08 2025 10:43:05.
dummy_threading.py File 2804 bytes January 08 2025 10:43:03.
dummy_threading.pyc File 1298 bytes January 08 2025 10:43:39.
dummy_threading.pyo File 1298 bytes January 08 2025 10:43:39.
filecmp.py File 9588 bytes January 08 2025 10:43:03.
filecmp.pyc File 9882 bytes January 08 2025 10:43:28.
filecmp.pyo File 9882 bytes January 08 2025 10:43:28.
fileinput.py File 13746 bytes January 08 2025 10:43:08.
fileinput.pyc File 14890 bytes January 08 2025 10:43:35.
fileinput.pyo File 14890 bytes January 08 2025 10:43:35.
fnmatch.py File 3315 bytes January 08 2025 10:43:03.
fnmatch.pyc File 3692 bytes January 08 2025 10:43:00.
fnmatch.pyo File 3692 bytes January 08 2025 10:43:00.
formatter.py File 14911 bytes January 08 2025 10:43:04.
formatter.pyc File 20179 bytes January 08 2025 10:43:03.
formatter.pyo File 20179 bytes January 08 2025 10:43:03.
fpformat.py File 4732 bytes January 08 2025 10:43:28.
fpformat.pyc File 4807 bytes January 08 2025 10:43:11.
fpformat.pyo File 4807 bytes January 08 2025 10:43:11.
fractions.py File 22390 bytes January 08 2025 10:42:56.
fractions.pyc File 20218 bytes January 08 2025 10:43:00.
fractions.pyo File 20218 bytes January 08 2025 10:43:00.
ftplib.py File 38194 bytes January 08 2025 10:43:03.
ftplib.pyc File 35652 bytes January 08 2025 10:42:56.
ftplib.pyo File 35652 bytes January 08 2025 10:42:56.
functools.py File 4806 bytes January 08 2025 10:43:42.
functools.pyc File 7019 bytes January 08 2025 10:43:05.
functools.pyo File 7019 bytes January 08 2025 10:43:05.
genericpath.py File 3201 bytes January 08 2025 10:43:41.
genericpath.pyc File 3660 bytes January 21 2025 11:47:01.
genericpath.pyo File 3660 bytes January 08 2025 10:43:35.
getopt.py File 7319 bytes January 08 2025 10:43:35.
getopt.pyc File 6784 bytes January 08 2025 10:43:35.
getopt.pyo File 6739 bytes January 08 2025 10:43:40.
getpass.py File 5563 bytes January 08 2025 10:42:56.
getpass.pyc File 4835 bytes January 08 2025 10:43:35.
getpass.pyo File 4835 bytes January 08 2025 10:43:35.
gettext.py File 22666 bytes January 08 2025 10:43:35.
gettext.pyc File 18602 bytes January 08 2025 10:43:42.
gettext.pyo File 18602 bytes January 08 2025 10:43:42.
glob.py File 3114 bytes January 08 2025 10:42:59.
glob.pyc File 3047 bytes January 08 2025 10:43:03.
glob.pyo File 3047 bytes January 08 2025 10:43:03.
gzip.py File 19028 bytes January 08 2025 10:43:35.
gzip.pyc File 15626 bytes January 08 2025 10:43:04.
gzip.pyo File 15626 bytes January 08 2025 10:43:04.
hashlib.py File 7842 bytes January 08 2025 10:43:39.
hashlib.pyc File 7026 bytes January 08 2025 10:43:39.
hashlib.pyo File 7026 bytes January 08 2025 10:43:39.
heapq.py File 18295 bytes January 08 2025 10:42:52.
heapq.pyc File 14798 bytes January 08 2025 10:43:04.
heapq.pyo File 14798 bytes January 08 2025 10:43:04.
hmac.py File 4588 bytes January 08 2025 10:43:11.
hmac.pyc File 4672 bytes January 08 2025 10:43:35.
hmac.pyo File 4672 bytes January 08 2025 10:43:35.
htmlentitydefs.py File 18056 bytes January 08 2025 10:43:04.
htmlentitydefs.pyc File 6380 bytes January 08 2025 10:43:04.
htmlentitydefs.pyo File 6380 bytes January 08 2025 10:43:04.
htmllib.py File 12869 bytes January 08 2025 10:43:08.
htmllib.pyc File 21492 bytes January 08 2025 10:42:59.
htmllib.pyo File 21492 bytes January 08 2025 10:42:59.
httplib.py File 52300 bytes January 08 2025 10:43:35.
httplib.pyc File 38793 bytes January 08 2025 10:43:11.
httplib.pyo File 38609 bytes January 08 2025 10:43:40.
ihooks.py File 18986 bytes January 08 2025 10:43:11.
ihooks.pyc File 22269 bytes January 08 2025 10:43:04.
ihooks.pyo File 22269 bytes January 08 2025 10:43:04.
imaplib.py File 48366 bytes January 08 2025 10:43:34.
imaplib.pyc File 46272 bytes January 08 2025 10:43:03.
imaplib.pyo File 43506 bytes January 08 2025 10:43:04.
imghdr.py File 3541 bytes January 08 2025 10:43:35.
imghdr.pyc File 5046 bytes January 08 2025 10:43:05.
imghdr.pyo File 5046 bytes January 08 2025 10:43:05.
imputil.py File 25764 bytes January 08 2025 10:43:03.
imputil.pyc File 16117 bytes January 08 2025 10:43:28.
imputil.pyo File 15939 bytes January 08 2025 10:43:31.
inspect.py File 43008 bytes January 08 2025 10:43:27.
inspect.pyc File 41126 bytes January 08 2025 10:43:31.
inspect.pyo File 41126 bytes January 08 2025 10:43:31.
io.py File 3322 bytes January 08 2025 10:43:04.
io.pyc File 3654 bytes January 08 2025 10:43:00.
io.pyo File 3654 bytes January 08 2025 10:43:00.
keyword.py File 2005 bytes January 08 2025 10:43:35.
keyword.pyc File 2131 bytes January 08 2025 10:43:42.
keyword.pyo File 2131 bytes January 08 2025 10:43:42.
linecache.py File 4027 bytes January 08 2025 10:43:05.
linecache.pyc File 3350 bytes January 21 2025 11:47:01.
linecache.pyo File 3350 bytes January 08 2025 10:42:55.
locale.py File 102834 bytes January 08 2025 10:43:27.
locale.pyc File 57026 bytes January 08 2025 10:42:51.
locale.pyo File 57026 bytes January 08 2025 10:42:51.
macpath.py File 6289 bytes January 08 2025 10:43:04.
macpath.pyc File 7928 bytes January 08 2025 10:43:03.
macpath.pyo File 7928 bytes January 08 2025 10:43:03.
macurl2path.py File 2731 bytes January 08 2025 10:43:03.
macurl2path.pyc File 2296 bytes January 08 2025 10:43:27.
macurl2path.pyo File 2296 bytes January 08 2025 10:43:27.
mailbox.py File 81240 bytes January 08 2025 10:43:27.
mailbox.pyc File 79564 bytes January 08 2025 10:43:35.
mailbox.pyo File 79517 bytes January 08 2025 10:43:03.
mailcap.py File 7429 bytes January 08 2025 10:42:56.
mailcap.pyc File 7248 bytes January 08 2025 10:43:08.
mailcap.pyo File 7248 bytes January 08 2025 10:43:08.
markupbase.py File 14643 bytes January 08 2025 10:43:40.
markupbase.pyc File 9488 bytes January 08 2025 10:43:38.
markupbase.pyo File 9292 bytes January 08 2025 10:42:55.
md5.py File 358 bytes January 08 2025 10:43:40.
md5.pyc File 391 bytes January 08 2025 10:43:03.
md5.pyo File 391 bytes January 08 2025 10:43:03.
mhlib.py File 33434 bytes January 08 2025 10:43:28.
mhlib.pyc File 34791 bytes January 08 2025 10:43:28.
mhlib.pyo File 34791 bytes January 08 2025 10:43:28.
mimetools.py File 7168 bytes January 08 2025 10:43:11.
mimetools.pyc File 8461 bytes January 08 2025 10:43:39.
mimetools.pyo File 8461 bytes January 08 2025 10:43:39.
mimetypes.py File 21028 bytes January 08 2025 10:43:27.
mimetypes.pyc File 18736 bytes January 08 2025 10:43:35.
mimetypes.pyo File 18736 bytes January 08 2025 10:43:35.
mimify.py File 15030 bytes January 08 2025 10:43:05.
mimify.pyc File 12196 bytes January 08 2025 10:43:27.
mimify.pyo File 12196 bytes January 08 2025 10:43:27.
modulefinder.py File 24461 bytes January 08 2025 10:43:03.
modulefinder.pyc File 19582 bytes January 08 2025 10:42:56.
modulefinder.pyo File 19500 bytes January 08 2025 10:42:55.
multifile.py File 4820 bytes January 08 2025 10:43:27.
multifile.pyc File 5615 bytes January 08 2025 10:43:31.
multifile.pyo File 5573 bytes January 08 2025 10:42:52.
mutex.py File 1878 bytes January 08 2025 10:43:01.
mutex.pyc File 2607 bytes January 08 2025 10:43:27.
mutex.pyo File 2607 bytes January 08 2025 10:43:27.
netrc.py File 5888 bytes January 08 2025 10:43:11.
netrc.pyc File 4831 bytes January 08 2025 10:43:27.
netrc.pyo File 4831 bytes January 08 2025 10:43:27.
new.py File 610 bytes January 08 2025 10:43:35.
new.pyc File 875 bytes January 08 2025 10:42:58.
new.pyo File 875 bytes January 08 2025 10:42:58.
nntplib.py File 21470 bytes January 08 2025 10:42:55.
nntplib.pyc File 21616 bytes January 08 2025 10:43:31.
nntplib.pyo File 21616 bytes January 08 2025 10:43:31.
ntpath.py File 19429 bytes January 08 2025 10:42:58.
ntpath.pyc File 13415 bytes January 08 2025 10:43:11.
ntpath.pyo File 13415 bytes January 08 2025 10:43:11.
nturl2path.py File 2419 bytes January 08 2025 10:43:35.
nturl2path.pyc File 1854 bytes January 08 2025 10:43:04.
nturl2path.pyo File 1854 bytes January 08 2025 10:43:04.
numbers.py File 10319 bytes January 08 2025 10:43:39.
numbers.pyc File 14818 bytes January 08 2025 10:43:05.
numbers.pyo File 14818 bytes January 08 2025 10:43:05.
opcode.py File 5474 bytes January 08 2025 10:43:41.
opcode.pyc File 6210 bytes January 08 2025 10:42:56.
opcode.pyo File 6210 bytes January 08 2025 10:42:56.
optparse.py File 61203 bytes January 08 2025 10:43:35.
optparse.pyc File 55714 bytes January 08 2025 10:43:35.
optparse.pyo File 55631 bytes January 08 2025 10:43:39.
os.py File 25910 bytes January 08 2025 10:43:00.
os.pyc File 26378 bytes January 21 2025 11:47:01.
os.pyo File 26378 bytes January 08 2025 10:43:31.
os2emxpath.py File 4635 bytes January 08 2025 10:43:04.
os2emxpath.pyc File 4642 bytes January 08 2025 10:43:42.
os2emxpath.pyo File 4642 bytes January 08 2025 10:43:42.
pdb.doc File 7914 bytes January 08 2025 10:43:03.
pdb.py File 46108 bytes January 08 2025 10:43:05.
pdb.pyc File 45151 bytes January 08 2025 10:43:39.
pdb.pyo File 45151 bytes January 08 2025 10:43:39.
pickle.py File 45489 bytes January 08 2025 10:43:11.
pickle.pyc File 39912 bytes January 08 2025 10:43:39.
pickle.pyo File 39716 bytes January 08 2025 10:43:27.
pickletools.py File 74523 bytes January 08 2025 10:43:03.
pickletools.pyc File 57448 bytes January 08 2025 10:43:31.
pickletools.pyo File 56587 bytes January 08 2025 10:42:59.
pipes.py File 9582 bytes January 08 2025 10:43:35.
pipes.pyc File 9516 bytes January 08 2025 10:43:35.
pipes.pyo File 9516 bytes January 08 2025 10:43:35.
pkgutil.py File 20243 bytes January 08 2025 10:43:04.
pkgutil.pyc File 19388 bytes January 08 2025 10:43:04.
pkgutil.pyo File 19388 bytes January 08 2025 10:43:04.
platform.py File 52798 bytes January 08 2025 10:43:04.
platform.pyc File 38602 bytes January 08 2025 10:43:05.
platform.pyo File 38602 bytes January 08 2025 10:43:05.
plistlib.py File 15185 bytes January 08 2025 10:42:51.
plistlib.pyc File 20008 bytes January 08 2025 10:43:35.
plistlib.pyo File 19922 bytes January 08 2025 10:43:11.
popen2.py File 8416 bytes January 08 2025 10:43:39.
popen2.pyc File 9233 bytes January 08 2025 10:43:35.
popen2.pyo File 9191 bytes January 08 2025 10:43:03.
poplib.py File 12824 bytes January 08 2025 10:42:55.
poplib.pyc File 13774 bytes January 08 2025 10:43:04.
poplib.pyo File 13774 bytes January 08 2025 10:43:04.
posixfile.py File 8003 bytes January 08 2025 10:43:11.
posixfile.pyc File 7808 bytes January 08 2025 10:42:59.
posixfile.pyo File 7808 bytes January 08 2025 10:42:59.
posixpath.py File 14293 bytes January 08 2025 10:43:05.
posixpath.pyc File 11761 bytes January 21 2025 11:47:01.
posixpath.pyo File 11761 bytes January 08 2025 10:43:35.
pprint.py File 11777 bytes January 08 2025 10:43:04.
pprint.pyc File 10441 bytes January 08 2025 10:43:28.
pprint.pyo File 10264 bytes January 08 2025 10:43:27.
profile.py File 22791 bytes January 08 2025 10:43:09.
profile.pyc File 16963 bytes January 08 2025 10:43:38.
profile.pyo File 16716 bytes January 08 2025 10:43:09.
pstats.py File 26712 bytes January 08 2025 10:43:01.
pstats.pyc File 25793 bytes January 08 2025 10:42:55.
pstats.pyo File 25793 bytes January 08 2025 10:42:55.
pty.py File 5058 bytes January 08 2025 10:42:55.
pty.pyc File 5096 bytes January 08 2025 10:43:38.
pty.pyo File 5096 bytes January 08 2025 10:43:38.
py_compile.py File 5936 bytes January 08 2025 10:43:28.
py_compile.pyc File 6519 bytes January 08 2025 10:42:55.
py_compile.pyo File 6519 bytes January 08 2025 10:42:55.
pyclbr.py File 13388 bytes January 08 2025 10:42:51.
pyclbr.pyc File 9820 bytes January 08 2025 10:43:39.
pyclbr.pyo File 9820 bytes January 08 2025 10:43:39.
pydoc.py File 95676 bytes January 08 2025 10:43:04.
pydoc.pyc File 94914 bytes January 08 2025 10:43:04.
pydoc.pyo File 94850 bytes January 08 2025 10:43:37.
quopri.py File 6978 bytes January 08 2025 10:43:35.
quopri.pyc File 6717 bytes January 08 2025 10:43:11.
quopri.pyo File 6717 bytes January 08 2025 10:43:11.
random.py File 32457 bytes January 08 2025 10:42:55.
random.pyc File 26263 bytes January 08 2025 10:43:03.
random.pyo File 26263 bytes January 08 2025 10:43:03.
re.py File 13423 bytes January 08 2025 10:43:06.
re.pyc File 13686 bytes January 21 2025 11:47:01.
re.pyo File 13686 bytes January 08 2025 10:43:27.
repr.py File 4296 bytes January 08 2025 10:43:42.
repr.pyc File 5606 bytes January 08 2025 10:43:08.
repr.pyo File 5606 bytes January 08 2025 10:43:08.
rexec.py File 20148 bytes January 08 2025 10:43:05.
rexec.pyc File 24574 bytes January 08 2025 10:43:27.
rexec.pyo File 24574 bytes January 08 2025 10:43:27.
rfc822.py File 33542 bytes January 08 2025 10:43:35.
rfc822.pyc File 32593 bytes January 08 2025 10:43:40.
rfc822.pyo File 32593 bytes January 08 2025 10:43:40.
rlcompleter.py File 5991 bytes January 08 2025 10:43:42.
rlcompleter.pyc File 6182 bytes January 08 2025 10:43:11.
rlcompleter.pyo File 6182 bytes January 08 2025 10:43:11.
robotparser.py File 7695 bytes January 08 2025 10:43:03.
robotparser.pyc File 8315 bytes January 08 2025 10:43:28.
robotparser.pyo File 8315 bytes January 08 2025 10:43:28.
runpy.py File 11081 bytes January 08 2025 10:42:55.
runpy.pyc File 9063 bytes January 08 2025 10:43:27.
runpy.pyo File 9063 bytes January 08 2025 10:43:27.
sched.py File 5088 bytes January 08 2025 10:43:28.
sched.pyc File 5111 bytes January 08 2025 10:42:56.
sched.pyo File 5111 bytes January 08 2025 10:42:56.
sets.py File 19050 bytes January 08 2025 10:43:40.
sets.pyc File 17623 bytes January 08 2025 10:43:05.
sets.pyo File 17623 bytes January 08 2025 10:43:05.
sgmllib.py File 17884 bytes January 08 2025 10:42:55.
sgmllib.pyc File 16047 bytes January 08 2025 10:42:59.
sgmllib.pyo File 16047 bytes January 08 2025 10:42:59.
sha.py File 393 bytes January 08 2025 10:43:27.
sha.pyc File 434 bytes January 08 2025 10:43:00.
sha.pyo File 434 bytes January 08 2025 10:43:00.
shelve.py File 8178 bytes January 08 2025 10:43:35.
shelve.pyc File 10607 bytes January 08 2025 10:43:35.
shelve.pyo File 10607 bytes January 08 2025 10:43:35.
shlex.py File 11164 bytes January 08 2025 10:43:39.
shlex.pyc File 7727 bytes January 08 2025 10:42:51.
shlex.pyo File 7727 bytes January 08 2025 10:42:51.
shutil.py File 19871 bytes January 08 2025 10:43:31.
shutil.pyc File 19649 bytes January 08 2025 10:43:27.
shutil.pyo File 19649 bytes January 08 2025 10:43:27.
site.py File 19637 bytes January 08 2025 10:43:27.
site.pyc File 19819 bytes January 21 2025 11:47:01.
site.pyo File 19819 bytes January 08 2025 10:43:27.
smtpd.py File 18552 bytes January 08 2025 10:43:05.
smtpd.pyc File 16286 bytes January 08 2025 10:43:11.
smtpd.pyo File 16286 bytes January 08 2025 10:43:11.
smtplib.py File 32144 bytes January 08 2025 10:43:03.
smtplib.pyc File 31019 bytes January 08 2025 10:42:59.
smtplib.pyo File 31019 bytes January 08 2025 10:42:59.
sndhdr.py File 5973 bytes January 08 2025 10:43:35.
sndhdr.pyc File 7582 bytes January 08 2025 10:43:34.
sndhdr.pyo File 7582 bytes January 08 2025 10:43:34.
socket.py File 20615 bytes January 08 2025 10:43:39.
socket.pyc File 16542 bytes January 08 2025 10:43:00.
socket.pyo File 16456 bytes January 08 2025 10:43:35.
sre.py File 384 bytes January 08 2025 10:42:59.
sre.pyc File 532 bytes January 08 2025 10:43:00.
sre.pyo File 532 bytes January 08 2025 10:43:00.
sre_compile.py File 19823 bytes January 08 2025 10:43:03.
sre_compile.pyc File 12755 bytes January 21 2025 11:47:01.
sre_compile.pyo File 12599 bytes January 08 2025 10:43:35.
sre_constants.py File 7197 bytes January 08 2025 10:43:00.
sre_constants.pyc File 6260 bytes January 21 2025 11:47:01.
sre_constants.pyo File 6260 bytes January 08 2025 10:43:04.
sre_parse.py File 30700 bytes January 08 2025 10:43:05.
sre_parse.pyc File 21624 bytes January 21 2025 11:47:01.
sre_parse.pyo File 21624 bytes January 08 2025 10:43:09.
ssl.py File 37455 bytes January 08 2025 10:43:27.
ssl.pyc File 33015 bytes January 08 2025 10:43:28.
ssl.pyo File 33015 bytes January 08 2025 10:43:28.
stat.py File 1842 bytes January 08 2025 10:43:28.
stat.pyc File 2881 bytes January 21 2025 11:47:01.
stat.pyo File 2881 bytes January 08 2025 10:43:11.
statvfs.py File 898 bytes January 08 2025 10:43:03.
statvfs.pyc File 633 bytes January 08 2025 10:43:05.
statvfs.pyo File 633 bytes January 08 2025 10:43:05.
string.py File 21548 bytes January 08 2025 10:43:35.
string.pyc File 21122 bytes January 08 2025 10:43:35.
string.pyo File 21122 bytes January 08 2025 10:43:35.
stringold.py File 12449 bytes January 08 2025 10:42:55.
stringold.pyc File 12900 bytes January 08 2025 10:42:55.
stringold.pyo File 12900 bytes January 08 2025 10:42:55.
stringprep.py File 13522 bytes January 08 2025 10:43:11.
stringprep.pyc File 14747 bytes January 08 2025 10:43:05.
stringprep.pyo File 14675 bytes January 08 2025 10:43:11.
struct.py File 82 bytes January 08 2025 10:43:05.
struct.pyc File 252 bytes January 08 2025 10:43:31.
struct.pyo File 252 bytes January 08 2025 10:43:31.
subprocess.py File 50520 bytes January 08 2025 10:42:56.
subprocess.pyc File 33100 bytes January 08 2025 10:43:11.
subprocess.pyo File 33100 bytes January 08 2025 10:43:11.
sunau.py File 17222 bytes January 08 2025 10:43:04.
sunau.pyc File 19018 bytes January 08 2025 10:43:35.
sunau.pyo File 19018 bytes January 08 2025 10:43:35.
sunaudio.py File 1399 bytes January 08 2025 10:43:40.
sunaudio.pyc File 2052 bytes January 08 2025 10:43:35.
sunaudio.pyo File 2052 bytes January 08 2025 10:43:35.
symbol.py File 2067 bytes January 08 2025 10:43:03.
symbol.pyc File 3052 bytes January 08 2025 10:42:55.
symbol.pyo File 3052 bytes January 08 2025 10:42:55.
symtable.py File 7437 bytes January 08 2025 10:43:35.
symtable.pyc File 12436 bytes January 08 2025 10:43:11.
symtable.pyo File 12305 bytes January 08 2025 10:42:55.
sysconfig.py File 22852 bytes January 08 2025 10:43:31.
sysconfig.pyc File 18156 bytes January 21 2025 11:47:01.
sysconfig.pyo File 18153 bytes January 08 2025 10:43:31.
tabnanny.py File 11349 bytes January 08 2025 10:43:35.
tabnanny.pyc File 8507 bytes January 08 2025 10:43:35.
tabnanny.pyo File 8507 bytes January 08 2025 10:43:35.
tarfile.py File 90568 bytes January 08 2025 10:43:04.
tarfile.pyc File 78374 bytes January 08 2025 10:43:35.
tarfile.pyo File 78374 bytes January 08 2025 10:43:35.
telnetlib.py File 27036 bytes January 08 2025 10:43:03.
telnetlib.pyc File 23583 bytes January 08 2025 10:43:38.
telnetlib.pyo File 23583 bytes January 08 2025 10:43:38.
tempfile.py File 19547 bytes January 08 2025 10:42:56.
tempfile.pyc File 21046 bytes January 08 2025 10:43:39.
tempfile.pyo File 21046 bytes January 08 2025 10:43:39.
textwrap.py File 17280 bytes January 08 2025 10:42:58.
textwrap.pyc File 12279 bytes January 08 2025 10:43:28.
textwrap.pyo File 12187 bytes January 08 2025 10:42:55.
this.py File 1002 bytes January 08 2025 10:43:11.
this.pyc File 1233 bytes January 08 2025 10:43:35.
this.pyo File 1233 bytes January 08 2025 10:43:35.
threading.py File 47282 bytes January 08 2025 10:43:27.
threading.pyc File 43999 bytes January 08 2025 10:43:04.
threading.pyo File 41825 bytes January 08 2025 10:42:59.
timeit.py File 12801 bytes January 08 2025 10:43:04.
timeit.pyc File 12352 bytes January 08 2025 10:43:31.
timeit.pyo File 12352 bytes January 08 2025 10:43:31.
toaiff.py File 3142 bytes January 08 2025 10:43:39.
toaiff.pyc File 3158 bytes January 08 2025 10:43:04.
toaiff.pyo File 3158 bytes January 08 2025 10:43:04.
token.py File 2922 bytes January 08 2025 10:42:59.
token.pyc File 3881 bytes January 08 2025 10:42:51.
token.pyo File 3881 bytes January 08 2025 10:42:51.
tokenize.py File 17483 bytes January 08 2025 10:43:31.
tokenize.pyc File 14713 bytes January 08 2025 10:43:41.
tokenize.pyo File 14657 bytes January 08 2025 10:42:59.
trace.py File 29901 bytes January 08 2025 10:42:55.
trace.pyc File 23235 bytes January 08 2025 10:43:03.
trace.pyo File 23172 bytes January 08 2025 10:43:31.
traceback.py File 11285 bytes January 08 2025 10:43:34.
traceback.pyc File 11939 bytes January 21 2025 11:47:01.
traceback.pyo File 11939 bytes January 08 2025 10:43:31.
tty.py File 879 bytes January 08 2025 10:42:55.
tty.pyc File 1356 bytes January 08 2025 10:42:56.
tty.pyo File 1356 bytes January 08 2025 10:42:56.
types.py File 2094 bytes January 08 2025 10:42:56.
types.pyc File 2816 bytes January 21 2025 11:47:01.
types.pyo File 2816 bytes January 08 2025 10:43:04.
urllib.py File 60228 bytes January 08 2025 10:43:03.
urllib.pyc File 52580 bytes January 08 2025 10:43:37.
urllib.pyo File 52485 bytes January 08 2025 10:43:09.
urllib2.py File 52537 bytes January 08 2025 10:43:35.
urllib2.pyc File 48949 bytes January 08 2025 10:43:34.
urllib2.pyo File 48854 bytes January 08 2025 10:43:27.
urlparse.py File 16678 bytes January 08 2025 10:43:11.
urlparse.pyc File 15886 bytes January 08 2025 10:43:08.
urlparse.pyo File 15886 bytes January 08 2025 10:43:08.
user.py File 1627 bytes January 08 2025 10:43:03.
user.pyc File 1737 bytes January 08 2025 10:43:03.
user.pyo File 1737 bytes January 08 2025 10:43:03.
uu.py File 6707 bytes January 08 2025 10:42:59.
uu.pyc File 4455 bytes January 08 2025 10:43:27.
uu.pyo File 4455 bytes January 08 2025 10:43:27.
uuid.py File 23175 bytes January 08 2025 10:43:04.
uuid.pyc File 23778 bytes January 08 2025 10:43:05.
uuid.pyo File 23662 bytes January 08 2025 10:42:56.
warnings.py File 14823 bytes January 08 2025 10:43:04.
warnings.pyc File 13809 bytes January 21 2025 11:47:01.
warnings.pyo File 13020 bytes January 08 2025 10:43:41.
wave.py File 18582 bytes January 08 2025 10:43:03.
wave.pyc File 20676 bytes January 08 2025 10:43:27.
wave.pyo File 20532 bytes January 08 2025 10:43:05.
weakref.py File 14830 bytes January 08 2025 10:43:28.
weakref.pyc File 17130 bytes January 08 2025 10:43:05.
weakref.pyo File 17130 bytes January 08 2025 10:43:05.
webbrowser.py File 22735 bytes January 08 2025 10:43:35.
webbrowser.pyc File 20335 bytes January 08 2025 10:42:55.
webbrowser.pyo File 20290 bytes January 08 2025 10:43:27.
whichdb.py File 3388 bytes January 08 2025 10:43:11.
whichdb.pyc File 2267 bytes January 08 2025 10:43:27.
whichdb.pyo File 2267 bytes January 08 2025 10:43:27.
wsgiref.egg-info File 187 bytes January 08 2025 10:42:51.
xdrlib.py File 6069 bytes January 08 2025 10:43:40.
xdrlib.pyc File 10448 bytes January 08 2025 10:43:38.
xdrlib.pyo File 10448 bytes January 08 2025 10:43:38.
xmllib.py File 34865 bytes January 08 2025 10:42:56.
xmllib.pyc File 27550 bytes January 08 2025 10:43:35.
xmllib.pyo File 27550 bytes January 08 2025 10:43:35.
xmlrpclib.py File 52136 bytes January 08 2025 10:43:31.
xmlrpclib.pyc File 45887 bytes January 08 2025 10:43:27.
xmlrpclib.pyo File 45703 bytes January 08 2025 10:43:04.
zipfile.py File 59477 bytes January 08 2025 10:43:40.
zipfile.pyc File 42930 bytes January 08 2025 10:43:34.
zipfile.pyo File 42930 bytes January 08 2025 10:43:34.

Reading File: //opt/alt/python27/lib64///python2.7/tarfile.py

# -*- coding: iso-8859-1 -*-
#-------------------------------------------------------------------
# tarfile.py
#-------------------------------------------------------------------
# Copyright (C) 2002 Lars Gust�bel <lars@gustaebel.de>
# All rights reserved.
#
# Permission  is  hereby granted,  free  of charge,  to  any person
# obtaining a  copy of  this software  and associated documentation
# files  (the  "Software"),  to   deal  in  the  Software   without
# restriction,  including  without limitation  the  rights to  use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies  of  the  Software,  and to  permit  persons  to  whom the
# Software  is  furnished  to  do  so,  subject  to  the  following
# conditions:
#
# The above copyright  notice and this  permission notice shall  be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS  IS", WITHOUT WARRANTY OF ANY  KIND,
# EXPRESS OR IMPLIED, INCLUDING  BUT NOT LIMITED TO  THE WARRANTIES
# OF  MERCHANTABILITY,  FITNESS   FOR  A  PARTICULAR   PURPOSE  AND
# NONINFRINGEMENT.  IN  NO  EVENT SHALL  THE  AUTHORS  OR COPYRIGHT
# HOLDERS  BE LIABLE  FOR ANY  CLAIM, DAMAGES  OR OTHER  LIABILITY,
# WHETHER  IN AN  ACTION OF  CONTRACT, TORT  OR OTHERWISE,  ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
"""Read from and write to tar format archives.
"""

__version__ = "$Revision: 85213 $"
# $Source$

version     = "0.9.0"
__author__  = "Lars Gust�bel (lars@gustaebel.de)"
__date__    = "$Date$"
__cvsid__   = "$Id$"
__credits__ = "Gustavo Niemeyer, Niels Gust�bel, Richard Townsend."

#---------
# Imports
#---------
from __builtin__ import open as bltn_open
import sys
import os
import shutil
import stat
import errno
import time
import struct
import copy
import re
import operator

try:
    import grp, pwd
except ImportError:
    grp = pwd = None

# from tarfile import *
__all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError"]

#---------------------------------------------------------
# tar constants
#---------------------------------------------------------
NUL = "\0"                      # the null character
BLOCKSIZE = 512                 # length of processing blocks
RECORDSIZE = BLOCKSIZE * 20     # length of records
GNU_MAGIC = "ustar  \0"         # magic gnu tar string
POSIX_MAGIC = "ustar\x0000"     # magic posix tar string

LENGTH_NAME = 100               # maximum length of a filename
LENGTH_LINK = 100               # maximum length of a linkname
LENGTH_PREFIX = 155             # maximum length of the prefix field

REGTYPE = "0"                   # regular file
AREGTYPE = "\0"                 # regular file
LNKTYPE = "1"                   # link (inside tarfile)
SYMTYPE = "2"                   # symbolic link
CHRTYPE = "3"                   # character special device
BLKTYPE = "4"                   # block special device
DIRTYPE = "5"                   # directory
FIFOTYPE = "6"                  # fifo special device
CONTTYPE = "7"                  # contiguous file

GNUTYPE_LONGNAME = "L"          # GNU tar longname
GNUTYPE_LONGLINK = "K"          # GNU tar longlink
GNUTYPE_SPARSE = "S"            # GNU tar sparse file

XHDTYPE = "x"                   # POSIX.1-2001 extended header
XGLTYPE = "g"                   # POSIX.1-2001 global header
SOLARIS_XHDTYPE = "X"           # Solaris extended header

USTAR_FORMAT = 0                # POSIX.1-1988 (ustar) format
GNU_FORMAT = 1                  # GNU tar format
PAX_FORMAT = 2                  # POSIX.1-2001 (pax) format
DEFAULT_FORMAT = GNU_FORMAT

#---------------------------------------------------------
# tarfile constants
#---------------------------------------------------------
# File types that tarfile supports:
SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE,
                   SYMTYPE, DIRTYPE, FIFOTYPE,
                   CONTTYPE, CHRTYPE, BLKTYPE,
                   GNUTYPE_LONGNAME, GNUTYPE_LONGLINK,
                   GNUTYPE_SPARSE)

# File types that will be treated as a regular file.
REGULAR_TYPES = (REGTYPE, AREGTYPE,
                 CONTTYPE, GNUTYPE_SPARSE)

# File types that are part of the GNU tar format.
GNU_TYPES = (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK,
             GNUTYPE_SPARSE)

# Fields from a pax header that override a TarInfo attribute.
PAX_FIELDS = ("path", "linkpath", "size", "mtime",
              "uid", "gid", "uname", "gname")

# Fields in a pax header that are numbers, all other fields
# are treated as strings.
PAX_NUMBER_FIELDS = {
    "atime": float,
    "ctime": float,
    "mtime": float,
    "uid": int,
    "gid": int,
    "size": int
}

#---------------------------------------------------------
# Bits used in the mode field, values in octal.
#---------------------------------------------------------
S_IFLNK = 0120000        # symbolic link
S_IFREG = 0100000        # regular file
S_IFBLK = 0060000        # block device
S_IFDIR = 0040000        # directory
S_IFCHR = 0020000        # character device
S_IFIFO = 0010000        # fifo

TSUID   = 04000          # set UID on execution
TSGID   = 02000          # set GID on execution
TSVTX   = 01000          # reserved

TUREAD  = 0400           # read by owner
TUWRITE = 0200           # write by owner
TUEXEC  = 0100           # execute/search by owner
TGREAD  = 0040           # read by group
TGWRITE = 0020           # write by group
TGEXEC  = 0010           # execute/search by group
TOREAD  = 0004           # read by other
TOWRITE = 0002           # write by other
TOEXEC  = 0001           # execute/search by other

#---------------------------------------------------------
# initialization
#---------------------------------------------------------
ENCODING = sys.getfilesystemencoding()
if ENCODING is None:
    ENCODING = sys.getdefaultencoding()

#---------------------------------------------------------
# Some useful functions
#---------------------------------------------------------

def stn(s, length):
    """Convert a python string to a null-terminated string buffer.
    """
    return s[:length] + (length - len(s)) * NUL

def nts(s):
    """Convert a null-terminated string field to a python string.
    """
    # Use the string up to the first null char.
    p = s.find("\0")
    if p == -1:
        return s
    return s[:p]

def nti(s):
    """Convert a number field to a python number.
    """
    # There are two possible encodings for a number field, see
    # itn() below.
    if s[0] != chr(0200):
        try:
            n = int(nts(s).strip() or "0", 8)
        except ValueError:
            raise InvalidHeaderError("invalid header")
    else:
        n = 0L
        for i in xrange(len(s) - 1):
            n <<= 8
            n += ord(s[i + 1])
    return n

def itn(n, digits=8, format=DEFAULT_FORMAT):
    """Convert a python number to a number field.
    """
    # POSIX 1003.1-1988 requires numbers to be encoded as a string of
    # octal digits followed by a null-byte, this allows values up to
    # (8**(digits-1))-1. GNU tar allows storing numbers greater than
    # that if necessary. A leading 0200 byte indicates this particular
    # encoding, the following digits-1 bytes are a big-endian
    # representation. This allows values up to (256**(digits-1))-1.
    if 0 <= n < 8 ** (digits - 1):
        s = "%0*o" % (digits - 1, n) + NUL
    else:
        if format != GNU_FORMAT or n >= 256 ** (digits - 1):
            raise ValueError("overflow in number field")

        if n < 0:
            # XXX We mimic GNU tar's behaviour with negative numbers,
            # this could raise OverflowError.
            n = struct.unpack("L", struct.pack("l", n))[0]

        s = ""
        for i in xrange(digits - 1):
            s = chr(n & 0377) + s
            n >>= 8
        s = chr(0200) + s
    return s

def uts(s, encoding, errors):
    """Convert a unicode object to a string.
    """
    if errors == "utf-8":
        # An extra error handler similar to the -o invalid=UTF-8 option
        # in POSIX.1-2001. Replace untranslatable characters with their
        # UTF-8 representation.
        try:
            return s.encode(encoding, "strict")
        except UnicodeEncodeError:
            x = []
            for c in s:
                try:
                    x.append(c.encode(encoding, "strict"))
                except UnicodeEncodeError:
                    x.append(c.encode("utf8"))
            return "".join(x)
    else:
        return s.encode(encoding, errors)

def calc_chksums(buf):
    """Calculate the checksum for a member's header by summing up all
       characters except for the chksum field which is treated as if
       it was filled with spaces. According to the GNU tar sources,
       some tars (Sun and NeXT) calculate chksum with signed char,
       which will be different if there are chars in the buffer with
       the high bit set. So we calculate two checksums, unsigned and
       signed.
    """
    unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512]))
    signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512]))
    return unsigned_chksum, signed_chksum

def copyfileobj(src, dst, length=None):
    """Copy length bytes from fileobj src to fileobj dst.
       If length is None, copy the entire content.
    """
    if length == 0:
        return
    if length is None:
        shutil.copyfileobj(src, dst)
        return

    BUFSIZE = 16 * 1024
    blocks, remainder = divmod(length, BUFSIZE)
    for b in xrange(blocks):
        buf = src.read(BUFSIZE)
        if len(buf) < BUFSIZE:
            raise IOError("end of file reached")
        dst.write(buf)

    if remainder != 0:
        buf = src.read(remainder)
        if len(buf) < remainder:
            raise IOError("end of file reached")
        dst.write(buf)
    return

filemode_table = (
    ((S_IFLNK,      "l"),
     (S_IFREG,      "-"),
     (S_IFBLK,      "b"),
     (S_IFDIR,      "d"),
     (S_IFCHR,      "c"),
     (S_IFIFO,      "p")),

    ((TUREAD,       "r"),),
    ((TUWRITE,      "w"),),
    ((TUEXEC|TSUID, "s"),
     (TSUID,        "S"),
     (TUEXEC,       "x")),

    ((TGREAD,       "r"),),
    ((TGWRITE,      "w"),),
    ((TGEXEC|TSGID, "s"),
     (TSGID,        "S"),
     (TGEXEC,       "x")),

    ((TOREAD,       "r"),),
    ((TOWRITE,      "w"),),
    ((TOEXEC|TSVTX, "t"),
     (TSVTX,        "T"),
     (TOEXEC,       "x"))
)

def filemode(mode):
    """Convert a file's mode to a string of the form
       -rwxrwxrwx.
       Used by TarFile.list()
    """
    perm = []
    for table in filemode_table:
        for bit, char in table:
            if mode & bit == bit:
                perm.append(char)
                break
        else:
            perm.append("-")
    return "".join(perm)

class TarError(Exception):
    """Base exception."""
    pass
class ExtractError(TarError):
    """General exception for extract errors."""
    pass
class ReadError(TarError):
    """Exception for unreadable tar archives."""
    pass
class CompressionError(TarError):
    """Exception for unavailable compression methods."""
    pass
class StreamError(TarError):
    """Exception for unsupported operations on stream-like TarFiles."""
    pass
class HeaderError(TarError):
    """Base exception for header errors."""
    pass
class EmptyHeaderError(HeaderError):
    """Exception for empty headers."""
    pass
class TruncatedHeaderError(HeaderError):
    """Exception for truncated headers."""
    pass
class EOFHeaderError(HeaderError):
    """Exception for end of file headers."""
    pass
class InvalidHeaderError(HeaderError):
    """Exception for invalid headers."""
    pass
class SubsequentHeaderError(HeaderError):
    """Exception for missing and invalid extended headers."""
    pass

#---------------------------
# internal stream interface
#---------------------------
class _LowLevelFile:
    """Low-level file object. Supports reading and writing.
       It is used instead of a regular file object for streaming
       access.
    """

    def __init__(self, name, mode):
        mode = {
            "r": os.O_RDONLY,
            "w": os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
        }[mode]
        if hasattr(os, "O_BINARY"):
            mode |= os.O_BINARY
        self.fd = os.open(name, mode, 0666)

    def close(self):
        os.close(self.fd)

    def read(self, size):
        return os.read(self.fd, size)

    def write(self, s):
        os.write(self.fd, s)

class _Stream:
    """Class that serves as an adapter between TarFile and
       a stream-like object.  The stream-like object only
       needs to have a read() or write() method and is accessed
       blockwise.  Use of gzip or bzip2 compression is possible.
       A stream-like object could be for example: sys.stdin,
       sys.stdout, a socket, a tape device etc.

       _Stream is intended to be used only internally.
    """

    def __init__(self, name, mode, comptype, fileobj, bufsize):
        """Construct a _Stream object.
        """
        self._extfileobj = True
        if fileobj is None:
            fileobj = _LowLevelFile(name, mode)
            self._extfileobj = False

        if comptype == '*':
            # Enable transparent compression detection for the
            # stream interface
            fileobj = _StreamProxy(fileobj)
            comptype = fileobj.getcomptype()

        self.name     = name or ""
        self.mode     = mode
        self.comptype = comptype
        self.fileobj  = fileobj
        self.bufsize  = bufsize
        self.buf      = ""
        self.pos      = 0L
        self.closed   = False

        try:
            if comptype == "gz":
                try:
                    import zlib
                except ImportError:
                    raise CompressionError("zlib module is not available")
                self.zlib = zlib
                self.crc = zlib.crc32("") & 0xffffffffL
                if mode == "r":
                    self._init_read_gz()
                else:
                    self._init_write_gz()

            elif comptype == "bz2":
                try:
                    import bz2
                except ImportError:
                    raise CompressionError("bz2 module is not available")
                if mode == "r":
                    self.dbuf = ""
                    self.cmp = bz2.BZ2Decompressor()
                else:
                    self.cmp = bz2.BZ2Compressor()
        except:
            if not self._extfileobj:
                self.fileobj.close()
            self.closed = True
            raise

    def __del__(self):
        if hasattr(self, "closed") and not self.closed:
            self.close()

    def _init_write_gz(self):
        """Initialize for writing with gzip compression.
        """
        self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED,
                                            -self.zlib.MAX_WBITS,
                                            self.zlib.DEF_MEM_LEVEL,
                                            0)
        timestamp = struct.pack("<L", long(time.time()))
        self.__write("\037\213\010\010%s\002\377" % timestamp)
        if type(self.name) is unicode:
            self.name = self.name.encode("iso-8859-1", "replace")
        if self.name.endswith(".gz"):
            self.name = self.name[:-3]
        self.__write(self.name + NUL)

    def write(self, s):
        """Write string s to the stream.
        """
        if self.comptype == "gz":
            self.crc = self.zlib.crc32(s, self.crc) & 0xffffffffL
        self.pos += len(s)
        if self.comptype != "tar":
            s = self.cmp.compress(s)
        self.__write(s)

    def __write(self, s):
        """Write string s to the stream if a whole new block
           is ready to be written.
        """
        self.buf += s
        while len(self.buf) > self.bufsize:
            self.fileobj.write(self.buf[:self.bufsize])
            self.buf = self.buf[self.bufsize:]

    def close(self):
        """Close the _Stream object. No operation should be
           done on it afterwards.
        """
        if self.closed:
            return

        self.closed = True
        try:
            if self.mode == "w" and self.comptype != "tar":
                self.buf += self.cmp.flush()

            if self.mode == "w" and self.buf:
                self.fileobj.write(self.buf)
                self.buf = ""
                if self.comptype == "gz":
                    # The native zlib crc is an unsigned 32-bit integer, but
                    # the Python wrapper implicitly casts that to a signed C
                    # long.  So, on a 32-bit box self.crc may "look negative",
                    # while the same crc on a 64-bit box may "look positive".
                    # To avoid irksome warnings from the `struct` module, force
                    # it to look positive on all boxes.
                    self.fileobj.write(struct.pack("<L", self.crc & 0xffffffffL))
                    self.fileobj.write(struct.pack("<L", self.pos & 0xffffFFFFL))
        finally:
            if not self._extfileobj:
                self.fileobj.close()

    def _init_read_gz(self):
        """Initialize for reading a gzip compressed fileobj.
        """
        self.cmp = self.zlib.decompressobj(-self.zlib.MAX_WBITS)
        self.dbuf = ""

        # taken from gzip.GzipFile with some alterations
        if self.__read(2) != "\037\213":
            raise ReadError("not a gzip file")
        if self.__read(1) != "\010":
            raise CompressionError("unsupported compression method")

        flag = ord(self.__read(1))
        self.__read(6)

        if flag & 4:
            xlen = ord(self.__read(1)) + 256 * ord(self.__read(1))
            self.read(xlen)
        if flag & 8:
            while True:
                s = self.__read(1)
                if not s or s == NUL:
                    break
        if flag & 16:
            while True:
                s = self.__read(1)
                if not s or s == NUL:
                    break
        if flag & 2:
            self.__read(2)

    def tell(self):
        """Return the stream's file pointer position.
        """
        return self.pos

    def seek(self, pos=0):
        """Set the stream's file pointer to pos. Negative seeking
           is forbidden.
        """
        if pos - self.pos >= 0:
            blocks, remainder = divmod(pos - self.pos, self.bufsize)
            for i in xrange(blocks):
                self.read(self.bufsize)
            self.read(remainder)
        else:
            raise StreamError("seeking backwards is not allowed")
        return self.pos

    def read(self, size=None):
        """Return the next size number of bytes from the stream.
           If size is not defined, return all bytes of the stream
           up to EOF.
        """
        if size is None:
            t = []
            while True:
                buf = self._read(self.bufsize)
                if not buf:
                    break
                t.append(buf)
            buf = "".join(t)
        else:
            buf = self._read(size)
        self.pos += len(buf)
        return buf

    def _read(self, size):
        """Return size bytes from the stream.
        """
        if self.comptype == "tar":
            return self.__read(size)

        c = len(self.dbuf)
        t = [self.dbuf]
        while c < size:
            buf = self.__read(self.bufsize)
            if not buf:
                break
            try:
                buf = self.cmp.decompress(buf)
            except IOError:
                raise ReadError("invalid compressed data")
            t.append(buf)
            c += len(buf)
        t = "".join(t)
        self.dbuf = t[size:]
        return t[:size]

    def __read(self, size):
        """Return size bytes from stream. If internal buffer is empty,
           read another block from the stream.
        """
        c = len(self.buf)
        t = [self.buf]
        while c < size:
            buf = self.fileobj.read(self.bufsize)
            if not buf:
                break
            t.append(buf)
            c += len(buf)
        t = "".join(t)
        self.buf = t[size:]
        return t[:size]
# class _Stream

class _StreamProxy(object):
    """Small proxy class that enables transparent compression
       detection for the Stream interface (mode 'r|*').
    """

    def __init__(self, fileobj):
        self.fileobj = fileobj
        self.buf = self.fileobj.read(BLOCKSIZE)

    def read(self, size):
        self.read = self.fileobj.read
        return self.buf

    def getcomptype(self):
        if self.buf.startswith("\037\213\010"):
            return "gz"
        if self.buf[0:3] == "BZh" and self.buf[4:10] == "1AY&SY":
            return "bz2"
        return "tar"

    def close(self):
        self.fileobj.close()
# class StreamProxy

class _BZ2Proxy(object):
    """Small proxy class that enables external file object
       support for "r:bz2" and "w:bz2" modes. This is actually
       a workaround for a limitation in bz2 module's BZ2File
       class which (unlike gzip.GzipFile) has no support for
       a file object argument.
    """

    blocksize = 16 * 1024

    def __init__(self, fileobj, mode):
        self.fileobj = fileobj
        self.mode = mode
        self.name = getattr(self.fileobj, "name", None)
        self.init()

    def init(self):
        import bz2
        self.pos = 0
        if self.mode == "r":
            self.bz2obj = bz2.BZ2Decompressor()
            self.fileobj.seek(0)
            self.buf = ""
        else:
            self.bz2obj = bz2.BZ2Compressor()

    def read(self, size):
        b = [self.buf]
        x = len(self.buf)
        while x < size:
            raw = self.fileobj.read(self.blocksize)
            if not raw:
                break
            data = self.bz2obj.decompress(raw)
            b.append(data)
            x += len(data)
        self.buf = "".join(b)

        buf = self.buf[:size]
        self.buf = self.buf[size:]
        self.pos += len(buf)
        return buf

    def seek(self, pos):
        if pos < self.pos:
            self.init()
        self.read(pos - self.pos)

    def tell(self):
        return self.pos

    def write(self, data):
        self.pos += len(data)
        raw = self.bz2obj.compress(data)
        self.fileobj.write(raw)

    def close(self):
        if self.mode == "w":
            raw = self.bz2obj.flush()
            self.fileobj.write(raw)
# class _BZ2Proxy

#------------------------
# Extraction file object
#------------------------
class _FileInFile(object):
    """A thin wrapper around an existing file object that
       provides a part of its data as an individual file
       object.
    """

    def __init__(self, fileobj, offset, size, sparse=None):
        self.fileobj = fileobj
        self.offset = offset
        self.size = size
        self.sparse = sparse
        self.position = 0

    def tell(self):
        """Return the current file position.
        """
        return self.position

    def seek(self, position):
        """Seek to a position in the file.
        """
        self.position = position

    def read(self, size=None):
        """Read data from the file.
        """
        if size is None:
            size = self.size - self.position
        else:
            size = min(size, self.size - self.position)

        if self.sparse is None:
            return self.readnormal(size)
        else:
            return self.readsparse(size)

    def __read(self, size):
        buf = self.fileobj.read(size)
        if len(buf) != size:
            raise ReadError("unexpected end of data")
        return buf

    def readnormal(self, size):
        """Read operation for regular files.
        """
        self.fileobj.seek(self.offset + self.position)
        self.position += size
        return self.__read(size)

    def readsparse(self, size):
        """Read operation for sparse files.
        """
        data = []
        while size > 0:
            buf = self.readsparsesection(size)
            if not buf:
                break
            size -= len(buf)
            data.append(buf)
        return "".join(data)

    def readsparsesection(self, size):
        """Read a single section of a sparse file.
        """
        section = self.sparse.find(self.position)

        if section is None:
            return ""

        size = min(size, section.offset + section.size - self.position)

        if isinstance(section, _data):
            realpos = section.realpos + self.position - section.offset
            self.fileobj.seek(self.offset + realpos)
            self.position += size
            return self.__read(size)
        else:
            self.position += size
            return NUL * size
#class _FileInFile


class ExFileObject(object):
    """File-like object for reading an archive member.
       Is returned by TarFile.extractfile().
    """
    blocksize = 1024

    def __init__(self, tarfile, tarinfo):
        self.fileobj = _FileInFile(tarfile.fileobj,
                                   tarinfo.offset_data,
                                   tarinfo.size,
                                   getattr(tarinfo, "sparse", None))
        self.name = tarinfo.name
        self.mode = "r"
        self.closed = False
        self.size = tarinfo.size

        self.position = 0
        self.buffer = ""

    def read(self, size=None):
        """Read at most size bytes from the file. If size is not
           present or None, read all data until EOF is reached.
        """
        if self.closed:
            raise ValueError("I/O operation on closed file")

        buf = ""
        if self.buffer:
            if size is None:
                buf = self.buffer
                self.buffer = ""
            else:
                buf = self.buffer[:size]
                self.buffer = self.buffer[size:]

        if size is None:
            buf += self.fileobj.read()
        else:
            buf += self.fileobj.read(size - len(buf))

        self.position += len(buf)
        return buf

    def readline(self, size=-1):
        """Read one entire line from the file. If size is present
           and non-negative, return a string with at most that
           size, which may be an incomplete line.
        """
        if self.closed:
            raise ValueError("I/O operation on closed file")

        if "\n" in self.buffer:
            pos = self.buffer.find("\n") + 1
        else:
            buffers = [self.buffer]
            while True:
                buf = self.fileobj.read(self.blocksize)
                buffers.append(buf)
                if not buf or "\n" in buf:
                    self.buffer = "".join(buffers)
                    pos = self.buffer.find("\n") + 1
                    if pos == 0:
                        # no newline found.
                        pos = len(self.buffer)
                    break

        if size != -1:
            pos = min(size, pos)

        buf = self.buffer[:pos]
        self.buffer = self.buffer[pos:]
        self.position += len(buf)
        return buf

    def readlines(self):
        """Return a list with all remaining lines.
        """
        result = []
        while True:
            line = self.readline()
            if not line: break
            result.append(line)
        return result

    def tell(self):
        """Return the current file position.
        """
        if self.closed:
            raise ValueError("I/O operation on closed file")

        return self.position

    def seek(self, pos, whence=os.SEEK_SET):
        """Seek to a position in the file.
        """
        if self.closed:
            raise ValueError("I/O operation on closed file")

        if whence == os.SEEK_SET:
            self.position = min(max(pos, 0), self.size)
        elif whence == os.SEEK_CUR:
            if pos < 0:
                self.position = max(self.position + pos, 0)
            else:
                self.position = min(self.position + pos, self.size)
        elif whence == os.SEEK_END:
            self.position = max(min(self.size + pos, self.size), 0)
        else:
            raise ValueError("Invalid argument")

        self.buffer = ""
        self.fileobj.seek(self.position)

    def close(self):
        """Close the file object.
        """
        self.closed = True

    def __iter__(self):
        """Get an iterator over the file's lines.
        """
        while True:
            line = self.readline()
            if not line:
                break
            yield line
#class ExFileObject

#------------------
# Exported Classes
#------------------
class TarInfo(object):
    """Informational class which holds the details about an
       archive member given by a tar header block.
       TarInfo objects are returned by TarFile.getmember(),
       TarFile.getmembers() and TarFile.gettarinfo() and are
       usually created internally.
    """

    def __init__(self, name=""):
        """Construct a TarInfo object. name is the optional name
           of the member.
        """
        self.name = name        # member name
        self.mode = 0644        # file permissions
        self.uid = 0            # user id
        self.gid = 0            # group id
        self.size = 0           # file size
        self.mtime = 0          # modification time
        self.chksum = 0         # header checksum
        self.type = REGTYPE     # member type
        self.linkname = ""      # link name
        self.uname = ""         # user name
        self.gname = ""         # group name
        self.devmajor = 0       # device major number
        self.devminor = 0       # device minor number

        self.offset = 0         # the tar header starts here
        self.offset_data = 0    # the file's data starts here

        self.pax_headers = {}   # pax header information

    # In pax headers the "name" and "linkname" field are called
    # "path" and "linkpath".
    def _getpath(self):
        return self.name
    def _setpath(self, name):
        self.name = name
    path = property(_getpath, _setpath)

    def _getlinkpath(self):
        return self.linkname
    def _setlinkpath(self, linkname):
        self.linkname = linkname
    linkpath = property(_getlinkpath, _setlinkpath)

    def __repr__(self):
        return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self))

    def get_info(self, encoding, errors):
        """Return the TarInfo's attributes as a dictionary.
        """
        info = {
            "name":     self.name,
            "mode":     self.mode & 07777,
            "uid":      self.uid,
            "gid":      self.gid,
            "size":     self.size,
            "mtime":    self.mtime,
            "chksum":   self.chksum,
            "type":     self.type,
            "linkname": self.linkname,
            "uname":    self.uname,
            "gname":    self.gname,
            "devmajor": self.devmajor,
            "devminor": self.devminor
        }

        if info["type"] == DIRTYPE and not info["name"].endswith("/"):
            info["name"] += "/"

        for key in ("name", "linkname", "uname", "gname"):
            if type(info[key]) is unicode:
                info[key] = info[key].encode(encoding, errors)

        return info

    def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="strict"):
        """Return a tar header as a string of 512 byte blocks.
        """
        info = self.get_info(encoding, errors)

        if format == USTAR_FORMAT:
            return self.create_ustar_header(info)
        elif format == GNU_FORMAT:
            return self.create_gnu_header(info)
        elif format == PAX_FORMAT:
            return self.create_pax_header(info, encoding, errors)
        else:
            raise ValueError("invalid format")

    def create_ustar_header(self, info):
        """Return the object as a ustar header block.
        """
        info["magic"] = POSIX_MAGIC

        if len(info["linkname"]) > LENGTH_LINK:
            raise ValueError("linkname is too long")

        if len(info["name"]) > LENGTH_NAME:
            info["prefix"], info["name"] = self._posix_split_name(info["name"])

        return self._create_header(info, USTAR_FORMAT)

    def create_gnu_header(self, info):
        """Return the object as a GNU header block sequence.
        """
        info["magic"] = GNU_MAGIC

        buf = ""
        if len(info["linkname"]) > LENGTH_LINK:
            buf += self._create_gnu_long_header(info["linkname"], GNUTYPE_LONGLINK)

        if len(info["name"]) > LENGTH_NAME:
            buf += self._create_gnu_long_header(info["name"], GNUTYPE_LONGNAME)

        return buf + self._create_header(info, GNU_FORMAT)

    def create_pax_header(self, info, encoding, errors):
        """Return the object as a ustar header block. If it cannot be
           represented this way, prepend a pax extended header sequence
           with supplement information.
        """
        info["magic"] = POSIX_MAGIC
        pax_headers = self.pax_headers.copy()

        # Test string fields for values that exceed the field length or cannot
        # be represented in ASCII encoding.
        for name, hname, length in (
                ("name", "path", LENGTH_NAME), ("linkname", "linkpath", LENGTH_LINK),
                ("uname", "uname", 32), ("gname", "gname", 32)):

            if hname in pax_headers:
                # The pax header has priority.
                continue

            val = info[name].decode(encoding, errors)

            # Try to encode the string as ASCII.
            try:
                val.encode("ascii")
            except UnicodeEncodeError:
                pax_headers[hname] = val
                continue

            if len(info[name]) > length:
                pax_headers[hname] = val

        # Test number fields for values that exceed the field limit or values
        # that like to be stored as float.
        for name, digits in (("uid", 8), ("gid", 8), ("size", 12), ("mtime", 12)):
            if name in pax_headers:
                # The pax header has priority. Avoid overflow.
                info[name] = 0
                continue

            val = info[name]
            if not 0 <= val < 8 ** (digits - 1) or isinstance(val, float):
                pax_headers[name] = unicode(val)
                info[name] = 0

        # Create a pax extended header if necessary.
        if pax_headers:
            buf = self._create_pax_generic_header(pax_headers)
        else:
            buf = ""

        return buf + self._create_header(info, USTAR_FORMAT)

    @classmethod
    def create_pax_global_header(cls, pax_headers):
        """Return the object as a pax global header block sequence.
        """
        return cls._create_pax_generic_header(pax_headers, type=XGLTYPE)

    def _posix_split_name(self, name):
        """Split a name longer than 100 chars into a prefix
           and a name part.
        """
        prefix = name[:LENGTH_PREFIX + 1]
        while prefix and prefix[-1] != "/":
            prefix = prefix[:-1]

        name = name[len(prefix):]
        prefix = prefix[:-1]

        if not prefix or len(name) > LENGTH_NAME:
            raise ValueError("name is too long")
        return prefix, name

    @staticmethod
    def _create_header(info, format):
        """Return a header block. info is a dictionary with file
           information, format must be one of the *_FORMAT constants.
        """
        parts = [
            stn(info.get("name", ""), 100),
            itn(info.get("mode", 0) & 07777, 8, format),
            itn(info.get("uid", 0), 8, format),
            itn(info.get("gid", 0), 8, format),
            itn(info.get("size", 0), 12, format),
            itn(info.get("mtime", 0), 12, format),
            "        ", # checksum field
            info.get("type", REGTYPE),
            stn(info.get("linkname", ""), 100),
            stn(info.get("magic", POSIX_MAGIC), 8),
            stn(info.get("uname", ""), 32),
            stn(info.get("gname", ""), 32),
            itn(info.get("devmajor", 0), 8, format),
            itn(info.get("devminor", 0), 8, format),
            stn(info.get("prefix", ""), 155)
        ]

        buf = struct.pack("%ds" % BLOCKSIZE, "".join(parts))
        chksum = calc_chksums(buf[-BLOCKSIZE:])[0]
        buf = buf[:-364] + "%06o\0" % chksum + buf[-357:]
        return buf

    @staticmethod
    def _create_payload(payload):
        """Return the string payload filled with zero bytes
           up to the next 512 byte border.
        """
        blocks, remainder = divmod(len(payload), BLOCKSIZE)
        if remainder > 0:
            payload += (BLOCKSIZE - remainder) * NUL
        return payload

    @classmethod
    def _create_gnu_long_header(cls, name, type):
        """Return a GNUTYPE_LONGNAME or GNUTYPE_LONGLINK sequence
           for name.
        """
        name += NUL

        info = {}
        info["name"] = "././@LongLink"
        info["type"] = type
        info["size"] = len(name)
        info["magic"] = GNU_MAGIC

        # create extended header + name blocks.
        return cls._create_header(info, USTAR_FORMAT) + \
                cls._create_payload(name)

    @classmethod
    def _create_pax_generic_header(cls, pax_headers, type=XHDTYPE):
        """Return a POSIX.1-2001 extended or global header sequence
           that contains a list of keyword, value pairs. The values
           must be unicode objects.
        """
        records = []
        for keyword, value in pax_headers.iteritems():
            keyword = keyword.encode("utf8")
            value = value.encode("utf8")
            l = len(keyword) + len(value) + 3   # ' ' + '=' + '\n'
            n = p = 0
            while True:
                n = l + len(str(p))
                if n == p:
                    break
                p = n
            records.append("%d %s=%s\n" % (p, keyword, value))
        records = "".join(records)

        # We use a hardcoded "././@PaxHeader" name like star does
        # instead of the one that POSIX recommends.
        info = {}
        info["name"] = "././@PaxHeader"
        info["type"] = type
        info["size"] = len(records)
        info["magic"] = POSIX_MAGIC

        # Create pax header + record blocks.
        return cls._create_header(info, USTAR_FORMAT) + \
                cls._create_payload(records)

    @classmethod
    def frombuf(cls, buf):
        """Construct a TarInfo object from a 512 byte string buffer.
        """
        if len(buf) == 0:
            raise EmptyHeaderError("empty header")
        if len(buf) != BLOCKSIZE:
            raise TruncatedHeaderError("truncated header")
        if buf.count(NUL) == BLOCKSIZE:
            raise EOFHeaderError("end of file header")

        chksum = nti(buf[148:156])
        if chksum not in calc_chksums(buf):
            raise InvalidHeaderError("bad checksum")

        obj = cls()
        obj.buf = buf
        obj.name = nts(buf[0:100])
        obj.mode = nti(buf[100:108])
        obj.uid = nti(buf[108:116])
        obj.gid = nti(buf[116:124])
        obj.size = nti(buf[124:136])
        obj.mtime = nti(buf[136:148])
        obj.chksum = chksum
        obj.type = buf[156:157]
        obj.linkname = nts(buf[157:257])
        obj.uname = nts(buf[265:297])
        obj.gname = nts(buf[297:329])
        obj.devmajor = nti(buf[329:337])
        obj.devminor = nti(buf[337:345])
        prefix = nts(buf[345:500])

        # Old V7 tar format represents a directory as a regular
        # file with a trailing slash.
        if obj.type == AREGTYPE and obj.name.endswith("/"):
            obj.type = DIRTYPE

        # Remove redundant slashes from directories.
        if obj.isdir():
            obj.name = obj.name.rstrip("/")

        # Reconstruct a ustar longname.
        if prefix and obj.type not in GNU_TYPES:
            obj.name = prefix + "/" + obj.name
        return obj

    @classmethod
    def fromtarfile(cls, tarfile):
        """Return the next TarInfo object from TarFile object
           tarfile.
        """
        buf = tarfile.fileobj.read(BLOCKSIZE)
        obj = cls.frombuf(buf)
        obj.offset = tarfile.fileobj.tell() - BLOCKSIZE
        return obj._proc_member(tarfile)

    #--------------------------------------------------------------------------
    # The following are methods that are called depending on the type of a
    # member. The entry point is _proc_member() which can be overridden in a
    # subclass to add custom _proc_*() methods. A _proc_*() method MUST
    # implement the following
    # operations:
    # 1. Set self.offset_data to the position where the data blocks begin,
    #    if there is data that follows.
    # 2. Set tarfile.offset to the position where the next member's header will
    #    begin.
    # 3. Return self or another valid TarInfo object.
    def _proc_member(self, tarfile):
        """Choose the right processing method depending on
           the type and call it.
        """
        if self.type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK):
            return self._proc_gnulong(tarfile)
        elif self.type == GNUTYPE_SPARSE:
            return self._proc_sparse(tarfile)
        elif self.type in (XHDTYPE, XGLTYPE, SOLARIS_XHDTYPE):
            return self._proc_pax(tarfile)
        else:
            return self._proc_builtin(tarfile)

    def _proc_builtin(self, tarfile):
        """Process a builtin type or an unknown type which
           will be treated as a regular file.
        """
        self.offset_data = tarfile.fileobj.tell()
        offset = self.offset_data
        if self.isreg() or self.type not in SUPPORTED_TYPES:
            # Skip the following data blocks.
            offset += self._block(self.size)
        tarfile.offset = offset

        # Patch the TarInfo object with saved global
        # header information.
        self._apply_pax_info(tarfile.pax_headers, tarfile.encoding, tarfile.errors)

        return self

    def _proc_gnulong(self, tarfile):
        """Process the blocks that hold a GNU longname
           or longlink member.
        """
        buf = tarfile.fileobj.read(self._block(self.size))

        # Fetch the next header and process it.
        try:
            next = self.fromtarfile(tarfile)
        except HeaderError:
            raise SubsequentHeaderError("missing or bad subsequent header")

        # Patch the TarInfo object from the next header with
        # the longname information.
        next.offset = self.offset
        if self.type == GNUTYPE_LONGNAME:
            next.name = nts(buf)
        elif self.type == GNUTYPE_LONGLINK:
            next.linkname = nts(buf)

        return next

    def _proc_sparse(self, tarfile):
        """Process a GNU sparse header plus extra headers.
        """
        buf = self.buf
        sp = _ringbuffer()
        pos = 386
        lastpos = 0L
        realpos = 0L
        # There are 4 possible sparse structs in the
        # first header.
        for i in xrange(4):
            try:
                offset = nti(buf[pos:pos + 12])
                numbytes = nti(buf[pos + 12:pos + 24])
            except ValueError:
                break
            if offset > lastpos:
                sp.append(_hole(lastpos, offset - lastpos))
            sp.append(_data(offset, numbytes, realpos))
            realpos += numbytes
            lastpos = offset + numbytes
            pos += 24

        isextended = ord(buf[482])
        origsize = nti(buf[483:495])

        # If the isextended flag is given,
        # there are extra headers to process.
        while isextended == 1:
            buf = tarfile.fileobj.read(BLOCKSIZE)
            pos = 0
            for i in xrange(21):
                try:
                    offset = nti(buf[pos:pos + 12])
                    numbytes = nti(buf[pos + 12:pos + 24])
                except ValueError:
                    break
                if offset > lastpos:
                    sp.append(_hole(lastpos, offset - lastpos))
                sp.append(_data(offset, numbytes, realpos))
                realpos += numbytes
                lastpos = offset + numbytes
                pos += 24
            isextended = ord(buf[504])

        if lastpos < origsize:
            sp.append(_hole(lastpos, origsize - lastpos))

        self.sparse = sp

        self.offset_data = tarfile.fileobj.tell()
        tarfile.offset = self.offset_data + self._block(self.size)
        self.size = origsize

        return self

    def _proc_pax(self, tarfile):
        """Process an extended or global header as described in
           POSIX.1-2001.
        """
        # Read the header information.
        buf = tarfile.fileobj.read(self._block(self.size))

        # A pax header stores supplemental information for either
        # the following file (extended) or all following files
        # (global).
        if self.type == XGLTYPE:
            pax_headers = tarfile.pax_headers
        else:
            pax_headers = tarfile.pax_headers.copy()

        # Parse pax header information. A record looks like that:
        # "%d %s=%s\n" % (length, keyword, value). length is the size
        # of the complete record including the length field itself and
        # the newline. keyword and value are both UTF-8 encoded strings.
        regex = re.compile(r"(\d+) ([^=]+)=", re.U)
        pos = 0
        while True:
            match = regex.match(buf, pos)
            if not match:
                break

            length, keyword = match.groups()
            length = int(length)
            value = buf[match.end(2) + 1:match.start(1) + length - 1]

            keyword = keyword.decode("utf8")
            value = value.decode("utf8")

            pax_headers[keyword] = value
            pos += length

        # Fetch the next header.
        try:
            next = self.fromtarfile(tarfile)
        except HeaderError:
            raise SubsequentHeaderError("missing or bad subsequent header")

        if self.type in (XHDTYPE, SOLARIS_XHDTYPE):
            # Patch the TarInfo object with the extended header info.
            next._apply_pax_info(pax_headers, tarfile.encoding, tarfile.errors)
            next.offset = self.offset

            if "size" in pax_headers:
                # If the extended header replaces the size field,
                # we need to recalculate the offset where the next
                # header starts.
                offset = next.offset_data
                if next.isreg() or next.type not in SUPPORTED_TYPES:
                    offset += next._block(next.size)
                tarfile.offset = offset

        return next

    def _apply_pax_info(self, pax_headers, encoding, errors):
        """Replace fields with supplemental information from a previous
           pax extended or global header.
        """
        for keyword, value in pax_headers.iteritems():
            if keyword not in PAX_FIELDS:
                continue

            if keyword == "path":
                value = value.rstrip("/")

            if keyword in PAX_NUMBER_FIELDS:
                try:
                    value = PAX_NUMBER_FIELDS[keyword](value)
                except ValueError:
                    value = 0
            else:
                value = uts(value, encoding, errors)

            setattr(self, keyword, value)

        self.pax_headers = pax_headers.copy()

    def _block(self, count):
        """Round up a byte count by BLOCKSIZE and return it,
           e.g. _block(834) => 1024.
        """
        blocks, remainder = divmod(count, BLOCKSIZE)
        if remainder:
            blocks += 1
        return blocks * BLOCKSIZE

    def isreg(self):
        return self.type in REGULAR_TYPES
    def isfile(self):
        return self.isreg()
    def isdir(self):
        return self.type == DIRTYPE
    def issym(self):
        return self.type == SYMTYPE
    def islnk(self):
        return self.type == LNKTYPE
    def ischr(self):
        return self.type == CHRTYPE
    def isblk(self):
        return self.type == BLKTYPE
    def isfifo(self):
        return self.type == FIFOTYPE
    def issparse(self):
        return self.type == GNUTYPE_SPARSE
    def isdev(self):
        return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE)
# class TarInfo

class TarFile(object):
    """The TarFile Class provides an interface to tar archives.
    """

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

    dereference = False         # If true, add content of linked file to the
                                # tar file, else the link.

    ignore_zeros = False        # If true, skips empty or invalid blocks and
                                # continues processing.

    errorlevel = 1              # If 0, fatal errors only appear in debug
                                # messages (if debug >= 0). If > 0, errors
                                # are passed to the caller as exceptions.

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

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

    errors = None               # Error handler for unicode conversion.

    tarinfo = TarInfo           # The default TarInfo class to use.

    fileobject = ExFileObject   # The default ExFileObject class to use.

    def __init__(self, name=None, mode="r", fileobj=None, format=None,
            tarinfo=None, dereference=None, ignore_zeros=None, encoding=None,
            errors=None, pax_headers=None, debug=None, errorlevel=None):
        """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to
           read from an existing archive, 'a' to append data to an existing
           file or 'w' to create a new file overwriting an existing one. `mode'
           defaults to 'r'.
           If `fileobj' is given, it is used for reading or writing data. If it
           can be determined, `mode' is overridden by `fileobj's mode.
           `fileobj' is not closed, when TarFile is closed.
        """
        modes = {"r": "rb", "a": "r+b", "w": "wb"}
        if mode not in modes:
            raise ValueError("mode must be 'r', 'a' or 'w'")
        self.mode = mode
        self._mode = modes[mode]

        if not fileobj:
            if self.mode == "a" and not os.path.exists(name):
                # Create nonexistent files in append mode.
                self.mode = "w"
                self._mode = "wb"
            fileobj = bltn_open(name, self._mode)
            self._extfileobj = False
        else:
            if name is None and hasattr(fileobj, "name"):
                name = fileobj.name
            if hasattr(fileobj, "mode"):
                self._mode = fileobj.mode
            self._extfileobj = True
        self.name = os.path.abspath(name) if name else None
        self.fileobj = fileobj

        # Init attributes.
        if format is not None:
            self.format = format
        if tarinfo is not None:
            self.tarinfo = tarinfo
        if dereference is not None:
            self.dereference = dereference
        if ignore_zeros is not None:
            self.ignore_zeros = ignore_zeros
        if encoding is not None:
            self.encoding = encoding

        if errors is not None:
            self.errors = errors
        elif mode == "r":
            self.errors = "utf-8"
        else:
            self.errors = "strict"

        if pax_headers is not None and self.format == PAX_FORMAT:
            self.pax_headers = pax_headers
        else:
            self.pax_headers = {}

        if debug is not None:
            self.debug = debug
        if errorlevel is not None:
            self.errorlevel = errorlevel

        # Init datastructures.
        self.closed = False
        self.members = []       # list of members as TarInfo objects
        self._loaded = False    # flag if all members have been read
        self.offset = self.fileobj.tell()
                                # current position in the archive file
        self.inodes = {}        # dictionary caching the inodes of
                                # archive members already added

        try:
            if self.mode == "r":
                self.firstmember = None
                self.firstmember = self.next()

            if self.mode == "a":
                # Move to the end of the archive,
                # before the first empty block.
                while True:
                    self.fileobj.seek(self.offset)
                    try:
                        tarinfo = self.tarinfo.fromtarfile(self)
                        self.members.append(tarinfo)
                    except EOFHeaderError:
                        self.fileobj.seek(self.offset)
                        break
                    except HeaderError, e:
                        raise ReadError(str(e))

            if self.mode in "aw":
                self._loaded = True

                if self.pax_headers:
                    buf = self.tarinfo.create_pax_global_header(self.pax_headers.copy())
                    self.fileobj.write(buf)
                    self.offset += len(buf)
        except:
            if not self._extfileobj:
                self.fileobj.close()
            self.closed = True
            raise

    def _getposix(self):
        return self.format == USTAR_FORMAT
    def _setposix(self, value):
        import warnings
        warnings.warn("use the format attribute instead", DeprecationWarning,
                      2)
        if value:
            self.format = USTAR_FORMAT
        else:
            self.format = GNU_FORMAT
    posix = property(_getposix, _setposix)

    #--------------------------------------------------------------------------
    # Below are the classmethods which act as alternate constructors to the
    # TarFile class. The open() method is the only one that is needed for
    # public use; it is the "super"-constructor and is able to select an
    # adequate "sub"-constructor for a particular compression using the mapping
    # from OPEN_METH.
    #
    # This concept allows one to subclass TarFile without losing the comfort of
    # the super-constructor. A sub-constructor is registered and made available
    # by adding it to the mapping in OPEN_METH.

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

           mode:
           'r' or 'r:*' open for reading with transparent compression
           'r:'         open for reading exclusively uncompressed
           'r:gz'       open for reading with gzip compression
           'r:bz2'      open for reading with bzip2 compression
           'a' or 'a:'  open for appending, creating the file if necessary
           'w' or 'w:'  open for writing without compression
           'w:gz'       open for writing with gzip compression
           'w:bz2'      open for writing with bzip2 compression

           'r|*'        open a stream of tar blocks with transparent compression
           'r|'         open an uncompressed stream of tar blocks for reading
           'r|gz'       open a gzip compressed stream of tar blocks
           'r|bz2'      open a bzip2 compressed stream of tar blocks
           'w|'         open an uncompressed stream for writing
           'w|gz'       open a gzip compressed stream for writing
           'w|bz2'      open a bzip2 compressed stream for writing
        """

        if not name and not fileobj:
            raise ValueError("nothing to open")

        if mode in ("r", "r:*"):
            # Find out which *open() is appropriate for opening the file.
            def not_compressed(comptype):
                return cls.OPEN_METH[comptype] == 'taropen'
            for comptype in sorted(cls.OPEN_METH, key=not_compressed):
                func = getattr(cls, cls.OPEN_METH[comptype])
                if fileobj is not None:
                    saved_pos = fileobj.tell()
                try:
                    return func(name, "r", fileobj, **kwargs)
                except (ReadError, CompressionError), e:
                    if fileobj is not None:
                        fileobj.seek(saved_pos)
                    continue
            raise ReadError("file could not be opened successfully")

        elif ":" in mode:
            filemode, comptype = mode.split(":", 1)
            filemode = filemode or "r"
            comptype = comptype or "tar"

            # Select the *open() function according to
            # given compression.
            if comptype in cls.OPEN_METH:
                func = getattr(cls, cls.OPEN_METH[comptype])
            else:
                raise CompressionError("unknown compression type %r" % comptype)
            return func(name, filemode, fileobj, **kwargs)

        elif "|" in mode:
            filemode, comptype = mode.split("|", 1)
            filemode = filemode or "r"
            comptype = comptype or "tar"

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

            stream = _Stream(name, filemode, comptype, fileobj, bufsize)
            try:
                t = cls(name, filemode, stream, **kwargs)
            except:
                stream.close()
                raise
            t._extfileobj = False
            return t

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

        raise ValueError("undiscernible mode")

    @classmethod
    def taropen(cls, name, mode="r", fileobj=None, **kwargs):
        """Open uncompressed tar archive name for reading or writing.
        """
        if mode not in ("r", "a", "w"):
            raise ValueError("mode must be 'r', 'a' or 'w'")
        return cls(name, mode, fileobj, **kwargs)

    @classmethod
    def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs):
        """Open gzip compressed tar archive name for reading or writing.
           Appending is not allowed.
        """
        if mode not in ("r", "w"):
            raise ValueError("mode must be 'r' or 'w'")

        try:
            import gzip
            gzip.GzipFile
        except (ImportError, AttributeError):
            raise CompressionError("gzip module is not available")

        try:
            fileobj = gzip.GzipFile(name, mode, compresslevel, fileobj)
        except OSError:
            if fileobj is not None and mode == 'r':
                raise ReadError("not a gzip file")
            raise

        try:
            t = cls.taropen(name, mode, fileobj, **kwargs)
        except IOError:
            fileobj.close()
            if mode == 'r':
                raise ReadError("not a gzip file")
            raise
        except:
            fileobj.close()
            raise
        t._extfileobj = False
        return t

    @classmethod
    def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs):
        """Open bzip2 compressed tar archive name for reading or writing.
           Appending is not allowed.
        """
        if mode not in ("r", "w"):
            raise ValueError("mode must be 'r' or 'w'.")

        try:
            import bz2
        except ImportError:
            raise CompressionError("bz2 module is not available")

        if fileobj is not None:
            fileobj = _BZ2Proxy(fileobj, mode)
        else:
            fileobj = bz2.BZ2File(name, mode, compresslevel=compresslevel)

        try:
            t = cls.taropen(name, mode, fileobj, **kwargs)
        except (IOError, EOFError):
            fileobj.close()
            if mode == 'r':
                raise ReadError("not a bzip2 file")
            raise
        except:
            fileobj.close()
            raise
        t._extfileobj = False
        return t

    # All *open() methods are registered here.
    OPEN_METH = {
        "tar": "taropen",   # uncompressed tar
        "gz":  "gzopen",    # gzip compressed tar
        "bz2": "bz2open"    # bzip2 compressed tar
    }

    #--------------------------------------------------------------------------
    # The public methods which TarFile provides:

    def close(self):
        """Close the TarFile. In write-mode, two finishing zero blocks are
           appended to the archive.
        """
        if self.closed:
            return

        self.closed = True
        try:
            if self.mode in "aw":
                self.fileobj.write(NUL * (BLOCKSIZE * 2))
                self.offset += (BLOCKSIZE * 2)
                # fill up the end with zero-blocks
                # (like option -b20 for tar does)
                blocks, remainder = divmod(self.offset, RECORDSIZE)
                if remainder > 0:
                    self.fileobj.write(NUL * (RECORDSIZE - remainder))
        finally:
            if not self._extfileobj:
                self.fileobj.close()

    def getmember(self, name):
        """Return a TarInfo object for member `name'. If `name' can not be
           found in the archive, KeyError is raised. If a member occurs more
           than once in the archive, its last occurrence is assumed to be the
           most up-to-date version.
        """
        tarinfo = self._getmember(name)
        if tarinfo is None:
            raise KeyError("filename %r not found" % name)
        return tarinfo

    def getmembers(self):
        """Return the members of the archive as a list of TarInfo objects. The
           list has the same order as the members in the archive.
        """
        self._check()
        if not self._loaded:    # if we want to obtain a list of
            self._load()        # all members, we first have to
                                # scan the whole archive.
        return self.members

    def getnames(self):
        """Return the members of the archive as a list of their names. It has
           the same order as the list returned by getmembers().
        """
        return [tarinfo.name for tarinfo in self.getmembers()]

    def gettarinfo(self, name=None, arcname=None, fileobj=None):
        """Create a TarInfo object from the result of os.stat or equivalent
           on an existing file. The file is either named by `name', or
           specified as a file object `fileobj' with a file descriptor. If
           given, `arcname' specifies an alternative name for the file in the
           archive, otherwise, the name is taken from the 'name' attribute of
           'fileobj', or the 'name' argument.
        """
        self._check("aw")

        # When fileobj is given, replace name by
        # fileobj's real name.
        if fileobj is not None:
            name = fileobj.name

        # Building the name of the member in the archive.
        # Backward slashes are converted to forward slashes,
        # Absolute paths are turned to relative paths.
        if arcname is None:
            arcname = name
        drv, arcname = os.path.splitdrive(arcname)
        arcname = arcname.replace(os.sep, "/")
        arcname = arcname.lstrip("/")

        # Now, fill the TarInfo object with
        # information specific for the file.
        tarinfo = self.tarinfo()
        tarinfo.tarfile = self  # Not needed

        # Use os.stat or os.lstat, depending on platform
        # and if symlinks shall be resolved.
        if fileobj is None:
            if hasattr(os, "lstat") and not self.dereference:
                statres = os.lstat(name)
            else:
                statres = os.stat(name)
        else:
            statres = os.fstat(fileobj.fileno())
        linkname = ""

        stmd = statres.st_mode
        if stat.S_ISREG(stmd):
            inode = (statres.st_ino, statres.st_dev)
            if not self.dereference and statres.st_nlink > 1 and \
                    inode in self.inodes and arcname != self.inodes[inode]:
                # Is it a hardlink to an already
                # archived file?
                type = LNKTYPE
                linkname = self.inodes[inode]
            else:
                # The inode is added only if its valid.
                # For win32 it is always 0.
                type = REGTYPE
                if inode[0]:
                    self.inodes[inode] = arcname
        elif stat.S_ISDIR(stmd):
            type = DIRTYPE
        elif stat.S_ISFIFO(stmd):
            type = FIFOTYPE
        elif stat.S_ISLNK(stmd):
            type = SYMTYPE
            linkname = os.readlink(name)
        elif stat.S_ISCHR(stmd):
            type = CHRTYPE
        elif stat.S_ISBLK(stmd):
            type = BLKTYPE
        else:
            return None

        # Fill the TarInfo object with all
        # information we can get.
        tarinfo.name = arcname
        tarinfo.mode = stmd
        tarinfo.uid = statres.st_uid
        tarinfo.gid = statres.st_gid
        if type == REGTYPE:
            tarinfo.size = statres.st_size
        else:
            tarinfo.size = 0L
        tarinfo.mtime = statres.st_mtime
        tarinfo.type = type
        tarinfo.linkname = linkname
        if pwd:
            try:
                tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0]
            except KeyError:
                pass
        if grp:
            try:
                tarinfo.gname = grp.getgrgid(tarinfo.gid)[0]
            except KeyError:
                pass

        if type in (CHRTYPE, BLKTYPE):
            if hasattr(os, "major") and hasattr(os, "minor"):
                tarinfo.devmajor = os.major(statres.st_rdev)
                tarinfo.devminor = os.minor(statres.st_rdev)
        return tarinfo

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

        for tarinfo in self:
            if verbose:
                print filemode(tarinfo.mode),
                print "%s/%s" % (tarinfo.uname or tarinfo.uid,
                                 tarinfo.gname or tarinfo.gid),
                if tarinfo.ischr() or tarinfo.isblk():
                    print "%10s" % ("%d,%d" \
                                    % (tarinfo.devmajor, tarinfo.devminor)),
                else:
                    print "%10d" % tarinfo.size,
                print "%d-%02d-%02d %02d:%02d:%02d" \
                      % time.localtime(tarinfo.mtime)[:6],

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

            if verbose:
                if tarinfo.issym():
                    print "->", tarinfo.linkname,
                if tarinfo.islnk():
                    print "link to", tarinfo.linkname,
            print

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

        if arcname is None:
            arcname = name

        # Exclude pathnames.
        if exclude is not None:
            import warnings
            warnings.warn("use the filter argument instead",
                    DeprecationWarning, 2)
            if exclude(name):
                self._dbg(2, "tarfile: Excluded %r" % name)
                return

        # Skip if somebody tries to archive the archive...
        if self.name is not None and os.path.abspath(name) == self.name:
            self._dbg(2, "tarfile: Skipped %r" % name)
            return

        self._dbg(1, name)

        # Create a TarInfo object from the file.
        tarinfo = self.gettarinfo(name, arcname)

        if tarinfo is None:
            self._dbg(1, "tarfile: Unsupported type %r" % name)
            return

        # Change or exclude the TarInfo object.
        if filter is not None:
            tarinfo = filter(tarinfo)
            if tarinfo is None:
                self._dbg(2, "tarfile: Excluded %r" % name)
                return

        # Append the tar header and data to the archive.
        if tarinfo.isreg():
            with bltn_open(name, "rb") as f:
                self.addfile(tarinfo, f)

        elif tarinfo.isdir():
            self.addfile(tarinfo)
            if recursive:
                for f in os.listdir(name):
                    self.add(os.path.join(name, f), os.path.join(arcname, f),
                            recursive, exclude, filter)

        else:
            self.addfile(tarinfo)

    def addfile(self, tarinfo, fileobj=None):
        """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is
           given, tarinfo.size bytes are read from it and added to the archive.
           You can create TarInfo objects directly, or by using gettarinfo().
           On Windows platforms, `fileobj' should always be opened with mode
           'rb' to avoid irritation about the file size.
        """
        self._check("aw")

        tarinfo = copy.copy(tarinfo)

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

        # If there's data to follow, append it.
        if fileobj is not None:
            copyfileobj(fileobj, self.fileobj, tarinfo.size)
            blocks, remainder = divmod(tarinfo.size, BLOCKSIZE)
            if remainder > 0:
                self.fileobj.write(NUL * (BLOCKSIZE - remainder))
                blocks += 1
            self.offset += blocks * BLOCKSIZE

        self.members.append(tarinfo)

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

        if members is None:
            members = self

        for tarinfo in members:
            if tarinfo.isdir():
                # Extract directories with a safe mode.
                directories.append(tarinfo)
                tarinfo = copy.copy(tarinfo)
                tarinfo.mode = 0700
            self.extract(tarinfo, path)

        # Reverse sort directories.
        directories.sort(key=operator.attrgetter('name'))
        directories.reverse()

        # Set correct owner, mtime and filemode on directories.
        for tarinfo in directories:
            dirpath = os.path.join(path, tarinfo.name)
            try:
                self.chown(tarinfo, dirpath)
                self.utime(tarinfo, dirpath)
                self.chmod(tarinfo, dirpath)
            except ExtractError, e:
                if self.errorlevel > 1:
                    raise
                else:
                    self._dbg(1, "tarfile: %s" % e)

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

        if isinstance(member, basestring):
            tarinfo = self.getmember(member)
        else:
            tarinfo = member

        # Prepare the link target for makelink().
        if tarinfo.islnk():
            tarinfo._link_target = os.path.join(path, tarinfo.linkname)

        try:
            self._extract_member(tarinfo, os.path.join(path, tarinfo.name))
        except EnvironmentError, e:
            if self.errorlevel > 0:
                raise
            else:
                if e.filename is None:
                    self._dbg(1, "tarfile: %s" % e.strerror)
                else:
                    self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename))
        except ExtractError, e:
            if self.errorlevel > 1:
                raise
            else:
                self._dbg(1, "tarfile: %s" % e)

    def extractfile(self, member):
        """Extract a member from the archive as a file object. `member' may be
           a filename or a TarInfo object. If `member' is a regular file, a
           file-like object is returned. If `member' is a link, a file-like
           object is constructed from the link's target. If `member' is none of
           the above, None is returned.
           The file-like object is read-only and provides the following
           methods: read(), readline(), readlines(), seek() and tell()
        """
        self._check("r")

        if isinstance(member, basestring):
            tarinfo = self.getmember(member)
        else:
            tarinfo = member

        if tarinfo.isreg():
            return self.fileobject(self, tarinfo)

        elif tarinfo.type not in SUPPORTED_TYPES:
            # If a member's type is unknown, it is treated as a
            # regular file.
            return self.fileobject(self, tarinfo)

        elif tarinfo.islnk() or tarinfo.issym():
            if isinstance(self.fileobj, _Stream):
                # A small but ugly workaround for the case that someone tries
                # to extract a (sym)link as a file-object from a non-seekable
                # stream of tar blocks.
                raise StreamError("cannot extract (sym)link as file object")
            else:
                # A (sym)link's file object is its target's file object.
                return self.extractfile(self._find_link_target(tarinfo))
        else:
            # If there's no data associated with the member (directory, chrdev,
            # blkdev, etc.), return None instead of a file object.
            return None

    def _extract_member(self, tarinfo, targetpath):
        """Extract the TarInfo object tarinfo to a physical
           file called targetpath.
        """
        # Fetch the TarInfo object for the given name
        # and build the destination pathname, replacing
        # forward slashes to platform specific separators.
        targetpath = targetpath.rstrip("/")
        targetpath = targetpath.replace("/", os.sep)

        # Create all upper directories.
        upperdirs = os.path.dirname(targetpath)
        if upperdirs and not os.path.exists(upperdirs):
            # Create directories that are not part of the archive with
            # default permissions.
            os.makedirs(upperdirs)

        if tarinfo.islnk() or tarinfo.issym():
            self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname))
        else:
            self._dbg(1, tarinfo.name)

        if tarinfo.isreg():
            self.makefile(tarinfo, targetpath)
        elif tarinfo.isdir():
            self.makedir(tarinfo, targetpath)
        elif tarinfo.isfifo():
            self.makefifo(tarinfo, targetpath)
        elif tarinfo.ischr() or tarinfo.isblk():
            self.makedev(tarinfo, targetpath)
        elif tarinfo.islnk() or tarinfo.issym():
            self.makelink(tarinfo, targetpath)
        elif tarinfo.type not in SUPPORTED_TYPES:
            self.makeunknown(tarinfo, targetpath)
        else:
            self.makefile(tarinfo, targetpath)

        self.chown(tarinfo, targetpath)
        if not tarinfo.issym():
            self.chmod(tarinfo, targetpath)
            self.utime(tarinfo, targetpath)

    #--------------------------------------------------------------------------
    # Below are the different file methods. They are called via
    # _extract_member() when extract() is called. They can be replaced in a
    # subclass to implement other functionality.

    def makedir(self, tarinfo, targetpath):
        """Make a directory called targetpath.
        """
        try:
            # Use a safe mode for the directory, the real mode is set
            # later in _extract_member().
            os.mkdir(targetpath, 0700)
        except EnvironmentError, e:
            if e.errno != errno.EEXIST:
                raise

    def makefile(self, tarinfo, targetpath):
        """Make a file called targetpath.
        """
        source = self.extractfile(tarinfo)
        try:
            with bltn_open(targetpath, "wb") as target:
                copyfileobj(source, target)
        finally:
            source.close()

    def makeunknown(self, tarinfo, targetpath):
        """Make a file from a TarInfo object with an unknown type
           at targetpath.
        """
        self.makefile(tarinfo, targetpath)
        self._dbg(1, "tarfile: Unknown file type %r, " \
                     "extracted as regular file." % tarinfo.type)

    def makefifo(self, tarinfo, targetpath):
        """Make a fifo called targetpath.
        """
        if hasattr(os, "mkfifo"):
            os.mkfifo(targetpath)
        else:
            raise ExtractError("fifo not supported by system")

    def makedev(self, tarinfo, targetpath):
        """Make a character or block device called targetpath.
        """
        if not hasattr(os, "mknod") or not hasattr(os, "makedev"):
            raise ExtractError("special devices not supported by system")

        mode = tarinfo.mode
        if tarinfo.isblk():
            mode |= stat.S_IFBLK
        else:
            mode |= stat.S_IFCHR

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

    def makelink(self, tarinfo, targetpath):
        """Make a (symbolic) link called targetpath. If it cannot be created
          (platform limitation), we try to make a copy of the referenced file
          instead of a link.
        """
        if hasattr(os, "symlink") and hasattr(os, "link"):
            # For systems that support symbolic and hard links.
            if tarinfo.issym():
                if os.path.lexists(targetpath):
                    os.unlink(targetpath)
                os.symlink(tarinfo.linkname, targetpath)
            else:
                # See extract().
                if os.path.exists(tarinfo._link_target):
                    if os.path.lexists(targetpath):
                        os.unlink(targetpath)
                    os.link(tarinfo._link_target, targetpath)
                else:
                    self._extract_member(self._find_link_target(tarinfo), targetpath)
        else:
            try:
                self._extract_member(self._find_link_target(tarinfo), targetpath)
            except KeyError:
                raise ExtractError("unable to resolve link inside archive")

    def chown(self, tarinfo, targetpath):
        """Set owner of targetpath according to tarinfo.
        """
        if pwd and hasattr(os, "geteuid") and os.geteuid() == 0:
            # We have to be root to do so.
            try:
                g = grp.getgrnam(tarinfo.gname)[2]
            except KeyError:
                g = tarinfo.gid
            try:
                u = pwd.getpwnam(tarinfo.uname)[2]
            except KeyError:
                u = tarinfo.uid
            try:
                if tarinfo.issym() and hasattr(os, "lchown"):
                    os.lchown(targetpath, u, g)
                else:
                    if sys.platform != "os2emx":
                        os.chown(targetpath, u, g)
            except EnvironmentError, e:
                raise ExtractError("could not change owner")

    def chmod(self, tarinfo, targetpath):
        """Set file permissions of targetpath according to tarinfo.
        """
        if hasattr(os, 'chmod'):
            try:
                os.chmod(targetpath, tarinfo.mode)
            except EnvironmentError, e:
                raise ExtractError("could not change mode")

    def utime(self, tarinfo, targetpath):
        """Set modification time of targetpath according to tarinfo.
        """
        if not hasattr(os, 'utime'):
            return
        try:
            os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime))
        except EnvironmentError, e:
            raise ExtractError("could not change modification time")

    #--------------------------------------------------------------------------
    def next(self):
        """Return the next member of the archive as a TarInfo object, when
           TarFile is opened for reading. Return None if there is no more
           available.
        """
        self._check("ra")
        if self.firstmember is not None:
            m = self.firstmember
            self.firstmember = None
            return m

        # Advance the file pointer.
        if self.offset != self.fileobj.tell():
            self.fileobj.seek(self.offset - 1)
            if not self.fileobj.read(1):
                raise ReadError("unexpected end of data")

        # Read the next block.
        tarinfo = None
        while True:
            try:
                tarinfo = self.tarinfo.fromtarfile(self)
            except EOFHeaderError, e:
                if self.ignore_zeros:
                    self._dbg(2, "0x%X: %s" % (self.offset, e))
                    self.offset += BLOCKSIZE
                    continue
            except InvalidHeaderError, e:
                if self.ignore_zeros:
                    self._dbg(2, "0x%X: %s" % (self.offset, e))
                    self.offset += BLOCKSIZE
                    continue
                elif self.offset == 0:
                    raise ReadError(str(e))
            except EmptyHeaderError:
                if self.offset == 0:
                    raise ReadError("empty file")
            except TruncatedHeaderError, e:
                if self.offset == 0:
                    raise ReadError(str(e))
            except SubsequentHeaderError, e:
                raise ReadError(str(e))
            break

        if tarinfo is not None:
            self.members.append(tarinfo)
        else:
            self._loaded = True

        return tarinfo

    #--------------------------------------------------------------------------
    # Little helper methods:

    def _getmember(self, name, tarinfo=None, normalize=False):
        """Find an archive member by name from bottom to top.
           If tarinfo is given, it is used as the starting point.
        """
        # Ensure that all members have been loaded.
        members = self.getmembers()

        # Limit the member search list up to tarinfo.
        if tarinfo is not None:
            members = members[:members.index(tarinfo)]

        if normalize:
            name = os.path.normpath(name)

        for member in reversed(members):
            if normalize:
                member_name = os.path.normpath(member.name)
            else:
                member_name = member.name

            if name == member_name:
                return member

    def _load(self):
        """Read through the entire archive file and look for readable
           members.
        """
        while True:
            tarinfo = self.next()
            if tarinfo is None:
                break
        self._loaded = True

    def _check(self, mode=None):
        """Check if TarFile is still open, and if the operation's mode
           corresponds to TarFile's mode.
        """
        if self.closed:
            raise IOError("%s is closed" % self.__class__.__name__)
        if mode is not None and self.mode not in mode:
            raise IOError("bad operation for mode %r" % self.mode)

    def _find_link_target(self, tarinfo):
        """Find the target member of a symlink or hardlink member in the
           archive.
        """
        if tarinfo.issym():
            # Always search the entire archive.
            linkname = "/".join(filter(None, (os.path.dirname(tarinfo.name), tarinfo.linkname)))
            limit = None
        else:
            # Search the archive before the link, because a hard link is
            # just a reference to an already archived file.
            linkname = tarinfo.linkname
            limit = tarinfo

        member = self._getmember(linkname, tarinfo=limit, normalize=True)
        if member is None:
            raise KeyError("linkname %r not found" % linkname)
        return member

    def __iter__(self):
        """Provide an iterator object.
        """
        if self._loaded:
            return iter(self.members)
        else:
            return TarIter(self)

    def _dbg(self, level, msg):
        """Write debugging output to sys.stderr.
        """
        if level <= self.debug:
            print >> sys.stderr, msg

    def __enter__(self):
        self._check()
        return self

    def __exit__(self, type, value, traceback):
        if type is None:
            self.close()
        else:
            # An exception occurred. We must not call close() because
            # it would try to write end-of-archive blocks and padding.
            if not self._extfileobj:
                self.fileobj.close()
            self.closed = True
# class TarFile

class TarIter:
    """Iterator Class.

       for tarinfo in TarFile(...):
           suite...
    """

    def __init__(self, tarfile):
        """Construct a TarIter object.
        """
        self.tarfile = tarfile
        self.index = 0
    def __iter__(self):
        """Return iterator object.
        """
        return self
    def next(self):
        """Return the next item using TarFile's next() method.
           When all members have been read, set TarFile as _loaded.
        """
        # Fix for SF #1100429: Under rare circumstances it can
        # happen that getmembers() is called during iteration,
        # which will cause TarIter to stop prematurely.

        if self.index == 0 and self.tarfile.firstmember is not None:
            tarinfo = self.tarfile.next()
        elif self.index < len(self.tarfile.members):
            tarinfo = self.tarfile.members[self.index]
        elif not self.tarfile._loaded:
            tarinfo = self.tarfile.next()
            if not tarinfo:
                self.tarfile._loaded = True
                raise StopIteration
        else:
            raise StopIteration
        self.index += 1
        return tarinfo

# Helper classes for sparse file support
class _section:
    """Base class for _data and _hole.
    """
    def __init__(self, offset, size):
        self.offset = offset
        self.size = size
    def __contains__(self, offset):
        return self.offset <= offset < self.offset + self.size

class _data(_section):
    """Represent a data section in a sparse file.
    """
    def __init__(self, offset, size, realpos):
        _section.__init__(self, offset, size)
        self.realpos = realpos

class _hole(_section):
    """Represent a hole section in a sparse file.
    """
    pass

class _ringbuffer(list):
    """Ringbuffer class which increases performance
       over a regular list.
    """
    def __init__(self):
        self.idx = 0
    def find(self, offset):
        idx = self.idx
        while True:
            item = self[idx]
            if offset in item:
                break
            idx += 1
            if idx == len(self):
                idx = 0
            if idx == self.idx:
                # End of File
                return None
        self.idx = idx
        return item

#---------------------------------------------
# zipfile compatible TarFile class
#---------------------------------------------
TAR_PLAIN = 0           # zipfile.ZIP_STORED
TAR_GZIPPED = 8         # zipfile.ZIP_DEFLATED
class TarFileCompat:
    """TarFile class compatible with standard module zipfile's
       ZipFile class.
    """
    def __init__(self, file, mode="r", compression=TAR_PLAIN):
        from warnings import warnpy3k
        warnpy3k("the TarFileCompat class has been removed in Python 3.0",
                stacklevel=2)
        if compression == TAR_PLAIN:
            self.tarfile = TarFile.taropen(file, mode)
        elif compression == TAR_GZIPPED:
            self.tarfile = TarFile.gzopen(file, mode)
        else:
            raise ValueError("unknown compression constant")
        if mode[0:1] == "r":
            members = self.tarfile.getmembers()
            for m in members:
                m.filename = m.name
                m.file_size = m.size
                m.date_time = time.gmtime(m.mtime)[:6]
    def namelist(self):
        return map(lambda m: m.name, self.infolist())
    def infolist(self):
        return filter(lambda m: m.type in REGULAR_TYPES,
                      self.tarfile.getmembers())
    def printdir(self):
        self.tarfile.list()
    def testzip(self):
        return
    def getinfo(self, name):
        return self.tarfile.getmember(name)
    def read(self, name):
        return self.tarfile.extractfile(self.tarfile.getmember(name)).read()
    def write(self, filename, arcname=None, compress_type=None):
        self.tarfile.add(filename, arcname)
    def writestr(self, zinfo, bytes):
        try:
            from cStringIO import StringIO
        except ImportError:
            from StringIO import StringIO
        import calendar
        tinfo = TarInfo(zinfo.filename)
        tinfo.size = len(bytes)
        tinfo.mtime = calendar.timegm(zinfo.date_time)
        self.tarfile.addfile(tinfo, StringIO(bytes))
    def close(self):
        self.tarfile.close()
#class TarFileCompat

#--------------------
# exported functions
#--------------------
def is_tarfile(name):
    """Return True if name points to a tar archive that we
       are able to handle, else return False.
    """
    try:
        t = open(name)
        t.close()
        return True
    except TarError:
        return False

open = TarFile.open

SILENT KILLER Tool