On Jul 18, 2006, at 17:17 , Apple Consultants Network wrote:
Dear List,
I am new to the list and new to python, so please be kind :) I've
recently started playing with duplicity (http://
duplicity.nongnu.org) and really like the feature set that is
offered by the project. However, I am being stung by the thorn in
Apple's side; resource forks. duplicity uses a copy of tarfile.py
to build the tar archives. And since this file does not call OS
X's tar, nor does it have support for resource forks, it will only
add data forks to the tar archive.
So, I started looking around and found that OS X has a tarfile.py
(System/Library/Frameworks/Python.framework/Versions/2.3/lib/
python2.3/) as part of the standard python install. This
tarfile.py is different from the one distributed by duplicity, and
at first I though I would use it in the distribution. However,
using this default install shows that it too does not respect
resource forks. For example, doing a simple:
#!/usr/bin/python
import tarfile
tar = tarfile.open("sample.tar", "w")
for name in ["Arial"]:
tar.add(name)
tar.close()
produces a tar file with only the data fork. The resource fork is
lost. In the case of fonts, this is bad.
You've got to explicitly handle the resource fork yourself. The tar
format (AFAIK) doesn't support any notion of extra metadata or forks
of a file. Tiger's tar fakes it by saving the resource fork as a
separate file with '._' added to the front (e.g., for 'hello.font',
it stores the data fork as 'hello.font', and the resource fork as
'._hello.font').
I've attached two scripts I wrote a while ago that handle the
resource forks in this way.
--
|>|\/|<
/------------------------------------------------------------------\
|David M. Cooke http://arbutus.physics.mcmaster.ca/dmc/
|[EMAIL PROTECTED]
#!/usr/bin/env python
import os
from os.path import join, getsize
import tarfile
import sys
import fnmatch
def add_files(tar, directory, root_as='', exclude_pats =[]):
def get_arcname(root, name):
if root.startswith(directory):
root = root_as + root[len(directory):]
return join(root, name)
def add_resource_fork(root, name):
rf = join(root, name, 'rsrc')
try:
s = getsize(rf)
except os.error:
pass
else:
if s != 0:
arcname = get_arcname(root, '._' + name)
tfi = tar.gettarinfo(rf, arcname)
fo = open(rf, 'rb')
tfi.type = tarfile.REGTYPE
tfi.size = s
try:
tar.addfile(tfi, fo)
except IOError, e:
print >>sys.stderr, '***%s (%s) %s' % (rf, arcname, e)
fo.close()
def add_file(root, name):
filename = join(root, name)
arcname = get_arcname(root, name)
for expat in exclude_pats:
if fnmatch.fnmatch(arcname, expat):
return False
try:
tar.add(filename, arcname, recursive=False)
except IOError, e:
print >>sys.stderr, '***%s (%s) %s' % (filename, arcname, e)
add_resource_fork(root, name)
return True
for root, dirs, files in os.walk(directory):
print >>sys.stderr, root
rec_dirs = []
for d in dirs:
if add_file(root, d):
rec_dirs.append(d)
dirs[:] = rec_dirs
for name in files:
add_file(root, name)
def main():
rootdir = sys.argv[1]
tfname = sys.argv[2]
expats = sys.argv[3:]
tar = tarfile.open(tfname, "w")
tar.posix=False
add_files(tar, rootdir, exclude_pats=expats)
tar.close()
if __name__ == '__main__':
main()
#!/usr/bin/env python
import os
import tarfile
import sys
def extract_files(tar, directory):
for tfi in tar:
print >>sys.stderr, tfi.name
head, tail = os.path.split(tfi.name)
if tail.startswith('._'):
# resource fork. We're depending on the data fork being
# extracted first, though.
name = tail[2:]
dfname = os.path.join(head, name)
if not os.path.exists(dfname):
fo = open(dfname, 'w')
fo.close()
tfi.name = os.path.join(head, name, 'rsrc')
tar.extract(tfi, directory)
def main():
tfname = sys.argv[1]
dirname = sys.argv[2]
if not os.path.isdir(dirname):
os.mkdir(dirname)
tar = tarfile.open(tfname, 'r')
extract_files(tar)
if __name__ == '__main__':
main()
_______________________________________________
Pythonmac-SIG maillist - Pythonmac-SIG@python.org
http://mail.python.org/mailman/listinfo/pythonmac-sig