TIP:            118
Title:          Enhance [file attributes] and [file copy] on Mac OS X & BSD
Version:        $Revision: 1.7 $
Author:         Daniel A. Steffen <das@users.sourceforge.net>
State:          Final
Type:           Project
Vote:           Done
Created:        01-Nov-2002
Post-History:   
Tcl-Version:    8.5

~ Abstract

This TIP proposes a set of changes to ''[file attributes]'' and
''[file copy]'' to make them function better on MacOS X and other
BSD-Unix systems.

~ Summary of Proposed Changes

This TIP proposes five sets of changes to ''[file attributes]'' and
''[file copy]'':

 1. Add support for the Macintosh and Windows specific flag ''[file
    attributes -readonly]'' to Unixes that support the ''chflags()''
    API, to allow the ''user immutable'' flag to be accessed &
    modified from Tcl.

 2. Add support for the Macintosh specific flags ''[file attributes
    -readonly -creator -type -hidden]'' to Mac OS X via the POSIX
    level API ''getattrlist()''.

 3. Add a new flag ''[file attributes -rsrclength]'' to Mac OS X and
    Mac OS 9 that gives the length of the resource fork of a file; 0
    is the only value that this attribute can be set to, which strips
    the resource fork off a file.

 4. Change ''[file attributes]'' to return the list of attributes that
    can be retrieved without error for a given file, instead of
    aborting the whole command when any error occurs.

 5. Enhance ''[file copy]'' on Mac OS X (more precisely, the native
    file-system ''Tcl_FSCopyFile'') to copy finder attributes (i.e.
    ''-readonly -creator -type -hidden'') and resource forks
    transparently.

~ Rationale

There is currently no way to access and modify HFS file-system metadata
from Tcl on Mac OS X whereas Tcl on Mac OS 9 (or Classic) on the same
Macintosh has that capability.  Worse, ''[file copy]'' (and
potentially even ''[file rename]'' if it results in a copy) on Mac OS
X can be a destructive operation at present if it operates on a file
that has essential data in its resource fork or its HFS metadata.
This again in contrast to the same operations in Tcl on Mac OS 9 where
this information is preserved.  This TIP seeks to rectify these
asymmetries in order to better hide such file-system related platform
specificities from the scripter.

~ Details

Additional information & examples:

 1. Unix versions that support ''chflags()'' include BSD >= 4.4 and
    Darwin/Mac OS X (where ''user immutable'' is the flag
    corresponding to the file locked state on the HFS file-system,
    which is what ''[file attributes -readonly]'' controls on Mac OS
    9).

 2. The use of ''getattrlist()'' does not require linking with Carbon
    and thus allows access to HFS file-system metadata from Tcl on pure
    open-source Darwin systems (which is something no other scripting
    language can claim at present).

 3. The new attribute ''-rsrclength'' is useful to check whether a
    file has a resource fork and to calculate total file size on Mac
    OS 9 and X (note that ''[file size]'' returns the size of the data
    fork only).  Stripping a file's resource fork (by setting
    ''-rsrclength'' to 0) is a common operation on Mac OS when dealing
    with files that are destined for other platforms.  This is a
    feature that has been requested several times and given that it
    ties in well with the implementation of the other new attributes
    it comes at essentially no additional cost.

|% file attributes test
|-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 314
|% file attributes test -rsrclength 5
|setting nonzero rsrclength not supported
|% file attributes test -rsrclength 0
|% file attributes test
|-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 0

 4. On Mac OS X, trying to retrieve the new attributes ''-creator
    -type -rsrclength'' fails on non-regular files & directories (and
    on any file located on a non-HFS file-system that doesn't support
    ''getattrlist()'').  Returning only the list of attributes that
    are valid seems like much more sensible behaviour in this case
    than failing with an error and not returning anything.  In the
    case where no valid attributes can be retrieved at all, the error
    returned by the last attempt is passed upstream, to preserve
    existing error handling.  This proposed change in behaviour of
    ''[file attributes]'' seems necessary to allow the command to
    continue to work in a consistent way on all inputs and on all
    platforms; it should not impact existing code since for current
    attributes, failure to retrieve any one attribute is equivalent to
    failure to retrieve all attributes.

