TIP 118: Enhance [file attributes] and [file copy] on Mac OS X & BSD

FlightAware bounty program for improvements to Tcl and certain Tcl packages.
Author:         Daniel A. Steffen <das@users.sourceforge.net>
State:          Final
Type:           Project
Vote:           Done
Created:        01-Nov-2002
Tcl-Version:    8.5
Tcl-Ticket:     626360


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.


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.


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


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.


This document has been placed in the public domain.