summaryrefslogtreecommitdiffstats
path: root/Lib/plat-mac/macostools.py
blob: 3644e7ec0766423a672ee097d2d31773a2fdf880 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""macostools - Various utility functions for MacOS.

mkalias(src, dst) - Create a finder alias 'dst' pointing to 'src'
copy(src, dst) - Full copy of 'src' to 'dst'
"""

from Carbon import Res
from Carbon import File, Files
import os
import sys
import MacOS
import time
try:
    openrf = MacOS.openrf
except AttributeError:
    # Backward compatability
    openrf = open

Error = 'macostools.Error'

BUFSIZ=0x80000      # Copy in 0.5Mb chunks

COPY_FLAGS = (Files.kIsStationary|Files.kNameLocked|Files.kHasBundle|
              Files.kIsInvisible|Files.kIsAlias)

#
# Not guaranteed to be correct or stay correct (Apple doesn't tell you
# how to do this), but it seems to work.
#
def mkalias(src, dst, relative=None):
    """Create a finder alias"""
    srcfsr = File.FSRef(src)
    # The next line will fail under unix-Python if the destination
    # doesn't exist yet. We should change this code to be fsref-based.
    dstdir, dstname = os.path.split(dst)
    if not dstdir: dstdir = os.curdir
    dstdirfsr = File.FSRef(dstdir)
    if relative:
        relativefsr = File.FSRef(relative)
        # ik mag er geen None in stoppen :-(
        alias = File.FSNewAlias(relativefsr, srcfsr)
    else:
        alias = srcfsr.FSNewAliasMinimal()
    
    dstfsr, dstfss = Res.FSCreateResourceFile(dstdirfsr, unicode(dstname), 
        File.FSGetResourceForkName())
    h = Res.FSOpenResourceFile(dstfsr, File.FSGetResourceForkName(), 3)
    resource = Res.Resource(alias.data)
    resource.AddResource('alis', 0, '')
    Res.CloseResFile(h)
    
    dstfinfo = dstfss.FSpGetFInfo()
    dstfinfo.Flags = dstfinfo.Flags|0x8000    # Alias flag
    dstfss.FSpSetFInfo(dstfinfo)
    
def mkdirs(dst):
    """Make directories leading to 'dst' if they don't exist yet"""
    if dst == '' or os.path.exists(dst):
        return
    head, tail = os.path.split(dst)
    if os.sep == ':' and not ':' in head:
        head = head + ':'
    mkdirs(head)
    os.mkdir(dst, 0777)
    
def touched(dst):
    """Tell the finder a file has changed. No-op on MacOSX."""
    if sys.platform != 'mac': return
    import warnings
    warnings.filterwarnings("ignore", "macfs.*", DeprecationWarning, __name__)
    import macfs
    file_fss = macfs.FSSpec(dst)
    vRefNum, dirID, name = file_fss.as_tuple()
    dir_fss = macfs.FSSpec((vRefNum, dirID, ''))
    crdate, moddate, bkdate = dir_fss.GetDates()
    now = time.time()
    if now == moddate:
        now = now + 1
    try:
        dir_fss.SetDates(crdate, now, bkdate)
    except macfs.error:
        pass
    
def touched_ae(dst):
    """Tell the finder a file has changed"""
    pardir = os.path.split(dst)[0]
    if not pardir:
        pardir = os.curdir
    import Finder
    f = Finder.Finder()
    f.update(File.FSRef(pardir))
    
def copy(src, dst, createpath=0, copydates=1, forcetype=None):
    """Copy a file, including finder info, resource fork, etc"""
    src = File.pathname(src)
    dst = File.pathname(dst)
    if createpath:
        mkdirs(os.path.split(dst)[0])
    
    ifp = open(src, 'rb')
    ofp = open(dst, 'wb')
    d = ifp.read(BUFSIZ)
    while d:
        ofp.write(d)
        d = ifp.read(BUFSIZ)
    ifp.close()
    ofp.close()
    
    ifp = openrf(src, '*rb')
    ofp = openrf(dst, '*wb')
    d = ifp.read(BUFSIZ)
    while d:
        ofp.write(d)
        d = ifp.read(BUFSIZ)
    ifp.close()
    ofp.close()
    
    srcfss = File.FSSpec(src)
    dstfss = File.FSSpec(dst)
    sf = srcfss.FSpGetFInfo()
    df = dstfss.FSpGetFInfo()
    df.Creator, df.Type = sf.Creator, sf.Type
    if forcetype != None:
        df.Type = forcetype
    df.Flags = (sf.Flags & COPY_FLAGS)
    dstfss.FSpSetFInfo(df)
    if copydates:
        srcfsr = File.FSRef(src)
        dstfsr = File.FSRef(dst)
        catinfo, _, _, _ = srcfsr.FSGetCatalogInfo(Files.kFSCatInfoAllDates)
        dstfsr.FSSetCatalogInfo(Files.kFSCatInfoAllDates, catinfo)
    touched(dstfss)
    
def copytree(src, dst, copydates=1):
    """Copy a complete file tree to a new destination"""
    if os.path.isdir(src):
        mkdirs(dst)
        files = os.listdir(src)
        for f in files:
            copytree(os.path.join(src, f), os.path.join(dst, f), copydates)
    else:
        copy(src, dst, 1, copydates)