|% close [open test w]
|% file attributes test
|-group admin -owner steffen -permissions 00644 -readonly 0 -creator {} -type {} -hidden 0 -rsrclength 0
|% file delete test
|% file mkdir test
|% file attributes test
|-group admin -owner steffen -permissions 040755 -readonly 0 -hidden 0
|% file delete test

 5. Unlike the Finder and other HFS aware tools on Mac OS X, Tcl
    currently ignores HFS metadata and the resource fork, which will
    undoubtedly surprise scripters unpleasantly.  ''[file copy]''
    should hide such platform specificities and copy a file in the
    same way as the Finder:

|% file attributes test
|-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 314
|% file copy test test1
|% file attributes test1
|-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 314
|% file delete test1

~ Comments

Additional implementation details:

 * To support the new attributes ''-creator -type'', routines to
   convert from numerical OSTypes (''u_int32_t'') to the usual four
   character human readable format have been adapted from
   ''mac/tclMacResource.c''; the new versions accept/return strings of
   length 0-4 unlike the originals that only dealt with length 4.
   This is important because creator/type 0 (i.e. ''-creator {} -type
   {}'') is common on Mac OS X. The Mac OS 9 implementation of the
   OSType string representation code has been modified accordingly by
   adding support for strings of length 0-4 and missing
   ''UtfToExternal/ExternalToUtf'' conversions.

 * ''macRoman'' is the encoding used for the string representation of
   OSTypes, for consistency with Tcl on Mac OS 9 as well as with
   common Mac OS X tools such as Resorcerer & SuperGetInfo that all
   use ''macRoman'' to display creator/type codes; this encoding is
   probably what most people would expect.  It's unfortunate that this
   means that use of ''[file attributes]'' on Darwin/Mac OS X will
   cause the non-builtin ''macRoman'' encoding to load.  ASCII-only
   OSTypes will still work properly if ''macRoman'' is not available,
   fallback to ''latin1'' in that case could also be added if deemed
   necessary.  However, the Tk Aqua port already relies on
   ''macRoman'' being present so in the most common usage pattern
   ''macRoman'' should be present and loaded anyway.

 * The Mac OS 9 implementation of ''[file attributes -creator -type]''
   currently returns the bogus 'Fldr' type & creator for directories,
   this has been changed to return an error for consistency with the
   Mac OS X implementation.

 * Most of the implementation of the new Mac OS X specific features
   has been added added at the end of ''unix/tclUnixFCmd.c'', it might
   be cleaner to move this code to a separate file
   ''macosx/tclMacOSXFCmd.c'', but that would require several routines
   in both ''unix/tclUnixFCmd.c'' and ''mac/tclMacOSXFCmd.c'' to be
   made non-static.  It's unclear whether this is an acceptable change
   just for the sake of code separation/cleanliness.

~ Reference Implementation

SourceForge patch #626360
[[http://sourceforge.net/tracker/index.php?func=detail&aid=626360&group_id=10894&atid=310894]]
implements this TIP as a patch to the current HEAD.

The patch has been tested on the SF compile-farm on hosts:

 [Alpha] Linux 2.4 (Debian 3.0): where ''chflags()'' and
   ''getattrlist()'' are not available and no ill effects ensue
   (i.e. no new tests fail).

 [x86] FreeBSD (4.7-RC): where ''chflags()'' is available and ''[file
   attributes -readonly]'' can successfully be interrogated (but not
   set due to permission issues at SourceForge).  No new tests fail.

as well as on Mac OS 9, X 10.1.5 and X 10.2.1, where all the new
functionality is available and no new tests fail.

~ Copyright

This document has been placed in the public domain.
