Now, back to TextEdit, whose change of behaviour is quite
interesting. I ran TextEdit under both 10.5.x and 10.6 and looked
at the backtrace of a save. Here's the results for 10.5.x:
#0 0x970b0a60 in rename ()
#1 0x95c95526 in VolFSMount::rename ()
#2 0x95c9f163 in VolFSMount::moveandrename ()
#3 0x95c9ed18 in FSReplaceObject ()
#4 0x95c9df45 in FSPathReplaceObject ()
#5 0x930ba8c1 in +[NSDocument
_finishWritingFileAtPath:byTakingContentsFromFileAtPath:addingAttributes:usingTemporaryDirectoryAtPath:keepingBackupFile:error
:] ()
#6 0x9307c5d4 in -[NSDocument
_writeSafelyToURL:ofType:forSaveOperation:error:] ()
#7 0x9307c2d6 in -[NSDocument
writeSafelyToURL:ofType:forSaveOperation:error:] ()
[...]
and here's the result for 10.6:
#0 0x921f095b in rename ()
#1 0x9695d593 in _RenameURL ()
#2 0x9695ed7a in _URLReplaceObject ()
#3 0x98205066 in -[NSFileManager
replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error
:] ()
#4 0x96fd979a in +[NSFileWrapper(NSInternal)
_finishWritingToURL:byTakingContentsFromItemAtURL:addingAttributes:usingTemporaryDirectoryAtURL:keepingBackupFile:error
:] ()
#5 0x96fb0d71 in -[NSDocument
_writeSafelyToURL:ofType:forSaveOperation:error:] ()
#6 0x96fafdbe in -[NSDocument
writeSafelyToURL:ofType:forSaveOperation:error:] ()
[...]
As you can see, TextEdit uses -[NSDocument
writeSafelyToURL:ofType:forSaveOperation:error:] to save its
documents, and in 10.6 that method was rewritten to /not/ call the
File Manager routine FSPathReplaceObject. This is the reason why
extended attributes are not being preserved on 10.6:
FSPathReplaceObject was specifically designed to support this sort
of thing, and it seems that the AppKit equivalent code was not.
I would definitely classify this as a bug but, just to be sure, I'm
going to discuss this with AppKit engineering.
And finally, let's look at the different behaviour for different
attributes. You wrote:
I have found that all skim xattrs,
de.codingmonkeys.seestate:
org.openmetainfo:kOMManaged:
anyKeyYouMakeUp
etc, etc
get erased, while
com.apple.metadata:kMDItemStarRating
com.apple.metadata:kMDItemWhereFroms
and I assume resource forks, (although I did not test that) and
some other apple ones are saved.
First up, the resource fork is definitely not saved.
1. Start with a file with a resource fork.
$ ls -l@ file.txt
-rw-r--r--@ 1 xxxx xxxx 16 22 Sep 16:20 file.txt
com.apple.ResourceFork 368
com.apple.TextEncoding 11
com.apple.metadata:kMDItemStarRating 43
2. Open the file in TextEdit, modify it, save the changes, and close
it again.
3. The resource fork is now gone.
$ ls -l@ file.txt
-rw-r--r--@ 1xxxx xxxx 17 22 Sep 16:21 file.txt
com.apple.TextEncoding 11
com.apple.metadata:kMDItemStarRating 43
Secondly, it's not actually Cocoa that's preserving the Spotlight
attributes. Check out the following:
1. Start with a file with a star rating:
$ ls -l@ file.txt
-rw-r--r--@ 1xxxx xxxx 16 22 Sep 16:25 file.txt
com.apple.TextEncoding 11
com.apple.metadata:kMDItemStarRating 43
2. Run the SetXAttr.d DTrace script:
$ cat SetXAttr.d
#! /usr/sbin/dtrace -q -s
syscall::setxattr:entry
/ ! self->trace /
{
self->trace = 1;
self->path = arg0;
self->attr = arg1;
}
syscall::setxattr:return
/ self->trace /
{
path = copyinstr(self->path);
attr = copyinstr(self->attr);
printf("%s: setxattr('%s', '%s') -> %d\n", execname, path, attr,
errno);
self->trace = 0;
}
syscall::fsetxattr:entry
/ ! self->trace /
{
self->trace = 1;
self->attr = arg1;
}
syscall::fsetxattr:return
/ self->trace /
{
attr = copyinstr(self->attr);
printf("%s: fsetxattr(?, '%s') -> %d\n", execname, attr, errno);
self->trace = 0;
}
$ sudo ./SetXAttr.d
3. Open the file in TextEdit, modify it, save the changes, and close
it again.
4. Look at the output of the script:
TextEdit: setxattr('/private/var/folders/Ie/[...]/file.txt',
'com.apple.TextEncoding') -> 0
mds: fsetxattr(?, 'com.apple.metadata:kMDItemStarRating') -> 0
^C
As you can see, TextEdit only saves one extended attribute to the
file, namely "com.apple.TextEncoding". The
"com.apple.metadata:kMDItemStarRating" is being set by <x-man-page://8/mds
, aka the Spotlight daemon process. So it seems that, rather than
Cocoa preserving these extended attributes, Spotlight is handling
them as a special case.
I investigate this facility in depth as well. As you're probably
aware, Spotlight watches the file system for events of interest to
it, and uses those events to update its index. In this case
Spotlight is specifically looking for 'safe save' operations (that
is, renames which replace a file at the new path). When it sees
one, it copies its attributes from its internal records of the
original file to the replacement file.
You can verify that this has nothing to do with Cocoa by simply
performing the rename from Terminal:
1. Start with a file with a star rating.
$ ls -l@ file.txt
-rw-r--r--@ 1xxxx xxxx 13 22 Sep 16:56 file.txt
com.apple.metadata:kMDItemStarRating 43
2. Create a replacement file.
$ cat > file-bu.txt
this is a test
^D
3. Verify that the attributes are the way we expect.
$ ls -l@ file*.txt
-rw-r--r-- 1xxxx xxxx 15 22 Sep 17:28 file-bu.txt
-rw-r--r--@ 1xxxx xxxx 13 22 Sep 16:56 file.txt
com.apple.metadata:kMDItemStarRating 43
4. Do the rename.
$ mv file-bu.txt file.txt
5. Check the attributes of the final; somehow it has retained its
star rating.
$ ls -l@ file*.txt
-rw-r--r--@ 1xxxx xxxx 15 22 Sep 17:28 file.txt
com.apple.metadata:kMDItemStarRating 43
> I filed a bug, a tech support incident.
I've filed a bug as well. I think NSFileManager should behave the same
way that FSReplaceObject does.
> For OpenMeta I have a solution that will help quite a bit, in that
> mds seems to replace erased xattrs if they are in the right format
> in the spotlight DB: So that's what I am doing for OpenMeta. Tags
> will be filed under kMDItemOMUserTags instead of kOMUserTags.
kMDItemOMUserTags? Is that a typo?
Your solution seems to address searchability but not data exchange. It
seems like this change will break compatibility with other
applications that are using "com.apple.metadata:kOMUserTags".
My plan for EagleFiler is to continue using
"com.apple.metadata:kOMUserTags" and "org.openmetainfo:kOMUserTags",
using the timestamp to see which is newer, and to restore the xattrs
if they get deleted.
--Michael
> kMDItem* items get preserved when saving files - so really I have no
> choice.
> It seems that it works pretty well for compatibility - I keep a look
> out for files that have older tag formats and update them, I also
> write out tags in the old format.
So when you said "instead of" you meant "in addition to"? How are you
resolving conflicts, i.e. when the attributes have different values?
--Michael
> @Michael: You can't check the xattr "com.apple.metadata:kOMUserTags"
> and "org.openmetainfo:kOMUserTags" for which is newer. Both will be
> removed when files are being saved.
Yes, and both may be added back by other applications. So unless you
want to overwrite possibly newer data, you should to check all three
locations now. (Is there a timestamp for kMDItemOMUserTags?)
> You haven't responded to the Spotlight comment thing.
> I don't say that it is a perfect solution as it has some drawbacks as
> well (losing information in terminal apps for example).
> But at least it is an official solution.
Spotlight comments are still official, but I think they're still
really slow to read and write.
--Michael
> Spotlight comments are still official, but I think they're still
> really slow to read and write.
Plus many users were using "Finder comments" years before Spotlight
was even a twinkle in Steve Jobs' eye, and would prefer to keep them
clear for user-level purposes.
Michael
--
<http://www.linkedin.com/in/migrant>
<http://twitter.com/MiGrant>
<http://globalocal.blogspot.com>
<http://eurobubba.com>
I never metadata I didn't like.
> I uploaded the OpenMeta code that I am using in Yep 2
Why did you change the keys in org.openmetainfo? We should be able to
keep the format in our domain constant, to maximize compatibility.
--Michael
> HFS+ is getting really really old, and I think that a
> replacement for it may come along soon, perhaps even before 10.7?
Apple is not going to replace their filesystem between releases.
> Any
> new file system will likely have first class handling of meta data,
> including user added metadata.
HFS+ already has first-class handling of metadata. The problems we're
encountering are above the filesystem level, in the application
frameworks.
> Quarantine services - buried in some database somewhere.
This info is stored in the extended attributes.
> Launch Services (the stuff that keeps track of what application to
> open what files with) - some other database hidden away somewhere.
The file-specific bindings are stored in the resource fork. The
general bindings are not file metadata.
> The whole system is basically a pile of
> afterthoughts. A shiny new file system could change all of that.
It could also all be changed with HFS+, since it supports extended
attributes.
--Michael