dmg-builder 26.0.17 → 26.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/dmg.d.ts +33 -1
- package/out/dmg.js +7 -170
- package/out/dmg.js.map +1 -1
- package/out/dmgUtil.d.ts +16 -2
- package/out/dmgUtil.js +152 -1
- package/out/dmgUtil.js.map +1 -1
- package/out/hdiuil.js +1 -1
- package/out/hdiuil.js.map +1 -1
- package/package.json +3 -4
- package/vendor/biplist/__init__.py +75 -75
- package/vendor/dmgbuild/__init__.py +5 -0
- package/vendor/dmgbuild/__main__.py +67 -0
- package/vendor/dmgbuild/badge.py +104 -78
- package/vendor/dmgbuild/colors.py +239 -229
- package/vendor/dmgbuild/core.py +945 -274
- package/vendor/dmgbuild/licensing.py +329 -0
- package/vendor/dmgbuild/resources/builtin-arrow.tiff +0 -0
- package/vendor/ds_store/__init__.py +3 -1
- package/vendor/ds_store/__main__.py +102 -0
- package/vendor/ds_store/buddy.py +142 -134
- package/vendor/ds_store/store.py +333 -322
- package/vendor/mac_alias/__init__.py +43 -23
- package/vendor/mac_alias/alias.py +334 -224
- package/vendor/mac_alias/bookmark.py +283 -278
- package/vendor/mac_alias/osx.py +406 -302
- package/vendor/mac_alias/utils.py +10 -8
- package/vendor/run_dmgbuild.py +14 -0
|
@@ -1,39 +1,29 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
from __future__ import unicode_literals
|
|
3
|
-
from __future__ import division
|
|
4
|
-
|
|
5
|
-
import struct
|
|
6
1
|
import datetime
|
|
7
2
|
import io
|
|
8
|
-
import re
|
|
9
3
|
import os
|
|
10
4
|
import os.path
|
|
11
|
-
import
|
|
5
|
+
import struct
|
|
12
6
|
import sys
|
|
7
|
+
from unicodedata import normalize
|
|
13
8
|
|
|
14
|
-
if sys.platform ==
|
|
9
|
+
if sys.platform == "darwin":
|
|
15
10
|
from . import osx
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
long
|
|
19
|
-
except NameError:
|
|
20
|
-
long = int
|
|
21
|
-
|
|
22
|
-
from .utils import *
|
|
12
|
+
from .utils import mac_epoch
|
|
23
13
|
|
|
24
14
|
ALIAS_KIND_FILE = 0
|
|
25
15
|
ALIAS_KIND_FOLDER = 1
|
|
26
16
|
|
|
27
|
-
ALIAS_HFS_VOLUME_SIGNATURE = b
|
|
17
|
+
ALIAS_HFS_VOLUME_SIGNATURE = b"H+"
|
|
28
18
|
|
|
29
|
-
ALIAS_FILESYSTEM_UDF
|
|
30
|
-
ALIAS_FILESYSTEM_FAT32
|
|
31
|
-
ALIAS_FILESYSTEM_EXFAT
|
|
32
|
-
ALIAS_FILESYSTEM_HFSX
|
|
33
|
-
ALIAS_FILESYSTEM_HFSPLUS =
|
|
34
|
-
ALIAS_FILESYSTEM_FTP
|
|
35
|
-
ALIAS_FILESYSTEM_NTFS
|
|
36
|
-
ALIAS_FILESYSTEM_UNKNOWN =
|
|
19
|
+
ALIAS_FILESYSTEM_UDF = "UDF (CD/DVD)"
|
|
20
|
+
ALIAS_FILESYSTEM_FAT32 = "FAT32"
|
|
21
|
+
ALIAS_FILESYSTEM_EXFAT = "exFAT"
|
|
22
|
+
ALIAS_FILESYSTEM_HFSX = "HFSX"
|
|
23
|
+
ALIAS_FILESYSTEM_HFSPLUS = "HFS+"
|
|
24
|
+
ALIAS_FILESYSTEM_FTP = "FTP"
|
|
25
|
+
ALIAS_FILESYSTEM_NTFS = "NTFS"
|
|
26
|
+
ALIAS_FILESYSTEM_UNKNOWN = "unknown"
|
|
37
27
|
|
|
38
28
|
ALIAS_FIXED_DISK = 0
|
|
39
29
|
ALIAS_NETWORK_DISK = 1
|
|
@@ -42,34 +32,36 @@ ALIAS_800KB_FLOPPY_DISK = 3
|
|
|
42
32
|
ALIAS_1_44MB_FLOPPY_DISK = 4
|
|
43
33
|
ALIAS_EJECTABLE_DISK = 5
|
|
44
34
|
|
|
45
|
-
ALIAS_NO_CNID =
|
|
35
|
+
ALIAS_NO_CNID = 0xFFFFFFFF
|
|
46
36
|
|
|
47
37
|
ALIAS_FSTYPE_MAP = {
|
|
48
38
|
# Version 2 aliases
|
|
49
|
-
b
|
|
50
|
-
b
|
|
51
|
-
|
|
39
|
+
b"HX": ALIAS_FILESYSTEM_HFSX,
|
|
40
|
+
b"H+": ALIAS_FILESYSTEM_HFSPLUS,
|
|
52
41
|
# Version 3 aliases
|
|
53
|
-
b
|
|
54
|
-
b
|
|
55
|
-
b
|
|
56
|
-
b
|
|
57
|
-
b
|
|
58
|
-
b
|
|
59
|
-
b
|
|
42
|
+
b"BDcu": ALIAS_FILESYSTEM_UDF,
|
|
43
|
+
b"BDIS": ALIAS_FILESYSTEM_FAT32,
|
|
44
|
+
b"BDxF": ALIAS_FILESYSTEM_EXFAT,
|
|
45
|
+
b"HX\0\0": ALIAS_FILESYSTEM_HFSX,
|
|
46
|
+
b"H+\0\0": ALIAS_FILESYSTEM_HFSPLUS,
|
|
47
|
+
b"KG\0\0": ALIAS_FILESYSTEM_FTP,
|
|
48
|
+
b"NTcu": ALIAS_FILESYSTEM_NTFS,
|
|
60
49
|
}
|
|
61
50
|
|
|
51
|
+
|
|
62
52
|
def encode_utf8(s):
|
|
63
53
|
if isinstance(s, bytes):
|
|
64
54
|
return s
|
|
65
|
-
return s.encode(
|
|
55
|
+
return s.encode("utf-8")
|
|
56
|
+
|
|
66
57
|
|
|
67
58
|
def decode_utf8(s):
|
|
68
59
|
if isinstance(s, bytes):
|
|
69
|
-
return s.decode(
|
|
60
|
+
return s.decode("utf-8")
|
|
70
61
|
return s
|
|
71
62
|
|
|
72
|
-
|
|
63
|
+
|
|
64
|
+
class AppleShareInfo:
|
|
73
65
|
def __init__(self, zone=None, server=None, user=None):
|
|
74
66
|
#: The AppleShare zone
|
|
75
67
|
self.zone = zone
|
|
@@ -79,13 +71,27 @@ class AppleShareInfo (object):
|
|
|
79
71
|
self.user = user
|
|
80
72
|
|
|
81
73
|
def __repr__(self):
|
|
82
|
-
return
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
74
|
+
return "AppleShareInfo({!r},{!r},{!r})".format(
|
|
75
|
+
self.zone, self.server, self.user
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class VolumeInfo:
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
name,
|
|
83
|
+
creation_date,
|
|
84
|
+
fs_type,
|
|
85
|
+
disk_type,
|
|
86
|
+
attribute_flags,
|
|
87
|
+
fs_id,
|
|
88
|
+
appleshare_info=None,
|
|
89
|
+
driver_name=None,
|
|
90
|
+
posix_path=None,
|
|
91
|
+
disk_image_alias=None,
|
|
92
|
+
dialup_info=None,
|
|
93
|
+
network_mount_info=None,
|
|
94
|
+
):
|
|
89
95
|
#: The name of the volume on which the target resides
|
|
90
96
|
self.name = name
|
|
91
97
|
|
|
@@ -140,26 +146,52 @@ class VolumeInfo (object):
|
|
|
140
146
|
return ALIAS_FSTYPE_MAP.get(self.fs_type, ALIAS_FILESYSTEM_UNKNOWN)
|
|
141
147
|
|
|
142
148
|
def __repr__(self):
|
|
143
|
-
args = [
|
|
144
|
-
|
|
149
|
+
args = [
|
|
150
|
+
"name",
|
|
151
|
+
"creation_date",
|
|
152
|
+
"fs_type",
|
|
153
|
+
"disk_type",
|
|
154
|
+
"attribute_flags",
|
|
155
|
+
"fs_id",
|
|
156
|
+
]
|
|
145
157
|
values = []
|
|
146
158
|
for a in args:
|
|
147
159
|
v = getattr(self, a)
|
|
148
160
|
values.append(repr(v))
|
|
149
161
|
|
|
150
|
-
kwargs = [
|
|
151
|
-
|
|
162
|
+
kwargs = [
|
|
163
|
+
"appleshare_info",
|
|
164
|
+
"driver_name",
|
|
165
|
+
"posix_path",
|
|
166
|
+
"disk_image_alias",
|
|
167
|
+
"dialup_info",
|
|
168
|
+
"network_mount_info",
|
|
169
|
+
]
|
|
152
170
|
for a in kwargs:
|
|
153
171
|
v = getattr(self, a)
|
|
154
172
|
if v is not None:
|
|
155
|
-
values.append(
|
|
156
|
-
return
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
173
|
+
values.append(f"{a}={v!r}")
|
|
174
|
+
return "VolumeInfo(%s)" % ",".join(values)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class TargetInfo:
|
|
178
|
+
def __init__(
|
|
179
|
+
self,
|
|
180
|
+
kind,
|
|
181
|
+
filename,
|
|
182
|
+
folder_cnid,
|
|
183
|
+
cnid,
|
|
184
|
+
creation_date,
|
|
185
|
+
creator_code,
|
|
186
|
+
type_code,
|
|
187
|
+
levels_from=-1,
|
|
188
|
+
levels_to=-1,
|
|
189
|
+
folder_name=None,
|
|
190
|
+
cnid_path=None,
|
|
191
|
+
carbon_path=None,
|
|
192
|
+
posix_path=None,
|
|
193
|
+
user_home_prefix_len=None,
|
|
194
|
+
):
|
|
163
195
|
#: Either ALIAS_KIND_FILE or ALIAS_KIND_FOLDER
|
|
164
196
|
self.kind = kind
|
|
165
197
|
|
|
@@ -208,25 +240,38 @@ class TargetInfo (object):
|
|
|
208
240
|
self.user_home_prefix_len = user_home_prefix_len
|
|
209
241
|
|
|
210
242
|
def __repr__(self):
|
|
211
|
-
args = [
|
|
212
|
-
|
|
243
|
+
args = [
|
|
244
|
+
"kind",
|
|
245
|
+
"filename",
|
|
246
|
+
"folder_cnid",
|
|
247
|
+
"cnid",
|
|
248
|
+
"creation_date",
|
|
249
|
+
"creator_code",
|
|
250
|
+
"type_code",
|
|
251
|
+
]
|
|
213
252
|
values = []
|
|
214
253
|
for a in args:
|
|
215
254
|
v = getattr(self, a)
|
|
216
255
|
values.append(repr(v))
|
|
217
256
|
|
|
218
257
|
if self.levels_from != -1:
|
|
219
|
-
values.append(
|
|
258
|
+
values.append("levels_from=%r" % self.levels_from)
|
|
220
259
|
if self.levels_to != -1:
|
|
221
|
-
values.append(
|
|
222
|
-
|
|
223
|
-
kwargs = [
|
|
224
|
-
|
|
260
|
+
values.append("levels_to=%r" % self.levels_to)
|
|
261
|
+
|
|
262
|
+
kwargs = [
|
|
263
|
+
"folder_name",
|
|
264
|
+
"cnid_path",
|
|
265
|
+
"carbon_path",
|
|
266
|
+
"posix_path",
|
|
267
|
+
"user_home_prefix_len",
|
|
268
|
+
]
|
|
225
269
|
for a in kwargs:
|
|
226
270
|
v = getattr(self, a)
|
|
227
|
-
values.append(
|
|
271
|
+
values.append(f"{a}={v!r}")
|
|
272
|
+
|
|
273
|
+
return "TargetInfo(%s)" % ",".join(values)
|
|
228
274
|
|
|
229
|
-
return 'TargetInfo(%s)' % ','.join(values)
|
|
230
275
|
|
|
231
276
|
TAG_CARBON_FOLDER_NAME = 0
|
|
232
277
|
TAG_CNID_PATH = 1
|
|
@@ -246,9 +291,16 @@ TAG_POSIX_PATH_TO_MOUNTPOINT = 19
|
|
|
246
291
|
TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE = 20
|
|
247
292
|
TAG_USER_HOME_LENGTH_PREFIX = 21
|
|
248
293
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
294
|
+
|
|
295
|
+
class Alias:
|
|
296
|
+
def __init__(
|
|
297
|
+
self,
|
|
298
|
+
appinfo=b"\0\0\0\0",
|
|
299
|
+
version=2,
|
|
300
|
+
volume=None,
|
|
301
|
+
target=None,
|
|
302
|
+
extra=[],
|
|
303
|
+
):
|
|
252
304
|
"""Construct a new :class:`Alias` object with the specified
|
|
253
305
|
contents."""
|
|
254
306
|
|
|
@@ -269,26 +321,48 @@ class Alias (object):
|
|
|
269
321
|
|
|
270
322
|
@classmethod
|
|
271
323
|
def _from_fd(cls, b):
|
|
272
|
-
appinfo, recsize, version = struct.unpack(b
|
|
324
|
+
appinfo, recsize, version = struct.unpack(b">4shh", b.read(8))
|
|
273
325
|
|
|
274
326
|
if recsize < 150:
|
|
275
|
-
raise ValueError(
|
|
327
|
+
raise ValueError("Incorrect alias length")
|
|
276
328
|
|
|
277
329
|
if version not in (2, 3):
|
|
278
|
-
raise ValueError(
|
|
330
|
+
raise ValueError("Unsupported alias version %u" % version)
|
|
279
331
|
|
|
280
332
|
if version == 2:
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
333
|
+
(
|
|
334
|
+
kind, # h
|
|
335
|
+
volname, # 28p
|
|
336
|
+
voldate, # I
|
|
337
|
+
fstype, # 2s
|
|
338
|
+
disktype, # h
|
|
339
|
+
folder_cnid, # I
|
|
340
|
+
filename, # 64p
|
|
341
|
+
cnid, # I
|
|
342
|
+
crdate, # I
|
|
343
|
+
creator_code, # 4s
|
|
344
|
+
type_code, # 4s
|
|
345
|
+
levels_from, # h
|
|
346
|
+
levels_to, # h
|
|
347
|
+
volattrs, # I
|
|
348
|
+
volfsid, # 2s
|
|
349
|
+
reserved, # 10s
|
|
350
|
+
) = struct.unpack(b">h28pI2shI64pII4s4shhI2s10s", b.read(142))
|
|
285
351
|
else:
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
352
|
+
(
|
|
353
|
+
kind, # h
|
|
354
|
+
voldate_hr, # Q
|
|
355
|
+
fstype, # 4s
|
|
356
|
+
disktype, # h
|
|
357
|
+
folder_cnid, # I
|
|
358
|
+
cnid, # I
|
|
359
|
+
crdate_hr, # Q
|
|
360
|
+
volattrs, # I
|
|
361
|
+
reserved, # 14s
|
|
362
|
+
) = struct.unpack(b">hQ4shIIQI14s", b.read(46))
|
|
363
|
+
|
|
364
|
+
volname = b""
|
|
365
|
+
filename = b""
|
|
292
366
|
creator_code = None
|
|
293
367
|
type_code = None
|
|
294
368
|
voldate = voldate_hr / 65536.0
|
|
@@ -300,28 +374,38 @@ class Alias (object):
|
|
|
300
374
|
alias = Alias()
|
|
301
375
|
alias.appinfo = appinfo
|
|
302
376
|
|
|
303
|
-
alias.volume = VolumeInfo
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
377
|
+
alias.volume = VolumeInfo(
|
|
378
|
+
volname.decode().replace("/", ":"),
|
|
379
|
+
voldate,
|
|
380
|
+
fstype,
|
|
381
|
+
disktype,
|
|
382
|
+
volattrs,
|
|
383
|
+
volfsid,
|
|
384
|
+
)
|
|
385
|
+
alias.target = TargetInfo(
|
|
386
|
+
kind,
|
|
387
|
+
filename.decode().replace("/", ":"),
|
|
388
|
+
folder_cnid,
|
|
389
|
+
cnid,
|
|
390
|
+
crdate,
|
|
391
|
+
creator_code,
|
|
392
|
+
type_code,
|
|
393
|
+
)
|
|
309
394
|
alias.target.levels_from = levels_from
|
|
310
395
|
alias.target.levels_to = levels_to
|
|
311
396
|
|
|
312
|
-
tag = struct.unpack(b
|
|
397
|
+
tag = struct.unpack(b">h", b.read(2))[0]
|
|
313
398
|
|
|
314
399
|
while tag != -1:
|
|
315
|
-
length = struct.unpack(b
|
|
400
|
+
length = struct.unpack(b">h", b.read(2))[0]
|
|
316
401
|
value = b.read(length)
|
|
317
402
|
if length & 1:
|
|
318
403
|
b.read(1)
|
|
319
404
|
|
|
320
405
|
if tag == TAG_CARBON_FOLDER_NAME:
|
|
321
|
-
alias.target.folder_name = value.decode().replace(
|
|
406
|
+
alias.target.folder_name = value.decode().replace("/", ":")
|
|
322
407
|
elif tag == TAG_CNID_PATH:
|
|
323
|
-
alias.target.cnid_path = struct.unpack(
|
|
324
|
-
value)
|
|
408
|
+
alias.target.cnid_path = struct.unpack(">%uI" % (length // 4), value)
|
|
325
409
|
elif tag == TAG_CARBON_PATH:
|
|
326
410
|
alias.target.carbon_path = value
|
|
327
411
|
elif tag == TAG_APPLESHARE_ZONE:
|
|
@@ -343,17 +427,19 @@ class Alias (object):
|
|
|
343
427
|
elif tag == TAG_DIALUP_INFO:
|
|
344
428
|
alias.volume.dialup_info = value
|
|
345
429
|
elif tag == TAG_UNICODE_FILENAME:
|
|
346
|
-
alias.target.filename = value[2:].decode(
|
|
430
|
+
alias.target.filename = value[2:].decode("utf-16be")
|
|
347
431
|
elif tag == TAG_UNICODE_VOLUME_NAME:
|
|
348
|
-
alias.volume.name = value[2:].decode(
|
|
432
|
+
alias.volume.name = value[2:].decode("utf-16be")
|
|
349
433
|
elif tag == TAG_HIGH_RES_VOLUME_CREATION_DATE:
|
|
350
|
-
seconds = struct.unpack(b
|
|
351
|
-
alias.volume.creation_date
|
|
352
|
-
|
|
434
|
+
seconds = struct.unpack(b">Q", value)[0] / 65536.0
|
|
435
|
+
alias.volume.creation_date = mac_epoch + datetime.timedelta(
|
|
436
|
+
seconds=seconds
|
|
437
|
+
)
|
|
353
438
|
elif tag == TAG_HIGH_RES_CREATION_DATE:
|
|
354
|
-
seconds = struct.unpack(b
|
|
355
|
-
alias.target.creation_date
|
|
356
|
-
|
|
439
|
+
seconds = struct.unpack(b">Q", value)[0] / 65536.0
|
|
440
|
+
alias.target.creation_date = mac_epoch + datetime.timedelta(
|
|
441
|
+
seconds=seconds
|
|
442
|
+
)
|
|
357
443
|
elif tag == TAG_POSIX_PATH:
|
|
358
444
|
alias.target.posix_path = value.decode()
|
|
359
445
|
elif tag == TAG_POSIX_PATH_TO_MOUNTPOINT:
|
|
@@ -361,11 +447,11 @@ class Alias (object):
|
|
|
361
447
|
elif tag == TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE:
|
|
362
448
|
alias.volume.disk_image_alias = Alias.from_bytes(value)
|
|
363
449
|
elif tag == TAG_USER_HOME_LENGTH_PREFIX:
|
|
364
|
-
alias.target.user_home_prefix_len = struct.unpack(b
|
|
450
|
+
alias.target.user_home_prefix_len = struct.unpack(b">h", value)[0]
|
|
365
451
|
else:
|
|
366
452
|
alias.extra.append((tag, value))
|
|
367
453
|
|
|
368
|
-
tag = struct.unpack(b
|
|
454
|
+
tag = struct.unpack(b">h", b.read(2))[0]
|
|
369
455
|
|
|
370
456
|
return alias
|
|
371
457
|
|
|
@@ -378,8 +464,8 @@ class Alias (object):
|
|
|
378
464
|
@classmethod
|
|
379
465
|
def for_file(cls, path):
|
|
380
466
|
"""Create an :class:`Alias` that points at the specified file."""
|
|
381
|
-
if sys.platform !=
|
|
382
|
-
raise Exception(
|
|
467
|
+
if sys.platform != "darwin":
|
|
468
|
+
raise Exception("Not implemented (requires special support)")
|
|
383
469
|
|
|
384
470
|
path = encode_utf8(path)
|
|
385
471
|
|
|
@@ -389,21 +475,29 @@ class Alias (object):
|
|
|
389
475
|
st = osx.statfs(path)
|
|
390
476
|
vol_path = st.f_mntonname
|
|
391
477
|
|
|
478
|
+
# File and folder names in HFS+ are normalized to a form similar to NFD.
|
|
479
|
+
# Must be normalized (NFD->NFC) before use to avoid unicode string comparison issues.
|
|
480
|
+
vol_path = normalize("NFC", vol_path.decode("utf-8")).encode("utf-8")
|
|
481
|
+
|
|
392
482
|
# Grab its attributes
|
|
393
|
-
attrs = [osx.ATTR_CMN_CRTIME,
|
|
394
|
-
osx.ATTR_VOL_NAME,
|
|
395
|
-
0, 0, 0]
|
|
483
|
+
attrs = [osx.ATTR_CMN_CRTIME, osx.ATTR_VOL_NAME, 0, 0, 0]
|
|
396
484
|
volinfo = osx.getattrlist(vol_path, attrs, 0)
|
|
397
485
|
|
|
398
486
|
vol_crtime = volinfo[0]
|
|
399
487
|
vol_name = encode_utf8(volinfo[1])
|
|
400
488
|
|
|
401
489
|
# Also grab various attributes of the file
|
|
402
|
-
attrs = [
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
490
|
+
attrs = [
|
|
491
|
+
osx.ATTR_CMN_OBJTYPE
|
|
492
|
+
| osx.ATTR_CMN_CRTIME
|
|
493
|
+
| osx.ATTR_CMN_FNDRINFO
|
|
494
|
+
| osx.ATTR_CMN_FILEID
|
|
495
|
+
| osx.ATTR_CMN_PARENTID,
|
|
496
|
+
0,
|
|
497
|
+
0,
|
|
498
|
+
0,
|
|
499
|
+
0,
|
|
500
|
+
]
|
|
407
501
|
info = osx.getattrlist(path, attrs, osx.FSOPT_NOFOLLOW)
|
|
408
502
|
|
|
409
503
|
if info[0] == osx.VDIR:
|
|
@@ -416,7 +510,7 @@ class Alias (object):
|
|
|
416
510
|
|
|
417
511
|
dirname, filename = os.path.split(path)
|
|
418
512
|
|
|
419
|
-
if dirname == b
|
|
513
|
+
if dirname == b"" or dirname == b".":
|
|
420
514
|
dirname = os.getcwd()
|
|
421
515
|
|
|
422
516
|
foldername = os.path.basename(dirname)
|
|
@@ -424,16 +518,16 @@ class Alias (object):
|
|
|
424
518
|
creation_date = info[1]
|
|
425
519
|
|
|
426
520
|
if kind == ALIAS_KIND_FILE:
|
|
427
|
-
creator_code = struct.pack(b
|
|
428
|
-
type_code = struct.pack(b
|
|
521
|
+
creator_code = struct.pack(b"I", info[2].fileInfo.fileCreator)
|
|
522
|
+
type_code = struct.pack(b"I", info[2].fileInfo.fileType)
|
|
429
523
|
else:
|
|
430
|
-
creator_code = b
|
|
431
|
-
type_code = b
|
|
524
|
+
creator_code = b"\0\0\0\0"
|
|
525
|
+
type_code = b"\0\0\0\0"
|
|
432
526
|
|
|
433
|
-
a.target = TargetInfo(
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
527
|
+
a.target = TargetInfo(
|
|
528
|
+
kind, filename, folder_cnid, cnid, creation_date, creator_code, type_code
|
|
529
|
+
)
|
|
530
|
+
a.volume = VolumeInfo(vol_name, vol_crtime, b"H+", ALIAS_FIXED_DISK, 0, b"\0\0")
|
|
437
531
|
|
|
438
532
|
a.target.folder_name = foldername
|
|
439
533
|
a.volume.posix_path = vol_path
|
|
@@ -441,10 +535,10 @@ class Alias (object):
|
|
|
441
535
|
rel_path = os.path.relpath(path, vol_path)
|
|
442
536
|
|
|
443
537
|
# Leave off the initial '/' if vol_path is '/' (no idea why)
|
|
444
|
-
if vol_path == b
|
|
538
|
+
if vol_path == b"/":
|
|
445
539
|
a.target.posix_path = rel_path
|
|
446
540
|
else:
|
|
447
|
-
a.target.posix_path = b
|
|
541
|
+
a.target.posix_path = b"/" + rel_path
|
|
448
542
|
|
|
449
543
|
# Construct the Carbon and CNID paths
|
|
450
544
|
carbon_path = []
|
|
@@ -457,11 +551,11 @@ class Alias (object):
|
|
|
457
551
|
attrs = [osx.ATTR_CMN_FILEID, 0, 0, 0, 0]
|
|
458
552
|
info = osx.getattrlist(os.path.join(vol_path, head), attrs, 0)
|
|
459
553
|
cnid_path.append(info[0])
|
|
460
|
-
carbon_tail = tail.replace(b
|
|
554
|
+
carbon_tail = tail.replace(b":", b"/")
|
|
461
555
|
carbon_path.insert(0, carbon_tail)
|
|
462
556
|
head, tail = os.path.split(head)
|
|
463
557
|
|
|
464
|
-
carbon_path = vol_name + b
|
|
558
|
+
carbon_path = vol_name + b":" + b":\0".join(carbon_path)
|
|
465
559
|
|
|
466
560
|
a.target.carbon_path = carbon_path
|
|
467
561
|
a.target.cnid_path = cnid_path
|
|
@@ -471,172 +565,188 @@ class Alias (object):
|
|
|
471
565
|
def _to_fd(self, b):
|
|
472
566
|
# We'll come back and fix the length when we're done
|
|
473
567
|
pos = b.tell()
|
|
474
|
-
b.write(struct.pack(b
|
|
568
|
+
b.write(struct.pack(b">4shh", self.appinfo, 0, self.version))
|
|
475
569
|
|
|
476
|
-
carbon_volname = encode_utf8(self.volume.name).replace(b
|
|
477
|
-
carbon_filename = encode_utf8(self.target.filename).replace(b
|
|
570
|
+
carbon_volname = encode_utf8(self.volume.name).replace(b":", b"/")
|
|
571
|
+
carbon_filename = encode_utf8(self.target.filename).replace(b":", b"/")
|
|
478
572
|
voldate = (self.volume.creation_date - mac_epoch).total_seconds()
|
|
479
573
|
crdate = (self.target.creation_date - mac_epoch).total_seconds()
|
|
480
574
|
|
|
481
575
|
if self.version == 2:
|
|
482
576
|
# NOTE: crdate should be in local time, but that's system dependent
|
|
483
577
|
# (so doing so is ridiculous, and nothing could rely on it).
|
|
484
|
-
b.write(
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
578
|
+
b.write(
|
|
579
|
+
struct.pack(
|
|
580
|
+
b">h28pI2shI64pII4s4shhI2s10s",
|
|
581
|
+
self.target.kind, # h
|
|
582
|
+
carbon_volname, # 28p
|
|
583
|
+
int(voldate), # I
|
|
584
|
+
self.volume.fs_type, # 2s
|
|
585
|
+
self.volume.disk_type, # h
|
|
586
|
+
self.target.folder_cnid, # I
|
|
587
|
+
carbon_filename, # 64p
|
|
588
|
+
self.target.cnid, # I
|
|
589
|
+
int(crdate), # I
|
|
590
|
+
self.target.creator_code, # 4s
|
|
591
|
+
self.target.type_code, # 4s
|
|
592
|
+
self.target.levels_from, # h
|
|
593
|
+
self.target.levels_to, # h
|
|
594
|
+
self.volume.attribute_flags, # I
|
|
595
|
+
self.volume.fs_id, # 2s
|
|
596
|
+
b"\0" * 10, # 10s
|
|
597
|
+
)
|
|
598
|
+
)
|
|
500
599
|
else:
|
|
501
|
-
b.write(
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
600
|
+
b.write(
|
|
601
|
+
struct.pack(
|
|
602
|
+
b">hQ4shIIQI14s",
|
|
603
|
+
self.target.kind, # h
|
|
604
|
+
int(voldate * 65536), # Q
|
|
605
|
+
self.volume.fs_type, # 4s
|
|
606
|
+
self.volume.disk_type, # h
|
|
607
|
+
self.target.folder_cnid, # I
|
|
608
|
+
self.target.cnid, # I
|
|
609
|
+
int(crdate * 65536), # Q
|
|
610
|
+
self.volume.attribute_flags, # I
|
|
611
|
+
b"\0" * 14, # 14s
|
|
612
|
+
)
|
|
613
|
+
)
|
|
512
614
|
|
|
513
615
|
# Excuse the odd order; we're copying Finder
|
|
514
616
|
if self.target.folder_name:
|
|
515
|
-
carbon_foldername = encode_utf8(self.target.folder_name)
|
|
516
|
-
|
|
517
|
-
b.write(struct.pack(b'>hh', TAG_CARBON_FOLDER_NAME,
|
|
518
|
-
len(carbon_foldername)))
|
|
617
|
+
carbon_foldername = encode_utf8(self.target.folder_name).replace(b":", b"/")
|
|
618
|
+
b.write(struct.pack(b">hh", TAG_CARBON_FOLDER_NAME, len(carbon_foldername)))
|
|
519
619
|
b.write(carbon_foldername)
|
|
520
620
|
if len(carbon_foldername) & 1:
|
|
521
|
-
b.write(b
|
|
621
|
+
b.write(b"\0")
|
|
522
622
|
|
|
523
|
-
b.write(
|
|
623
|
+
b.write(
|
|
624
|
+
struct.pack(
|
|
625
|
+
b">hhQhhQ",
|
|
524
626
|
TAG_HIGH_RES_VOLUME_CREATION_DATE,
|
|
525
|
-
8,
|
|
627
|
+
8,
|
|
628
|
+
int(voldate * 65536),
|
|
526
629
|
TAG_HIGH_RES_CREATION_DATE,
|
|
527
|
-
8,
|
|
630
|
+
8,
|
|
631
|
+
int(crdate * 65536),
|
|
632
|
+
)
|
|
633
|
+
)
|
|
528
634
|
|
|
529
635
|
if self.target.cnid_path:
|
|
530
|
-
cnid_path = struct.pack(
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
636
|
+
cnid_path = struct.pack(
|
|
637
|
+
">%uI" % len(self.target.cnid_path), *self.target.cnid_path
|
|
638
|
+
)
|
|
639
|
+
b.write(struct.pack(b">hh", TAG_CNID_PATH, len(cnid_path)))
|
|
534
640
|
b.write(cnid_path)
|
|
535
641
|
|
|
536
642
|
if self.target.carbon_path:
|
|
537
|
-
carbon_path=encode_utf8(self.target.carbon_path)
|
|
538
|
-
b.write(struct.pack(b
|
|
539
|
-
len(carbon_path)))
|
|
643
|
+
carbon_path = encode_utf8(self.target.carbon_path)
|
|
644
|
+
b.write(struct.pack(b">hh", TAG_CARBON_PATH, len(carbon_path)))
|
|
540
645
|
b.write(carbon_path)
|
|
541
646
|
if len(carbon_path) & 1:
|
|
542
|
-
b.write(b
|
|
647
|
+
b.write(b"\0")
|
|
543
648
|
|
|
544
649
|
if self.volume.appleshare_info:
|
|
545
650
|
ai = self.volume.appleshare_info
|
|
546
651
|
if ai.zone:
|
|
547
|
-
b.write(struct.pack(b
|
|
548
|
-
len(ai.zone)))
|
|
652
|
+
b.write(struct.pack(b">hh", TAG_APPLESHARE_ZONE, len(ai.zone)))
|
|
549
653
|
b.write(ai.zone)
|
|
550
654
|
if len(ai.zone) & 1:
|
|
551
|
-
b.write(b
|
|
655
|
+
b.write(b"\0")
|
|
552
656
|
if ai.server:
|
|
553
|
-
b.write(struct.pack(b
|
|
554
|
-
len(ai.server)))
|
|
657
|
+
b.write(struct.pack(b">hh", TAG_APPLESHARE_SERVER_NAME, len(ai.server)))
|
|
555
658
|
b.write(ai.server)
|
|
556
659
|
if len(ai.server) & 1:
|
|
557
|
-
b.write(b
|
|
660
|
+
b.write(b"\0")
|
|
558
661
|
if ai.username:
|
|
559
|
-
b.write(struct.pack(b
|
|
560
|
-
len(ai.username)))
|
|
662
|
+
b.write(struct.pack(b">hh", TAG_APPLESHARE_USERNAME, len(ai.username)))
|
|
561
663
|
b.write(ai.username)
|
|
562
664
|
if len(ai.username) & 1:
|
|
563
|
-
b.write(b
|
|
665
|
+
b.write(b"\0")
|
|
564
666
|
|
|
565
667
|
if self.volume.driver_name:
|
|
566
668
|
driver_name = encode_utf8(self.volume.driver_name)
|
|
567
|
-
b.write(struct.pack(b
|
|
568
|
-
len(driver_name)))
|
|
669
|
+
b.write(struct.pack(b">hh", TAG_DRIVER_NAME, len(driver_name)))
|
|
569
670
|
b.write(driver_name)
|
|
570
671
|
if len(driver_name) & 1:
|
|
571
|
-
b.write(b
|
|
672
|
+
b.write(b"\0")
|
|
572
673
|
|
|
573
674
|
if self.volume.network_mount_info:
|
|
574
|
-
b.write(
|
|
575
|
-
|
|
675
|
+
b.write(
|
|
676
|
+
struct.pack(
|
|
677
|
+
b">hh", TAG_NETWORK_MOUNT_INFO, len(self.volume.network_mount_info)
|
|
678
|
+
)
|
|
679
|
+
)
|
|
576
680
|
b.write(self.volume.network_mount_info)
|
|
577
681
|
if len(self.volume.network_mount_info) & 1:
|
|
578
|
-
b.write(b
|
|
682
|
+
b.write(b"\0")
|
|
579
683
|
|
|
580
684
|
if self.volume.dialup_info:
|
|
581
|
-
b.write(
|
|
582
|
-
|
|
685
|
+
b.write(
|
|
686
|
+
struct.pack(
|
|
687
|
+
b">hh", TAG_DIALUP_INFO, len(self.volume.network_mount_info)
|
|
688
|
+
)
|
|
689
|
+
)
|
|
583
690
|
b.write(self.volume.network_mount_info)
|
|
584
691
|
if len(self.volume.network_mount_info) & 1:
|
|
585
|
-
b.write(b
|
|
692
|
+
b.write(b"\0")
|
|
586
693
|
|
|
587
|
-
utf16 = decode_utf8(self.target.filename)
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
len(utf16) // 2))
|
|
694
|
+
utf16 = decode_utf8(self.target.filename).replace(":", "/").encode("utf-16-be")
|
|
695
|
+
b.write(
|
|
696
|
+
struct.pack(b">hhh", TAG_UNICODE_FILENAME, len(utf16) + 2, len(utf16) // 2)
|
|
697
|
+
)
|
|
592
698
|
b.write(utf16)
|
|
593
699
|
|
|
594
|
-
utf16 = decode_utf8(self.volume.name)
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
700
|
+
utf16 = decode_utf8(self.volume.name).replace(":", "/").encode("utf-16-be")
|
|
701
|
+
b.write(
|
|
702
|
+
struct.pack(
|
|
703
|
+
b">hhh", TAG_UNICODE_VOLUME_NAME, len(utf16) + 2, len(utf16) // 2
|
|
704
|
+
)
|
|
705
|
+
)
|
|
599
706
|
b.write(utf16)
|
|
600
707
|
|
|
601
708
|
if self.target.posix_path:
|
|
602
709
|
posix_path = encode_utf8(self.target.posix_path)
|
|
603
|
-
b.write(struct.pack(b
|
|
604
|
-
len(posix_path)))
|
|
710
|
+
b.write(struct.pack(b">hh", TAG_POSIX_PATH, len(posix_path)))
|
|
605
711
|
b.write(posix_path)
|
|
606
712
|
if len(posix_path) & 1:
|
|
607
|
-
b.write(b
|
|
713
|
+
b.write(b"\0")
|
|
608
714
|
|
|
609
715
|
if self.volume.posix_path:
|
|
610
716
|
posix_path = encode_utf8(self.volume.posix_path)
|
|
611
|
-
b.write(struct.pack(b
|
|
612
|
-
len(posix_path)))
|
|
717
|
+
b.write(struct.pack(b">hh", TAG_POSIX_PATH_TO_MOUNTPOINT, len(posix_path)))
|
|
613
718
|
b.write(posix_path)
|
|
614
719
|
if len(posix_path) & 1:
|
|
615
|
-
b.write(b
|
|
720
|
+
b.write(b"\0")
|
|
616
721
|
|
|
617
722
|
if self.volume.disk_image_alias:
|
|
618
723
|
d = self.volume.disk_image_alias.to_bytes()
|
|
619
|
-
b.write(struct.pack(b
|
|
620
|
-
len(d)))
|
|
724
|
+
b.write(struct.pack(b">hh", TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE, len(d)))
|
|
621
725
|
b.write(d)
|
|
622
726
|
if len(d) & 1:
|
|
623
|
-
b.write(b
|
|
727
|
+
b.write(b"\0")
|
|
624
728
|
|
|
625
729
|
if self.target.user_home_prefix_len is not None:
|
|
626
|
-
b.write(
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
730
|
+
b.write(
|
|
731
|
+
struct.pack(
|
|
732
|
+
b">hhh",
|
|
733
|
+
TAG_USER_HOME_LENGTH_PREFIX,
|
|
734
|
+
2,
|
|
735
|
+
self.target.user_home_prefix_len,
|
|
736
|
+
)
|
|
737
|
+
)
|
|
738
|
+
|
|
739
|
+
for t, v in self.extra:
|
|
740
|
+
b.write(struct.pack(b">hh", t, len(v)))
|
|
631
741
|
b.write(v)
|
|
632
742
|
if len(v) & 1:
|
|
633
|
-
b.write(b
|
|
743
|
+
b.write(b"\0")
|
|
634
744
|
|
|
635
|
-
b.write(struct.pack(b
|
|
745
|
+
b.write(struct.pack(b">hh", -1, 0))
|
|
636
746
|
|
|
637
747
|
blen = b.tell() - pos
|
|
638
748
|
b.seek(pos + 4, os.SEEK_SET)
|
|
639
|
-
b.write(struct.pack(b
|
|
749
|
+
b.write(struct.pack(b">h", blen))
|
|
640
750
|
|
|
641
751
|
def to_bytes(self):
|
|
642
752
|
"""Returns the binary representation for this :class:`Alias`."""
|
|
@@ -645,18 +755,18 @@ class Alias (object):
|
|
|
645
755
|
return b.getvalue()
|
|
646
756
|
|
|
647
757
|
def __str__(self):
|
|
648
|
-
return
|
|
758
|
+
return "<Alias target=%s>" % self.target.filename
|
|
649
759
|
|
|
650
760
|
def __repr__(self):
|
|
651
761
|
values = []
|
|
652
|
-
if self.appinfo != b
|
|
653
|
-
values.append(
|
|
762
|
+
if self.appinfo != b"\0\0\0\0":
|
|
763
|
+
values.append("appinfo=%r" % self.appinfo)
|
|
654
764
|
if self.version != 2:
|
|
655
|
-
values.append(
|
|
765
|
+
values.append("version=%r" % self.version)
|
|
656
766
|
if self.volume is not None:
|
|
657
|
-
values.append(
|
|
767
|
+
values.append("volume=%r" % self.volume)
|
|
658
768
|
if self.target is not None:
|
|
659
|
-
values.append(
|
|
769
|
+
values.append("target=%r" % self.target)
|
|
660
770
|
if self.extra:
|
|
661
|
-
values.append(
|
|
662
|
-
return
|
|
771
|
+
values.append("extra=%r" % self.extra)
|
|
772
|
+
return "Alias(%s)" % ",".join(values)
|