Stop rewriting an alias file's own metadata
Writing a volume rebuilds every alias file, because the `alis` record names its target by CNID and CNIDs are assigned afresh on each write. It rebuilt more than the record, though: the file's type and creator were overwritten with ones guessed from the target, the rest of the resource fork was thrown away, and the data fork was cleared. Round-tripping the Apple Menu's Control Panels alias out of a System 7 image therefore turned `fact` into `fdrp`, dropped its `vers` resources, and renamed the `alis` from "Control Panels alias" to "Control Panels". Aliases to applications lost their `adrp` for whatever the target's type happened to be -- `APPC`, `cdev`. Only the `alis` resource is replaced now, in place and under its own name; type and creator are guessed only for an alias built here, which has neither. Reading and rewriting the 29 infinite-mac images machfs can parse touches 73 alias files: type and creator used to change on 10 of them and now change on none, and 28 resource forks used to lose more than the `alis` record and now lose nothing else. (Their data forks were already empty, so clearing those had cost nothing in practice.) For mihaip/infinite-mac#84
This commit is contained in:
1 parent
1f8e7b5288
commit
d32a327c5f
2 files changed
+69
-16
No files matched your search
+35
-16
@@ -474,23 +474,26 @@ class Volume(AbstractFolder):
|
||||
aliastarget = (self.name,) + aliastarget # match the convention for this function
|
||||
targetobj = path2wrap[aliastarget].of # probe the target to set some metadata
|
||||
|
||||
if isinstance(targetobj, Folder):
|
||||
wrap.creator = b'MACS'
|
||||
wrap.type = b'fdrp'
|
||||
# An alias read from a volume carries the type and creator the
|
||||
# Finder gave it, which the guesses below do not reproduce:
|
||||
# 'fact' for Control Panels, 'faet' for Automated Tasks. So
|
||||
# only guess for an alias built here, which has neither.
|
||||
if obj.type == b'????' and obj.creator == b'????':
|
||||
if isinstance(targetobj, Folder):
|
||||
wrap.creator = b'MACS'
|
||||
wrap.type = b'fdrp'
|
||||
|
||||
elif isinstance(targetobj, Volume):
|
||||
wrap.creator = b'MACS'
|
||||
wrap.type = b'hdsk' if size > 1440*1024 else b'flpy'
|
||||
elif isinstance(targetobj, Volume):
|
||||
wrap.creator = b'MACS'
|
||||
wrap.type = b'hdsk' if size > 1440*1024 else b'flpy'
|
||||
|
||||
elif isinstance(targetobj, File):
|
||||
wrap.creator = targetobj.creator
|
||||
elif isinstance(targetobj, File):
|
||||
wrap.creator = targetobj.creator
|
||||
|
||||
if targetobj.type == b'APPL':
|
||||
wrap.type = b'adrp'
|
||||
else:
|
||||
wrap.type = targetobj.type
|
||||
|
||||
wrap.data = b''
|
||||
if targetobj.type == b'APPL':
|
||||
wrap.type = b'adrp'
|
||||
else:
|
||||
wrap.type = targetobj.type
|
||||
|
||||
userType = b''
|
||||
aliasSize = 9999 # fill this short at offset 4
|
||||
@@ -514,7 +517,19 @@ class Volume(AbstractFolder):
|
||||
# Stress test: find file by name, not CNID
|
||||
# fileNum = 0
|
||||
|
||||
alis = Resource(b'alis', 0, name=path[-1])
|
||||
# The record below holds CNIDs, so it has to be rebuilt for this
|
||||
# volume. The rest of the fork belongs to the file: Control
|
||||
# Panels keeps its 'vers', and the 'alis' keeps its own name.
|
||||
resources = list(parse_file(obj.rsrc)) if obj.rsrc else []
|
||||
alisIndex = next((i for i, r in enumerate(resources)
|
||||
if (r.type, r.id) == (b'alis', 0)), None)
|
||||
|
||||
if alisIndex is None:
|
||||
alis = Resource(b'alis', 0, name=path[-1])
|
||||
else:
|
||||
oldalis = resources[alisIndex]
|
||||
alis = Resource(b'alis', 0, name=oldalis.name)
|
||||
alis.attribs = oldalis.attribs
|
||||
alis.data[:] = struct.pack('>4s H hh 28p L 2s hL 64p LL 4s4s HHLh',
|
||||
userType, aliasSize, aliasVersion, \
|
||||
thisAliasKind, volumeName, volumeCrDate, \
|
||||
@@ -531,7 +546,11 @@ class Volume(AbstractFolder):
|
||||
|
||||
# open('/tmp/creating','wb').write(alis.data)
|
||||
|
||||
wrap.rsrc = make_file([alis])
|
||||
if alisIndex is None:
|
||||
resources.append(alis)
|
||||
else:
|
||||
resources[alisIndex] = alis
|
||||
wrap.rsrc = make_file(resources)
|
||||
|
||||
if isinstance(obj, File):
|
||||
wrap.dfrk = wrap.rfrk = (0, 0)
|
||||
|
||||
+34
@@ -1,5 +1,7 @@
|
||||
from machfs import *
|
||||
from machfs import bitmanip, btree
|
||||
from machfs.main import FinderFlags
|
||||
from macresources import Resource, make_file, parse_file
|
||||
import os
|
||||
import struct
|
||||
import time
|
||||
@@ -27,6 +29,38 @@ def test_roundtrip():
|
||||
assert f.data in copies[-1]
|
||||
|
||||
|
||||
def test_alias_keeps_what_belongs_to_the_file():
|
||||
h = Volume()
|
||||
h.name = 'AliasTest'
|
||||
|
||||
target = File()
|
||||
target.type, target.creator = b'APPC', b'wnkl'
|
||||
target.data = b'target data'
|
||||
h['target'] = target
|
||||
|
||||
# Neither 'fact' nor the 'vers' resource can be derived from the target.
|
||||
vers = Resource(b'vers', 2, data=b'\x01\x00\x80\x00\x00\x00\x041.0')
|
||||
stale = Resource(b'alis', 0, name='alias resource name', data=bytes(150))
|
||||
alias = File()
|
||||
alias.flags |= FinderFlags.kIsAlias
|
||||
alias.type, alias.creator = b'fact', b'MACS'
|
||||
alias.rsrc = make_file([stale, vers])
|
||||
alias.aliastarget = target
|
||||
h['the alias'] = alias
|
||||
|
||||
copy = Volume()
|
||||
copy.read(h.write(10*1024*1024, desktopdb=False, bootable=False))
|
||||
got = copy['the alias']
|
||||
|
||||
assert (got.type, got.creator) == (b'fact', b'MACS')
|
||||
|
||||
resources = {(r.type, r.id): r for r in parse_file(got.rsrc)}
|
||||
assert resources[b'vers', 2].data == vers.data
|
||||
assert resources[b'alis', 0].name == 'alias resource name'
|
||||
# The record itself holds this volume's CNIDs, so it is rebuilt.
|
||||
assert resources[b'alis', 0].data != stale.data
|
||||
|
||||
|
||||
def test_open_folder():
|
||||
h = Volume()
|
||||
h.name = 'OpenFolderTest'
|
||||
|
||||
Reference in new issue
Block a user