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

Reply via email to