diff options
author | das <das@noemail.net> | 2003-05-14 19:21:20 (GMT) |
---|---|---|
committer | das <das@noemail.net> | 2003-05-14 19:21:20 (GMT) |
commit | 12c2ff9d30314e4383f8d3735ab39ada802b4429 (patch) | |
tree | 18a23b38b5ab18b3714c78cd1f0f131855938b1f /unix | |
parent | f13a73e097e9538aad65fa5be146d83d35f11d6c (diff) | |
download | tcl-12c2ff9d30314e4383f8d3735ab39ada802b4429.zip tcl-12c2ff9d30314e4383f8d3735ab39ada802b4429.tar.gz tcl-12c2ff9d30314e4383f8d3735ab39ada802b4429.tar.bz2 |
Implementation of TIP 118:
* generic/tclFCmd.c (TclFileAttrsCmd): 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.
* unix/tclUnixFCmd.c: added support for new file attributes and for
copying Mac OS X file attributes & resource fork during [file copy].
* generic/tclInt.decls: added declarations of new external commands
needed by new file attributes support in tclUnixFCmd.c.
* macosx/tclMacOSXFCmd.c (new): Mac OS X specific implementation of
new file attributes and of attribute & resource fork copying.
* mac/tclMacFCmd.c: added implementation of -rsrclength attribute &
fixes to other attributes for consistency with OSX implementation.
* mac/tclMacResource.c: fixes to OSType handling.
* doc/file.n: documentation of [file attributes] changes.
* unix/configure.in: check for APIs needed by new file attributes.
* unix/Makefile.in:
* unix/tcl.m4: added new platform specifc tclMacOSXFCmd.c source.
* unix/configure:
* generic/tclStubInit.c:
* generic/tclIntPlatDecls.h: regen.
* tools/genStubs.tcl: fixes to completely broken code trying to
prevent overlap of "aqua", "macosx", "x11" and "unix" stub entries.
* tests/unixFCmd.test: added tests of -readonly attribute.
* tests/macOSXFCmd.test (new): tests of macosx file attributes and
of preservation of attributes & resource fork during [file copy].
* tests/macFCmd.test: restore -readonly attribute of test dir, as
otherwise its removal can fail on unices supporting -readonly.
FossilOrigin-Name: a25df0d3d994f84ae358d728b146f05dae415a83
Diffstat (limited to 'unix')
-rw-r--r-- | unix/Makefile.in | 8 | ||||
-rwxr-xr-x | unix/configure | 180 | ||||
-rw-r--r-- | unix/configure.in | 14 | ||||
-rw-r--r-- | unix/tcl.m4 | 2 | ||||
-rw-r--r-- | unix/tclUnixFCmd.c | 156 |
5 files changed, 345 insertions, 15 deletions
diff --git a/unix/Makefile.in b/unix/Makefile.in index fc6c42c..8401624 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -5,7 +5,7 @@ # "autoconf" program (constructs like "@foo@" will get replaced in the # actual Makefile. # -# RCS: @(#) $Id: Makefile.in,v 1.124 2003/04/11 16:09:51 vincentdarley Exp $ +# RCS: @(#) $Id: Makefile.in,v 1.125 2003/05/14 19:21:25 das Exp $ VERSION = @TCL_VERSION@ MAJOR_VERSION = @TCL_MAJOR_VERSION@ @@ -435,7 +435,8 @@ DL_SRCS = \ $(UNIX_DIR)/tclLoadShl.c MAC_OSX_SRCS = \ - $(MAC_OSX_DIR)/tclMacOSXBundle.c + $(MAC_OSX_DIR)/tclMacOSXBundle.c \ + $(MAC_OSX_DIR)/tclMacOSXFCmd.c # Note: don't include DL_SRCS or MAC_OSX_SRCS in SRCS: most of those # files won't compile on the current machine, and they will cause @@ -1054,6 +1055,9 @@ tclUnixInit.o: $(UNIX_DIR)/tclUnixInit.c $(GENERIC_DIR)/tclInitScript.h tclConfi tclMacOSXBundle.o: $(MAC_OSX_DIR)/tclMacOSXBundle.c $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tclMacOSXBundle.c +tclMacOSXFCmd.o: $(MAC_OSX_DIR)/tclMacOSXFCmd.c + $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tclMacOSXFCmd.c + # The following targets are not completely general. They are provide # purely for documentation purposes so people who are interested in # the Xt based notifier can modify them to suit their own installation. diff --git a/unix/configure b/unix/configure index db36eb7..a7732ba 100755 --- a/unix/configure +++ b/unix/configure @@ -9562,6 +9562,184 @@ echo "${ECHO_T}$langinfo_ok" >&6 #-------------------------------------------------------------------- +# Check for support of chflags function +#-------------------------------------------------------------------- + + +for ac_func in chflags +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +#-------------------------------------------------------------------- +# Check for support of getattrlist function (Darwin, HFS+) +#-------------------------------------------------------------------- + + +for ac_func in getattrlist +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +#-------------------------------------------------------------------- # Look for libraries that we will need when compiling the Tcl shell #-------------------------------------------------------------------- @@ -11824,7 +12002,7 @@ fi SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" - PLAT_OBJS="tclMacOSXBundle.o" + PLAT_OBJS="tclMacOSXBundle.o tclMacOSXFCmd.o" DL_LIBS="" LDFLAGS="-prebind" CC_SEARCH_FLAGS="" diff --git a/unix/configure.in b/unix/configure.in index ce6b5e2..c538308 100644 --- a/unix/configure.in +++ b/unix/configure.in @@ -3,7 +3,7 @@ dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tcl installation dnl to configure the system for the local environment. # -# RCS: @(#) $Id: configure.in,v 1.108 2003/03/13 10:39:58 mdejong Exp $ +# RCS: @(#) $Id: configure.in,v 1.109 2003/05/14 19:21:29 das Exp $ AC_INIT(../generic/tcl.h) AC_PREREQ(2.57) @@ -417,6 +417,18 @@ fi SC_ENABLE_LANGINFO #-------------------------------------------------------------------- +# Check for support of chflags function +#-------------------------------------------------------------------- + +AC_CHECK_FUNCS(chflags) + +#-------------------------------------------------------------------- +# Check for support of getattrlist function (Darwin, HFS+) +#-------------------------------------------------------------------- + +AC_CHECK_FUNCS(getattrlist) + +#-------------------------------------------------------------------- # Look for libraries that we will need when compiling the Tcl shell #-------------------------------------------------------------------- diff --git a/unix/tcl.m4 b/unix/tcl.m4 index 88eaa56..03418d2 100644 --- a/unix/tcl.m4 +++ b/unix/tcl.m4 @@ -1281,7 +1281,7 @@ dnl AC_CHECK_TOOL(AR, ar) SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" - PLAT_OBJS="tclMacOSXBundle.o" + PLAT_OBJS="tclMacOSXBundle.o tclMacOSXFCmd.o" DL_LIBS="" LDFLAGS="-prebind" CC_SEARCH_FLAGS="" diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index bc9746f..7b26c08 100644 --- a/unix/tclUnixFCmd.c +++ b/unix/tclUnixFCmd.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixFCmd.c,v 1.28 2003/02/10 12:50:31 vincentdarley Exp $ + * RCS: @(#) $Id: tclUnixFCmd.c,v 1.29 2003/05/14 19:21:30 das Exp $ * * Portions of this code were derived from NetBSD source code which has * the following copyright notice: @@ -91,6 +91,14 @@ static int SetPermissionsAttribute _ANSI_ARGS_(( static int GetModeFromPermString _ANSI_ARGS_(( Tcl_Interp *interp, char *modeStringPtr, mode_t *modePtr)); +#ifdef HAVE_CHFLAGS +static int GetReadOnlyAttribute _ANSI_ARGS_((Tcl_Interp *interp, + int objIndex, Tcl_Obj *fileName, + Tcl_Obj **attributePtrPtr)); +static int SetReadOnlyAttribute _ANSI_ARGS_((Tcl_Interp *interp, + int objIndex, Tcl_Obj *fileName, + Tcl_Obj *attributePtr)); +#endif /* * Prototype for the TraverseUnixTree callback function. @@ -107,28 +115,53 @@ typedef int (TraversalProc) _ANSI_ARGS_((Tcl_DString *srcPtr, enum { UNIX_GROUP_ATTRIBUTE, UNIX_OWNER_ATTRIBUTE, - UNIX_PERMISSIONS_ATTRIBUTE + UNIX_PERMISSIONS_ATTRIBUTE, +#ifdef HAVE_CHFLAGS + UNIX_READONLY_ATTRIBUTE, +#endif +#ifdef MAC_OSX_TCL + MACOSX_CREATOR_ATTRIBUTE, + MACOSX_TYPE_ATTRIBUTE, + MACOSX_HIDDEN_ATTRIBUTE, + MACOSX_RSRCLENGTH_ATTRIBUTE, +#endif }; CONST char *tclpFileAttrStrings[] = { "-group", "-owner", "-permissions", +#ifdef HAVE_CHFLAGS + "-readonly", +#endif +#ifdef MAC_OSX_TCL + "-creator", + "-type", + "-hidden", + "-rsrclength", +#endif (char *) NULL }; CONST TclFileAttrProcs tclpFileAttrProcs[] = { {GetGroupAttribute, SetGroupAttribute}, {GetOwnerAttribute, SetOwnerAttribute}, - {GetPermissionsAttribute, SetPermissionsAttribute} + {GetPermissionsAttribute, SetPermissionsAttribute}, +#ifdef HAVE_CHFLAGS + {GetReadOnlyAttribute, SetReadOnlyAttribute}, +#endif +#ifdef MAC_OSX_TCL + {TclMacOSXGetFileAttribute, TclMacOSXSetFileAttribute}, + {TclMacOSXGetFileAttribute, TclMacOSXSetFileAttribute}, + {TclMacOSXGetFileAttribute, TclMacOSXSetFileAttribute}, + {TclMacOSXGetFileAttribute, TclMacOSXSetFileAttribute}, +#endif }; /* * Declarations for local procedures defined in this file: */ -static int CopyFile _ANSI_ARGS_((CONST char *src, - CONST char *dst, CONST Tcl_StatBuf *statBufPtr)); static int CopyFileAtts _ANSI_ARGS_((CONST char *src, CONST char *dst, CONST Tcl_StatBuf *statBufPtr)); static int DoCopyFile _ANSI_ARGS_((CONST char *srcPtr, @@ -400,7 +433,7 @@ DoCopyFile(src, dst) return CopyFileAtts(src, dst, &srcStatBuf); } default: { - return CopyFile(src, dst, &srcStatBuf); + return TclUnixCopyFile(src, dst, &srcStatBuf, 0); } } return TCL_OK; @@ -409,7 +442,7 @@ DoCopyFile(src, dst) /* *---------------------------------------------------------------------- * - * CopyFile - + * TclUnixCopyFile - * * Helper function for TclpCopyFile. Copies one regular file, * using read() and write(). @@ -423,13 +456,14 @@ DoCopyFile(src, dst) *---------------------------------------------------------------------- */ -static int -CopyFile(src, dst, statBufPtr) +int +TclUnixCopyFile(src, dst, statBufPtr, dontCopyAtts) CONST char *src; /* Pathname of file to copy (native). */ CONST char *dst; /* Pathname of file to create/overwrite * (native). */ CONST Tcl_StatBuf *statBufPtr; /* Used to determine mode and blocksize. */ + int dontCopyAtts; /* if flag set, don't copy attributes. */ { int srcFd; int dstFd; @@ -483,7 +517,7 @@ CopyFile(src, dst, statBufPtr) unlink(dst); /* INTL: Native. */ return TCL_ERROR; } - if (CopyFileAtts(src, dst, statBufPtr) == TCL_ERROR) { + if (!dontCopyAtts && CopyFileAtts(src, dst, statBufPtr) == TCL_ERROR) { /* * The copy succeeded, but setting the permissions failed, so be in * a consistent state, we remove the file that was created by the @@ -1071,6 +1105,9 @@ CopyFileAtts(src, dst, statBufPtr) if (utime(dst, &tval)) { /* INTL: Native. */ return TCL_ERROR; } +#ifdef MAC_OSX_TCL + TclMacOSXCopyFileAttributes(src, dst, statBufPtr); +#endif return TCL_OK; } @@ -1781,6 +1818,105 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) return nextCheckpoint; } + +#ifdef HAVE_CHFLAGS +/* + *---------------------------------------------------------------------- + * + * GetReadOnlyAttribute + * + * Gets the readonly attribute (user immutable flag) of a file. + * + * Results: + * Standard TCL result. Returns a new Tcl_Obj in attributePtrPtr + * if there is no error. The object will have ref count 0. + * + * Side effects: + * A new object is allocated. + * + *---------------------------------------------------------------------- + */ +static int +GetReadOnlyAttribute(interp, objIndex, fileName, attributePtrPtr) + Tcl_Interp *interp; /* The interp we are using for errors. */ + int objIndex; /* The index of the attribute. */ + Tcl_Obj *fileName; /* The name of the file (UTF-8). */ + Tcl_Obj **attributePtrPtr; /* A pointer to return the object with. */ +{ + Tcl_StatBuf statBuf; + int result; + result = TclpObjStat(fileName, &statBuf); + + if (result != 0) { + Tcl_AppendResult(interp, "could not read \"", + Tcl_GetString(fileName), "\": ", + Tcl_PosixError(interp), (char *) NULL); + return TCL_ERROR; + } + *attributePtrPtr = Tcl_NewBooleanObj((statBuf.st_flags & UF_IMMUTABLE) != 0); + + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * SetReadOnlyAttribute + * + * Sets the readonly attribute (user immutable flag) of a file. + * + * Results: + * Standard TCL result. + * + * Side effects: + * The readonly attribute of the file is changed. + * + *--------------------------------------------------------------------------- + */ + +static int +SetReadOnlyAttribute(interp, objIndex, fileName, attributePtr) + Tcl_Interp *interp; /* The interp we are using for errors. */ + int objIndex; /* The index of the attribute. */ + Tcl_Obj *fileName; /* The name of the file (UTF-8). */ + Tcl_Obj *attributePtr; /* The attribute to set. */ +{ + Tcl_StatBuf statBuf; + int result; + int readonly; + CONST char *native; + + if (Tcl_GetBooleanFromObj(interp, attributePtr, &readonly) != TCL_OK) { + return TCL_ERROR; + } + + result = TclpObjStat(fileName, &statBuf); + + if (result != 0) { + Tcl_AppendResult(interp, "could not read \"", + Tcl_GetString(fileName), "\": ", + Tcl_PosixError(interp), (char *) NULL); + return TCL_ERROR; + } + + if (readonly) { + statBuf.st_flags |= UF_IMMUTABLE; + } else { + statBuf.st_flags &= ~UF_IMMUTABLE; + } + + native = Tcl_FSGetNativePath(fileName); + result = chflags(native, statBuf.st_flags); /* INTL: Native. */ + if (result != 0) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "could not set flags for file \"", + Tcl_GetString(fileName), "\": ", + Tcl_PosixError(interp), (char *) NULL); + return TCL_ERROR; + } + return TCL_OK; +} +#endif /* HAVE_CHFLAGS */ |