summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixFile.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixFile.c')
-rw-r--r--unix/tclUnixFile.c1266
1 files changed, 905 insertions, 361 deletions
diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c
index 2679fdb..2cb0027 100644
--- a/unix/tclUnixFile.c
+++ b/unix/tclUnixFile.c
@@ -1,70 +1,75 @@
-/*
+/*
* tclUnixFile.c --
*
- * This file contains wrappers around UNIX file handling functions.
- * These wrappers mask differences between Windows and UNIX.
+ * This file contains wrappers around UNIX file handling functions.
+ * These wrappers mask differences between Windows and UNIX.
*
* Copyright (c) 1995-1998 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tclUnixFile.c,v 1.9 2000/01/11 22:09:19 hobbs Exp $
*/
#include "tclInt.h"
-#include "tclPort.h"
+#include "tclFileSystem.h"
+static int NativeMatchType(Tcl_Interp *interp, const char* nativeEntry,
+ const char* nativeName, Tcl_GlobTypeData *types);
/*
*---------------------------------------------------------------------------
*
* TclpFindExecutable --
*
- * This procedure computes the absolute path name of the current
- * application, given its argv[0] value.
+ * This function computes the absolute path name of the current
+ * application, given its argv[0] value. For Cygwin, argv[0] is
+ * ignored and the path is determined the same as under win32.
*
* Results:
- * A dirty UTF string that is the path to the executable. At this
- * point we may not know the system encoding. Convert the native
- * string value to UTF using the default encoding. The assumption
- * is that we will still be able to parse the path given the path
- * name contains ASCII string and '/' chars do not conflict with
- * other UTF chars.
+ * None.
*
* Side effects:
- * The variable tclNativeExecutableName gets filled in with the file
- * name for the application, if we figured it out. If we couldn't
- * figure it out, tclNativeExecutableName is set to NULL.
+ * The computed path name is stored as a ProcessGlobalValue.
*
*---------------------------------------------------------------------------
*/
-char *
-TclpFindExecutable(argv0)
- CONST char *argv0; /* The value of the application's argv[0]
+void
+TclpFindExecutable(
+ const char *argv0) /* The value of the application's argv[0]
* (native). */
{
- CONST char *name, *p;
- struct stat statBuf;
+ Tcl_Encoding encoding;
+#ifdef __CYGWIN__
int length;
- Tcl_DString buffer, nameString;
+ char buf[PATH_MAX * 2];
+ char name[PATH_MAX * TCL_UTF_MAX + 1];
+ GetModuleFileNameW(NULL, buf, PATH_MAX);
+ cygwin_conv_path(3, buf, name, PATH_MAX);
+ length = strlen(name);
+ if ((length > 4) && !strcasecmp(name + length - 4, ".exe")) {
+ /* Strip '.exe' part. */
+ length -= 4;
+ }
+ encoding = Tcl_GetEncoding(NULL, NULL);
+ TclSetObjNameOfExecutable(
+ Tcl_NewStringObj(name, length), encoding);
+#else
+ const char *name, *p;
+ Tcl_StatBuf statBuf;
+ Tcl_DString buffer, nameString, cwd, utfName;
if (argv0 == NULL) {
- return NULL;
- }
- if (tclNativeExecutableName != NULL) {
- return tclNativeExecutableName;
+ return;
}
-
Tcl_DStringInit(&buffer);
name = argv0;
for (p = name; *p != '\0'; p++) {
if (*p == '/') {
/*
- * The name contains a slash, so use the name directly
- * without doing a path search.
+ * The name contains a slash, so use the name directly without
+ * doing a path search.
*/
goto gotName;
@@ -74,8 +79,8 @@ TclpFindExecutable(argv0)
p = getenv("PATH"); /* INTL: Native. */
if (p == NULL) {
/*
- * There's no PATH environment variable; use the default that
- * is used by sh.
+ * There's no PATH environment variable; use the default that is used
+ * by sh.
*/
p = ":/bin:/usr/bin";
@@ -88,24 +93,23 @@ TclpFindExecutable(argv0)
}
/*
- * Search through all the directories named in the PATH variable
- * to see if argv[0] is in one of them. If so, use that file
- * name.
+ * Search through all the directories named in the PATH variable to see if
+ * argv[0] is in one of them. If so, use that file name.
*/
while (1) {
- while (isspace(UCHAR(*p))) { /* INTL: BUG */
+ while (TclIsSpaceProc(*p)) {
p++;
}
name = p;
while ((*p != ':') && (*p != 0)) {
p++;
}
- Tcl_DStringSetLength(&buffer, 0);
+ TclDStringClear(&buffer);
if (p != name) {
Tcl_DStringAppend(&buffer, name, p - name);
if (p[-1] != '/') {
- Tcl_DStringAppend(&buffer, "/", 1);
+ TclDStringAppendLiteral(&buffer, "/");
}
}
name = Tcl_DStringAppend(&buffer, argv0, -1);
@@ -116,8 +120,8 @@ TclpFindExecutable(argv0)
* strings directly.
*/
- if ((access(name, X_OK) == 0) /* INTL: Native. */
- && (stat(name, &statBuf) == 0) /* INTL: Native. */
+ if ((access(name, X_OK) == 0) /* INTL: Native. */
+ && (TclOSstat(name, &statBuf) == 0) /* INTL: Native. */
&& S_ISREG(statBuf.st_mode)) {
goto gotName;
}
@@ -129,64 +133,77 @@ TclpFindExecutable(argv0)
p++;
}
}
+ TclSetObjNameOfExecutable(Tcl_NewObj(), NULL);
goto done;
/*
- * If the name starts with "/" then just copy it to tclExecutableName.
+ * If the name starts with "/" then just store it
*/
- gotName:
- if (name[0] == '/') {
- Tcl_ExternalToUtfDString(NULL, name, -1, &nameString);
- tclNativeExecutableName = (char *)
- ckalloc((unsigned) (Tcl_DStringLength(&nameString) + 1));
- strcpy(tclNativeExecutableName, Tcl_DStringValue(&nameString));
- Tcl_DStringFree(&nameString);
+ gotName:
+#ifdef DJGPP
+ if (name[1] == ':')
+#else
+ if (name[0] == '/')
+#endif
+ {
+ encoding = Tcl_GetEncoding(NULL, NULL);
+ Tcl_ExternalToUtfDString(encoding, name, -1, &utfName);
+ TclSetObjNameOfExecutable(
+ Tcl_NewStringObj(Tcl_DStringValue(&utfName), -1), encoding);
+ Tcl_DStringFree(&utfName);
goto done;
}
/*
- * The name is relative to the current working directory. First
- * strip off a leading "./", if any, then add the full path name of
- * the current working directory.
+ * The name is relative to the current working directory. First strip off
+ * a leading "./", if any, then add the full path name of the current
+ * working directory.
*/
if ((name[0] == '.') && (name[1] == '/')) {
name += 2;
}
- Tcl_ExternalToUtfDString(NULL, name, -1, &nameString);
+ Tcl_DStringInit(&nameString);
+ Tcl_DStringAppend(&nameString, name, -1);
+
+ TclpGetCwd(NULL, &cwd);
Tcl_DStringFree(&buffer);
- TclpGetCwd(NULL, &buffer);
-
- length = Tcl_DStringLength(&buffer) + Tcl_DStringLength(&nameString) + 2;
- tclNativeExecutableName = (char *) ckalloc((unsigned) length);
- strcpy(tclNativeExecutableName, Tcl_DStringValue(&buffer));
- tclNativeExecutableName[Tcl_DStringLength(&buffer)] = '/';
- strcpy(tclNativeExecutableName + Tcl_DStringLength(&buffer) + 1,
- Tcl_DStringValue(&nameString));
+ Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&cwd),
+ Tcl_DStringLength(&cwd), &buffer);
+ if (Tcl_DStringValue(&cwd)[Tcl_DStringLength(&cwd) -1] != '/') {
+ TclDStringAppendLiteral(&buffer, "/");
+ }
+ Tcl_DStringFree(&cwd);
+ TclDStringAppendDString(&buffer, &nameString);
Tcl_DStringFree(&nameString);
-
- done:
+
+ encoding = Tcl_GetEncoding(NULL, NULL);
+ Tcl_ExternalToUtfDString(encoding, Tcl_DStringValue(&buffer), -1,
+ &utfName);
+ TclSetObjNameOfExecutable(
+ Tcl_NewStringObj(Tcl_DStringValue(&utfName), -1), encoding);
+ Tcl_DStringFree(&utfName);
+
+ done:
Tcl_DStringFree(&buffer);
- return tclNativeExecutableName;
+#endif
}
/*
*----------------------------------------------------------------------
*
- * TclpMatchFilesTypes --
+ * TclpMatchInDirectory --
*
- * This routine is used by the globbing code to search a
- * directory for all files which match a given pattern.
+ * This routine is used by the globbing code to search a directory for
+ * all files which match a given pattern.
*
- * Results:
- * If the tail argument is NULL, then the matching files are
- * added to the the interp's result. Otherwise, TclDoGlob is called
- * recursively for each matching subdirectory. The return value
- * is a standard Tcl result indicating whether an error occurred
- * in globbing.
+ * Results:
+ * The return value is a standard Tcl result indicating whether an error
+ * occurred in globbing. Errors are left in interp, good results are
+ * [lappend]ed to resultPtr (which must be a valid object).
*
* Side effects:
* None.
@@ -195,245 +212,348 @@ TclpFindExecutable(argv0)
*/
int
-TclpMatchFilesTypes(interp, separators, dirPtr, pattern, tail, types)
- Tcl_Interp *interp; /* Interpreter to receive results. */
- char *separators; /* Directory separators to pass to TclDoGlob */
- Tcl_DString *dirPtr; /* Contains path to directory to search. */
- char *pattern; /* Pattern to match against. */
- char *tail; /* Pointer to end of pattern. Tail must
- * point to a location in pattern and must
- * not be static. */
- GlobTypeData *types; /* Object containing list of acceptable types.
- * May be NULL. */
+TclpMatchInDirectory(
+ Tcl_Interp *interp, /* Interpreter to receive errors. */
+ Tcl_Obj *resultPtr, /* List object to lappend results. */
+ Tcl_Obj *pathPtr, /* Contains path to directory to search. */
+ const char *pattern, /* Pattern to match against. */
+ Tcl_GlobTypeData *types) /* Object containing list of acceptable types.
+ * May be NULL. In particular the directory
+ * flag is very important. */
{
- char *native, *fname, *dirName, *patternEnd = tail;
- char savedChar = 0; /* lint. */
- DIR *d;
- Tcl_DString ds;
- struct stat statBuf;
- int matchHidden;
- int result = TCL_OK;
- int baseLength = Tcl_DStringLength(dirPtr);
- Tcl_Obj *resultPtr;
+ const char *native;
+ Tcl_Obj *fileNamePtr;
+ int matchResult = 0;
- /*
- * Make sure that the directory part of the name really is a
- * directory. If the directory name is "", use the name "."
- * instead, because some UNIX systems don't treat "" like "."
- * automatically. Keep the "" for use in generating file names,
- * otherwise "glob foo.c" would return "./foo.c".
- */
+ if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) {
+ /*
+ * The native filesystem never adds mounts.
+ */
- if (Tcl_DStringLength(dirPtr) == 0) {
- dirName = ".";
- } else {
- dirName = Tcl_DStringValue(dirPtr);
+ return TCL_OK;
}
- if ((TclpStat(dirName, &statBuf) != 0) /* INTL: UTF-8. */
- || !S_ISDIR(statBuf.st_mode)) {
- return TCL_OK;
+ fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr);
+ if (fileNamePtr == NULL) {
+ return TCL_ERROR;
}
- /*
- * Check to see if the pattern needs to compare with hidden files.
- */
+ if (pattern == NULL || (*pattern == '\0')) {
+ /*
+ * Match a file directly.
+ */
- if ((pattern[0] == '.')
- || ((pattern[0] == '\\') && (pattern[1] == '.'))) {
- matchHidden = 1;
- } else {
- matchHidden = 0;
- }
+ Tcl_Obj *tailPtr;
+ const char *nativeTail;
- /*
- * Now open the directory for reading and iterate over the contents.
- */
+ native = Tcl_FSGetNativePath(pathPtr);
+ tailPtr = TclPathPart(interp, pathPtr, TCL_PATH_TAIL);
+ nativeTail = Tcl_FSGetNativePath(tailPtr);
+ matchResult = NativeMatchType(interp, native, nativeTail, types);
+ if (matchResult == 1) {
+ Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
+ }
+ Tcl_DecrRefCount(tailPtr);
+ Tcl_DecrRefCount(fileNamePtr);
+ } else {
+ DIR *d;
+ Tcl_DirEntry *entryPtr;
+ const char *dirName;
+ int dirLength, nativeDirLen;
+ int matchHidden, matchHiddenPat;
+ Tcl_StatBuf statBuf;
+ Tcl_DString ds; /* native encoding of dir */
+ Tcl_DString dsOrig; /* utf-8 encoding of dir */
- native = Tcl_UtfToExternalDString(NULL, dirName, -1, &ds);
- d = opendir(native); /* INTL: Native. */
- Tcl_DStringFree(&ds);
- if (d == NULL) {
- Tcl_ResetResult(interp);
+ Tcl_DStringInit(&dsOrig);
+ dirName = Tcl_GetStringFromObj(fileNamePtr, &dirLength);
+ Tcl_DStringAppend(&dsOrig, dirName, dirLength);
/*
- * Strip off a trailing '/' if necessary, before reporting the error.
+ * Make sure that the directory part of the name really is a
+ * directory. If the directory name is "", use the name "." instead,
+ * because some UNIX systems don't treat "" like "." automatically.
+ * Keep the "" for use in generating file names, otherwise "glob
+ * foo.c" would return "./foo.c".
*/
- if (baseLength > 0) {
- savedChar = (Tcl_DStringValue(dirPtr))[baseLength-1];
- if (savedChar == '/') {
- (Tcl_DStringValue(dirPtr))[baseLength-1] = '\0';
+ if (dirLength == 0) {
+ dirName = ".";
+ } else {
+ dirName = Tcl_DStringValue(&dsOrig);
+
+ /*
+ * Make sure we have a trailing directory delimiter.
+ */
+
+ if (dirName[dirLength-1] != '/') {
+ dirName = TclDStringAppendLiteral(&dsOrig, "/");
+ dirLength++;
}
}
- Tcl_AppendResult(interp, "couldn't read directory \"",
- Tcl_DStringValue(dirPtr), "\": ",
- Tcl_PosixError(interp), (char *) NULL);
- if (baseLength > 0) {
- (Tcl_DStringValue(dirPtr))[baseLength-1] = savedChar;
- }
- return TCL_ERROR;
- }
- /*
- * Clean up the end of the pattern and the tail pointer. Leave
- * the tail pointing to the first character after the path separator
- * following the pattern, or NULL. Also, ensure that the pattern
- * is null-terminated.
- */
+ /*
+ * Now open the directory for reading and iterate over the contents.
+ */
- if (*tail == '\\') {
- tail++;
- }
- if (*tail == '\0') {
- tail = NULL;
- } else {
- tail++;
- }
- savedChar = *patternEnd;
- *patternEnd = '\0';
+ native = Tcl_UtfToExternalDString(NULL, dirName, -1, &ds);
- resultPtr = Tcl_GetObjResult(interp);
- while (1) {
- char *utf;
- struct dirent *entryPtr;
-
- entryPtr = readdir(d); /* INTL: Native. */
- if (entryPtr == NULL) {
- break;
+ if ((TclOSstat(native, &statBuf) != 0) /* INTL: Native. */
+ || !S_ISDIR(statBuf.st_mode)) {
+ Tcl_DStringFree(&dsOrig);
+ Tcl_DStringFree(&ds);
+ Tcl_DecrRefCount(fileNamePtr);
+ return TCL_OK;
}
- if (types != NULL && (types->perm & TCL_GLOB_PERM_HIDDEN)) {
- /*
- * We explicitly asked for hidden files, so turn around
- * and ignore any file which isn't hidden.
- */
- if (*entryPtr->d_name != '.') {
- continue;
+ d = opendir(native); /* INTL: Native. */
+ if (d == NULL) {
+ Tcl_DStringFree(&ds);
+ if (interp != NULL) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "couldn't read directory \"%s\": %s",
+ Tcl_DStringValue(&dsOrig), Tcl_PosixError(interp)));
}
- } else if (!matchHidden && (*entryPtr->d_name == '.')) {
- /*
- * Don't match names starting with "." unless the "." is
- * present in the pattern.
- */
- continue;
+ Tcl_DStringFree(&dsOrig);
+ Tcl_DecrRefCount(fileNamePtr);
+ return TCL_ERROR;
}
+ nativeDirLen = Tcl_DStringLength(&ds);
+
/*
- * Now check to see if the file matches. If there are more
- * characters to be processed, then ensure matching files are
- * directories before calling TclDoGlob. Otherwise, just add
- * the file to the result.
+ * Check to see if -type or the pattern requests hidden files.
*/
- utf = Tcl_ExternalToUtfDString(NULL, entryPtr->d_name, -1, &ds);
- if (Tcl_StringMatch(utf, pattern) != 0) {
- Tcl_DStringSetLength(dirPtr, baseLength);
- Tcl_DStringAppend(dirPtr, utf, -1);
- fname = Tcl_DStringValue(dirPtr);
- if (tail == NULL) {
+ matchHiddenPat = (pattern[0] == '.')
+ || ((pattern[0] == '\\') && (pattern[1] == '.'));
+ matchHidden = matchHiddenPat
+ || (types && (types->perm & TCL_GLOB_PERM_HIDDEN));
+ while ((entryPtr = TclOSreaddir(d)) != NULL) { /* INTL: Native. */
+ Tcl_DString utfDs;
+ const char *utfname;
+
+ /*
+ * Skip this file if it doesn't agree with the hidden parameters
+ * requested by the user (via -type or pattern).
+ */
+
+ if (*entryPtr->d_name == '.') {
+ if (!matchHidden) {
+ continue;
+ }
+ } else {
+#ifdef MAC_OSX_TCL
+ if (matchHiddenPat) {
+ continue;
+ }
+ /* Also need to check HFS hidden flag in TclMacOSXMatchType. */
+#else
+ if (matchHidden) {
+ continue;
+ }
+#endif
+ }
+
+ /*
+ * Now check to see if the file matches, according to both type
+ * and pattern. If so, add the file to the result.
+ */
+
+ utfname = Tcl_ExternalToUtfDString(NULL, entryPtr->d_name, -1,
+ &utfDs);
+ if (Tcl_StringCaseMatch(utfname, pattern, 0)) {
int typeOk = 1;
+
if (types != NULL) {
- if (types->perm != 0) {
- struct stat buf;
-
- if (TclpStat(fname, &buf) != 0) {
- panic("stat failed on known file");
- }
- /*
- * readonly means that there are NO write permissions
- * (even for user), but execute is OK for anybody
- */
- if (
- ((types->perm & TCL_GLOB_PERM_RONLY) &&
- (buf.st_mode & (S_IWOTH|S_IWGRP|S_IWUSR))) ||
- ((types->perm & TCL_GLOB_PERM_R) &&
- (TclpAccess(fname, R_OK) != 0)) ||
- ((types->perm & TCL_GLOB_PERM_W) &&
- (TclpAccess(fname, W_OK) != 0)) ||
- ((types->perm & TCL_GLOB_PERM_X) &&
- (TclpAccess(fname, X_OK) != 0))
- ) {
- typeOk = 0;
- }
- }
- if (typeOk && (types->type != 0)) {
- struct stat buf;
- /*
- * We must match at least one flag to be listed
- */
- typeOk = 0;
- if (TclpLstat(fname, &buf) >= 0) {
- /*
- * In order bcdpfls as in 'find -t'
- */
- if (
- ((types->type & TCL_GLOB_TYPE_BLOCK) &&
- S_ISBLK(buf.st_mode)) ||
- ((types->type & TCL_GLOB_TYPE_CHAR) &&
- S_ISCHR(buf.st_mode)) ||
- ((types->type & TCL_GLOB_TYPE_DIR) &&
- S_ISDIR(buf.st_mode)) ||
- ((types->type & TCL_GLOB_TYPE_PIPE) &&
- S_ISFIFO(buf.st_mode)) ||
- ((types->type & TCL_GLOB_TYPE_FILE) &&
- S_ISREG(buf.st_mode))
-#ifdef S_ISLNK
- || ((types->type & TCL_GLOB_TYPE_LINK) &&
- S_ISLNK(buf.st_mode))
-#endif
-#ifdef S_ISSOCK
- || ((types->type & TCL_GLOB_TYPE_SOCK) &&
- S_ISSOCK(buf.st_mode))
-#endif
- ) {
- typeOk = 1;
- }
- } else {
- /* Posix error occurred */
- }
- }
+ Tcl_DStringSetLength(&ds, nativeDirLen);
+ native = Tcl_DStringAppend(&ds, entryPtr->d_name, -1);
+ matchResult = NativeMatchType(interp, native,
+ entryPtr->d_name, types);
+ typeOk = (matchResult == 1);
}
if (typeOk) {
- Tcl_ListObjAppendElement(interp, resultPtr,
- Tcl_NewStringObj(fname,
- Tcl_DStringLength(dirPtr)));
- }
- } else if ((TclpStat(fname, &statBuf) == 0)
- && S_ISDIR(statBuf.st_mode)) {
- Tcl_DStringAppend(dirPtr, "/", 1);
- result = TclDoGlob(interp, separators, dirPtr, tail, types);
- if (result != TCL_OK) {
- Tcl_DStringFree(&ds);
- break;
+ Tcl_ListObjAppendElement(interp, resultPtr,
+ TclNewFSPathObj(pathPtr, utfname,
+ Tcl_DStringLength(&utfDs)));
}
}
+ Tcl_DStringFree(&utfDs);
+ if (matchResult < 0) {
+ break;
+ }
}
+
+ closedir(d);
Tcl_DStringFree(&ds);
+ Tcl_DStringFree(&dsOrig);
+ Tcl_DecrRefCount(fileNamePtr);
}
- *patternEnd = savedChar;
-
- closedir(d);
- return result;
+ if (matchResult < 0) {
+ return TCL_ERROR;
+ }
+ return TCL_OK;
}
-/*
- * TclpMatchFiles --
- *
- * This function is now obsolete. Call the above function
- * 'TclpMatchFilesTypes' instead.
+/*
+ *----------------------------------------------------------------------
+ *
+ * NativeMatchType --
+ *
+ * This routine is used by the globbing code to check if a file matches a
+ * given type description.
+ *
+ * Results:
+ * The return value is 1, 0 or -1 indicating whether the file matches the
+ * given criteria, does not match them, or an error occurred (in which
+ * case an error is left in interp).
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-int
-TclpMatchFiles(interp, separators, dirPtr, pattern, tail)
- Tcl_Interp *interp; /* Interpreter to receive results. */
- char *separators; /* Directory separators to pass to TclDoGlob */
- Tcl_DString *dirPtr; /* Contains path to directory to search. */
- char *pattern; /* Pattern to match against. */
- char *tail; /* Pointer to end of pattern. Tail must
- * point to a location in pattern and must
- * not be static. */
+
+static int
+NativeMatchType(
+ Tcl_Interp *interp, /* Interpreter to receive errors. */
+ const char *nativeEntry, /* Native path to check. */
+ const char *nativeName, /* Native filename to check. */
+ Tcl_GlobTypeData *types) /* Type description to match against. */
{
- return TclpMatchFilesTypes(interp,separators,dirPtr,pattern,tail,NULL);
+ Tcl_StatBuf buf;
+
+ if (types == NULL) {
+ /*
+ * Simply check for the file's existence, but do it with lstat, in
+ * case it is a link to a file which doesn't exist (since that case
+ * would not show up if we used 'access' or 'stat')
+ */
+
+ if (TclOSlstat(nativeEntry, &buf) != 0) {
+ return 0;
+ }
+ return 1;
+ }
+
+ if (types->perm != 0) {
+ if (TclOSstat(nativeEntry, &buf) != 0) {
+ /*
+ * Either the file has disappeared between the 'readdir' call and
+ * the 'stat' call, or the file is a link to a file which doesn't
+ * exist (which we could ascertain with lstat), or there is some
+ * other strange problem. In all these cases, we define this to
+ * mean the file does not match any defined permission, and
+ * therefore it is not added to the list of files to return.
+ */
+
+ return 0;
+ }
+
+ /*
+ * readonly means that there are NO write permissions (even for user),
+ * but execute is OK for anybody OR that the user immutable flag is
+ * set (where supported).
+ */
+
+ if (((types->perm & TCL_GLOB_PERM_RONLY) &&
+#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE)
+ !(buf.st_flags & UF_IMMUTABLE) &&
+#endif
+ (buf.st_mode & (S_IWOTH|S_IWGRP|S_IWUSR))) ||
+ ((types->perm & TCL_GLOB_PERM_R) &&
+ (access(nativeEntry, R_OK) != 0)) ||
+ ((types->perm & TCL_GLOB_PERM_W) &&
+ (access(nativeEntry, W_OK) != 0)) ||
+ ((types->perm & TCL_GLOB_PERM_X) &&
+ (access(nativeEntry, X_OK) != 0))
+#ifndef MAC_OSX_TCL
+ || ((types->perm & TCL_GLOB_PERM_HIDDEN) &&
+ (*nativeName != '.'))
+#endif /* MAC_OSX_TCL */
+ ) {
+ return 0;
+ }
+ }
+ if (types->type != 0) {
+ if (types->perm == 0) {
+ /*
+ * We haven't yet done a stat on the file.
+ */
+
+ if (TclOSstat(nativeEntry, &buf) != 0) {
+ /*
+ * Posix error occurred. The only ok case is if this is a link
+ * to a nonexistent file, and the user did 'glob -l'. So we
+ * check that here:
+ */
+
+ if ((types->type & TCL_GLOB_TYPE_LINK)
+ && (TclOSlstat(nativeEntry, &buf) == 0)
+ && S_ISLNK(buf.st_mode)) {
+ return 1;
+ }
+ return 0;
+ }
+ }
+
+ /*
+ * In order bcdpsfl as in 'find -t'
+ */
+
+ if ( ((types->type & TCL_GLOB_TYPE_BLOCK)&& S_ISBLK(buf.st_mode)) ||
+ ((types->type & TCL_GLOB_TYPE_CHAR) && S_ISCHR(buf.st_mode)) ||
+ ((types->type & TCL_GLOB_TYPE_DIR) && S_ISDIR(buf.st_mode)) ||
+ ((types->type & TCL_GLOB_TYPE_PIPE) && S_ISFIFO(buf.st_mode))||
+#ifdef S_ISSOCK
+ ((types->type & TCL_GLOB_TYPE_SOCK) && S_ISSOCK(buf.st_mode))||
+#endif /* S_ISSOCK */
+ ((types->type & TCL_GLOB_TYPE_FILE) && S_ISREG(buf.st_mode))) {
+ /*
+ * Do nothing - this file is ok.
+ */
+ } else {
+#ifdef S_ISLNK
+ if ((types->type & TCL_GLOB_TYPE_LINK)
+ && (TclOSlstat(nativeEntry, &buf) == 0)
+ && S_ISLNK(buf.st_mode)) {
+ goto filetypeOK;
+ }
+#endif /* S_ISLNK */
+ return 0;
+ }
+ }
+ filetypeOK:
+
+ /*
+ * If we're on OSX, we also have to worry about matching the file creator
+ * code (if specified). Do that now.
+ */
+
+#ifdef MAC_OSX_TCL
+ if (types->macType != NULL || types->macCreator != NULL ||
+ (types->perm & TCL_GLOB_PERM_HIDDEN)) {
+ int matchResult;
+
+ if (types->perm == 0 && types->type == 0) {
+ /*
+ * We haven't yet done a stat on the file.
+ */
+
+ if (TclOSstat(nativeEntry, &buf) != 0) {
+ return 0;
+ }
+ }
+
+ matchResult = TclMacOSXMatchType(interp, nativeEntry, nativeName,
+ &buf, types);
+ if (matchResult != 1) {
+ return matchResult;
+ }
+ }
+#endif /* MAC_OSX_TCL */
+
+ return 1;
}
/*
@@ -441,15 +561,15 @@ TclpMatchFiles(interp, separators, dirPtr, pattern, tail)
*
* TclpGetUserHome --
*
- * This function takes the specified user name and finds their
- * home directory.
+ * This function takes the specified user name and finds their home
+ * directory.
*
* Results:
* The result is a pointer to a string specifying the user's home
* directory, or NULL if the user's home directory could not be
- * determined. Storage for the result string is allocated in
- * bufferPtr; the caller must call Tcl_DStringFree() when the result
- * is no longer needed.
+ * determined. Storage for the result string is allocated in bufferPtr;
+ * the caller must call Tcl_DStringFree() when the result is no longer
+ * needed.
*
* Side effects:
* None.
@@ -457,33 +577,30 @@ TclpMatchFiles(interp, separators, dirPtr, pattern, tail)
*----------------------------------------------------------------------
*/
-char *
-TclpGetUserHome(name, bufferPtr)
- CONST char *name; /* User name for desired home directory. */
- Tcl_DString *bufferPtr; /* Uninitialized or free DString filled
- * with name of user's home directory. */
+const char *
+TclpGetUserHome(
+ const char *name, /* User name for desired home directory. */
+ Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
+ * name of user's home directory. */
{
struct passwd *pwPtr;
Tcl_DString ds;
- char *native;
+ const char *native = Tcl_UtfToExternalDString(NULL, name, -1, &ds);
- native = Tcl_UtfToExternalDString(NULL, name, -1, &ds);
- pwPtr = getpwnam(native); /* INTL: Native. */
+ pwPtr = TclpGetPwNam(native); /* INTL: Native. */
Tcl_DStringFree(&ds);
-
+
if (pwPtr == NULL) {
- endpwent();
return NULL;
}
Tcl_ExternalToUtfDString(NULL, pwPtr->pw_dir, -1, bufferPtr);
- endpwent();
return Tcl_DStringValue(bufferPtr);
}
/*
*---------------------------------------------------------------------------
*
- * TclpAccess --
+ * TclpObjAccess --
*
* This function replaces the library version of access().
*
@@ -497,25 +614,22 @@ TclpGetUserHome(name, bufferPtr)
*/
int
-TclpAccess(path, mode)
- CONST char *path; /* Path of file to access (UTF-8). */
- int mode; /* Permission setting. */
+TclpObjAccess(
+ Tcl_Obj *pathPtr, /* Path of file to access */
+ int mode) /* Permission setting. */
{
- int result;
- Tcl_DString ds;
- char *native;
-
- native = Tcl_UtfToExternalDString(NULL, path, -1, &ds);
- result = access(native, mode); /* INTL: Native. */
- Tcl_DStringFree(&ds);
+ const char *path = Tcl_FSGetNativePath(pathPtr);
- return result;
+ if (path == NULL) {
+ return -1;
+ }
+ return access(path, mode);
}
/*
*---------------------------------------------------------------------------
*
- * TclpChdir --
+ * TclpObjChdir --
*
* This function replaces the library version of chdir().
*
@@ -523,30 +637,27 @@ TclpAccess(path, mode)
* See chdir() documentation.
*
* Side effects:
- * See chdir() documentation.
+ * See chdir() documentation.
*
*---------------------------------------------------------------------------
*/
int
-TclpChdir(dirName)
- CONST char *dirName; /* Path to new working directory (UTF-8). */
+TclpObjChdir(
+ Tcl_Obj *pathPtr) /* Path to new working directory */
{
- int result;
- Tcl_DString ds;
- char *native;
-
- native = Tcl_UtfToExternalDString(NULL, dirName, -1, &ds);
- result = chdir(native); /* INTL: Native. */
- Tcl_DStringFree(&ds);
+ const char *path = Tcl_FSGetNativePath(pathPtr);
- return result;
+ if (path == NULL) {
+ return -1;
+ }
+ return chdir(path);
}
/*
*----------------------------------------------------------------------
*
- * TclpLstat --
+ * TclpObjLstat --
*
* This function replaces the library version of lstat().
*
@@ -560,35 +671,27 @@ TclpChdir(dirName)
*/
int
-TclpLstat(path, bufPtr)
- CONST char *path; /* Path of file to stat (UTF-8). */
- struct stat *bufPtr; /* Filled with results of stat call. */
+TclpObjLstat(
+ Tcl_Obj *pathPtr, /* Path of file to stat */
+ Tcl_StatBuf *bufPtr) /* Filled with results of stat call. */
{
- int result;
- Tcl_DString ds;
- char *native;
-
- native = Tcl_UtfToExternalDString(NULL, path, -1, &ds);
- result = lstat(native, bufPtr); /* INTL: Native. */
- Tcl_DStringFree(&ds);
-
- return result;
+ return TclOSlstat(Tcl_FSGetNativePath(pathPtr), bufPtr);
}
/*
*---------------------------------------------------------------------------
*
- * TclpGetCwd --
+ * TclpGetNativeCwd --
*
* This function replaces the library version of getcwd().
*
* Results:
- * The result is a pointer to a string specifying the current
- * directory, or NULL if the current directory could not be
- * determined. If NULL is returned, an error message is left in the
- * interp's result. Storage for the result string is allocated in
- * bufferPtr; the caller must call Tcl_DStringFree() when the result
- * is no longer needed.
+ * The input and output are filesystem paths in native form. The result
+ * is either the given clientData, if the working directory hasn't
+ * changed, or a new clientData (owned by our caller), giving the new
+ * native path, or NULL if the current directory could not be determined.
+ * If NULL is returned, the caller can examine the standard posix error
+ * codes to determine the cause of the problem.
*
* Side effects:
* None.
@@ -596,23 +699,76 @@ TclpLstat(path, bufPtr)
*----------------------------------------------------------------------
*/
-char *
-TclpGetCwd(interp, bufferPtr)
- Tcl_Interp *interp; /* If non-NULL, used for error reporting. */
- Tcl_DString *bufferPtr; /* Uninitialized or free DString filled
- * with name of current directory. */
+ClientData
+TclpGetNativeCwd(
+ ClientData clientData)
{
char buffer[MAXPATHLEN+1];
#ifdef USEGETWD
if (getwd(buffer) == NULL) { /* INTL: Native. */
+ return NULL;
+ }
#else
- if (getcwd(buffer, MAXPATHLEN + 1) == NULL) { /* INTL: Native. */
-#endif
+ if (getcwd(buffer, MAXPATHLEN+1) == NULL) { /* INTL: Native. */
+ return NULL;
+ }
+#endif /* USEGETWD */
+
+ if ((clientData == NULL) || strcmp(buffer, (const char *) clientData)) {
+ char *newCd = ckalloc(strlen(buffer) + 1);
+
+ strcpy(newCd, buffer);
+ return newCd;
+ }
+
+ /*
+ * No change to pwd.
+ */
+
+ return clientData;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TclpGetCwd --
+ *
+ * This function replaces the library version of getcwd(). (Obsolete
+ * function, only retained for old extensions which may call it
+ * directly).
+ *
+ * Results:
+ * The result is a pointer to a string specifying the current directory,
+ * or NULL if the current directory could not be determined. If NULL is
+ * returned, an error message is left in the interp's result. Storage for
+ * the result string is allocated in bufferPtr; the caller must call
+ * Tcl_DStringFree() when the result is no longer needed.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+const char *
+TclpGetCwd(
+ Tcl_Interp *interp, /* If non-NULL, used for error reporting. */
+ Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
+ * name of current directory. */
+{
+ char buffer[MAXPATHLEN+1];
+
+#ifdef USEGETWD
+ if (getwd(buffer) == NULL) /* INTL: Native. */
+#else
+ if (getcwd(buffer, MAXPATHLEN+1) == NULL) /* INTL: Native. */
+#endif /* USEGETWD */
+ {
if (interp != NULL) {
- Tcl_AppendResult(interp,
- "error getting working directory name: ",
- Tcl_PosixError(interp), (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "error getting working directory name: %s",
+ Tcl_PosixError(interp)));
}
return NULL;
}
@@ -627,11 +783,11 @@ TclpGetCwd(interp, bufferPtr)
* This function replaces the library version of readlink().
*
* Results:
- * The result is a pointer to a string specifying the contents
- * of the symbolic link given by 'path', or NULL if the symbolic
- * link could not be read. Storage for the result string is
- * allocated in bufferPtr; the caller must call Tcl_DStringFree()
- * when the result is no longer needed.
+ * The result is a pointer to a string specifying the contents of the
+ * symbolic link given by 'path', or NULL if the symbolic link could not
+ * be read. Storage for the result string is allocated in bufferPtr; the
+ * caller must call Tcl_DStringFree() when the result is no longer
+ * needed.
*
* Side effects:
* See readlink() documentation.
@@ -640,32 +796,36 @@ TclpGetCwd(interp, bufferPtr)
*/
char *
-TclpReadlink(path, linkPtr)
- CONST char *path; /* Path of file to readlink (UTF-8). */
- Tcl_DString *linkPtr; /* Uninitialized or free DString filled
- * with contents of link (UTF-8). */
+TclpReadlink(
+ const char *path, /* Path of file to readlink (UTF-8). */
+ Tcl_DString *linkPtr) /* Uninitialized or free DString filled with
+ * contents of link (UTF-8). */
{
+#ifndef DJGPP
char link[MAXPATHLEN];
int length;
- char *native;
+ const char *native;
Tcl_DString ds;
native = Tcl_UtfToExternalDString(NULL, path, -1, &ds);
length = readlink(native, link, sizeof(link)); /* INTL: Native. */
Tcl_DStringFree(&ds);
-
+
if (length < 0) {
return NULL;
}
Tcl_ExternalToUtfDString(NULL, link, length, linkPtr);
return Tcl_DStringValue(linkPtr);
+#else
+ return NULL;
+#endif /* !DJGPP */
}
/*
*----------------------------------------------------------------------
*
- * TclpStat --
+ * TclpObjStat --
*
* This function replaces the library version of stat().
*
@@ -679,18 +839,402 @@ TclpReadlink(path, linkPtr)
*/
int
-TclpStat(path, bufPtr)
- CONST char *path; /* Path of file to stat (in UTF-8). */
- struct stat *bufPtr; /* Filled with results of stat call. */
+TclpObjStat(
+ Tcl_Obj *pathPtr, /* Path of file to stat */
+ Tcl_StatBuf *bufPtr) /* Filled with results of stat call. */
+{
+ const char *path = Tcl_FSGetNativePath(pathPtr);
+
+ if (path == NULL) {
+ return -1;
+ }
+ return TclOSstat(path, bufPtr);
+}
+
+#ifdef S_IFLNK
+
+Tcl_Obj *
+TclpObjLink(
+ Tcl_Obj *pathPtr,
+ Tcl_Obj *toPtr,
+ int linkAction)
+{
+ if (toPtr != NULL) {
+ const char *src = Tcl_FSGetNativePath(pathPtr);
+ const char *target = NULL;
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ /*
+ * If we're making a symbolic link and the path is relative, then we
+ * must check whether it exists _relative_ to the directory in which
+ * the src is found (not relative to the current cwd which is just not
+ * relevant in this case).
+ *
+ * If we're making a hard link, then a relative path is just converted
+ * to absolute relative to the cwd.
+ */
+
+ if ((linkAction & TCL_CREATE_SYMBOLIC_LINK)
+ && (Tcl_FSGetPathType(toPtr) == TCL_PATH_RELATIVE)) {
+ Tcl_Obj *dirPtr, *absPtr;
+
+ dirPtr = TclPathPart(NULL, pathPtr, TCL_PATH_DIRNAME);
+ if (dirPtr == NULL) {
+ return NULL;
+ }
+ absPtr = Tcl_FSJoinToPath(dirPtr, 1, &toPtr);
+ Tcl_IncrRefCount(absPtr);
+ if (Tcl_FSAccess(absPtr, F_OK) == -1) {
+ Tcl_DecrRefCount(absPtr);
+ Tcl_DecrRefCount(dirPtr);
+
+ /*
+ * Target doesn't exist.
+ */
+
+ errno = ENOENT;
+ return NULL;
+ }
+
+ /*
+ * Target exists; we'll construct the relative path we want below.
+ */
+
+ Tcl_DecrRefCount(absPtr);
+ Tcl_DecrRefCount(dirPtr);
+ } else {
+ target = Tcl_FSGetNativePath(toPtr);
+ if (target == NULL) {
+ return NULL;
+ }
+ if (access(target, F_OK) == -1) {
+ /*
+ * Target doesn't exist.
+ */
+
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+
+ if (access(src, F_OK) != -1) {
+ /*
+ * Src exists.
+ */
+
+ errno = EEXIST;
+ return NULL;
+ }
+
+ /*
+ * Check symbolic link flag first, since we prefer to create these.
+ */
+
+ if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
+ int targetLen;
+ Tcl_DString ds;
+ Tcl_Obj *transPtr;
+
+ /*
+ * Now we don't want to link to the absolute, normalized path.
+ * Relative links are quite acceptable (but links to ~user are not
+ * -- these must be expanded first).
+ */
+
+ transPtr = Tcl_FSGetTranslatedPath(NULL, toPtr);
+ if (transPtr == NULL) {
+ return NULL;
+ }
+ target = Tcl_GetStringFromObj(transPtr, &targetLen);
+ target = Tcl_UtfToExternalDString(NULL, target, targetLen, &ds);
+ Tcl_DecrRefCount(transPtr);
+
+ if (symlink(target, src) != 0) {
+ toPtr = NULL;
+ }
+ Tcl_DStringFree(&ds);
+ } else if (linkAction & TCL_CREATE_HARD_LINK) {
+ if (link(target, src) != 0) {
+ return NULL;
+ }
+ } else {
+ errno = ENODEV;
+ return NULL;
+ }
+ return toPtr;
+ } else {
+ Tcl_Obj *linkPtr = NULL;
+
+ char link[MAXPATHLEN];
+ int length;
+ Tcl_DString ds;
+ Tcl_Obj *transPtr;
+
+ transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr);
+ if (transPtr == NULL) {
+ return NULL;
+ }
+ Tcl_DecrRefCount(transPtr);
+
+ length = readlink(Tcl_FSGetNativePath(pathPtr), link, sizeof(link));
+ if (length < 0) {
+ return NULL;
+ }
+
+ Tcl_ExternalToUtfDString(NULL, link, length, &ds);
+ linkPtr = TclDStringToObj(&ds);
+ Tcl_IncrRefCount(linkPtr);
+ return linkPtr;
+ }
+}
+#endif /* S_IFLNK */
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TclpFilesystemPathType --
+ *
+ * This function is part of the native filesystem support, and returns
+ * the path type of the given path. Right now it simply returns NULL. In
+ * the future it could return specific path types, like 'nfs', 'samba',
+ * 'FAT32', etc.
+ *
+ * Results:
+ * NULL at present.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+Tcl_Obj *
+TclpFilesystemPathType(
+ Tcl_Obj *pathPtr)
+{
+ /*
+ * All native paths are of the same type.
+ */
+
+ return NULL;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TclpNativeToNormalized --
+ *
+ * Convert native format to a normalized path object, with refCount of
+ * zero.
+ *
+ * Currently assumes all native paths are actually normalized already, so
+ * if the path given is not normalized this will actually just convert to
+ * a valid string path, but not necessarily a normalized one.
+ *
+ * Results:
+ * A valid normalized path.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+Tcl_Obj *
+TclpNativeToNormalized(
+ ClientData clientData)
{
- int result;
Tcl_DString ds;
- char *native;
-
- native = Tcl_UtfToExternalDString(NULL, path, -1, &ds);
- result = stat(native, bufPtr); /* INTL: Native. */
+
+ Tcl_ExternalToUtfDString(NULL, (const char *) clientData, -1, &ds);
+ return TclDStringToObj(&ds);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TclNativeCreateNativeRep --
+ *
+ * Create a native representation for the given path.
+ *
+ * Results:
+ * The nativePath representation.
+ *
+ * Side effects:
+ * Memory will be allocated. The path may need to be normalized.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+ClientData
+TclNativeCreateNativeRep(
+ Tcl_Obj *pathPtr)
+{
+ char *nativePathPtr;
+ const char *str;
+ Tcl_DString ds;
+ Tcl_Obj *validPathPtr;
+ int len;
+
+ if (TclFSCwdIsNative()) {
+ /*
+ * The cwd is native, which means we can use the translated path
+ * without worrying about normalization (this will also usually be
+ * shorter so the utf-to-external conversion will be somewhat faster).
+ */
+
+ validPathPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr);
+ if (validPathPtr == NULL) {
+ return NULL;
+ }
+ } else {
+ /*
+ * Make sure the normalized path is set.
+ */
+
+ validPathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr);
+ if (validPathPtr == NULL) {
+ return NULL;
+ }
+ Tcl_IncrRefCount(validPathPtr);
+ }
+
+ str = Tcl_GetStringFromObj(validPathPtr, &len);
+ Tcl_UtfToExternalDString(NULL, str, len, &ds);
+ len = Tcl_DStringLength(&ds) + sizeof(char);
+ if (strlen(Tcl_DStringValue(&ds)) < len - sizeof(char)) {
+ /* See bug [3118489]: NUL in filenames */
+ Tcl_DecrRefCount(validPathPtr);
+ Tcl_DStringFree(&ds);
+ return NULL;
+ }
+ Tcl_DecrRefCount(validPathPtr);
+ nativePathPtr = ckalloc(len);
+ memcpy(nativePathPtr, Tcl_DStringValue(&ds), (size_t) len);
+
Tcl_DStringFree(&ds);
+ return nativePathPtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TclNativeDupInternalRep --
+ *
+ * Duplicate the native representation.
+ *
+ * Results:
+ * The copied native representation, or NULL if it is not possible to
+ * copy the representation.
+ *
+ * Side effects:
+ * Memory will be allocated for the copy.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+ClientData
+TclNativeDupInternalRep(
+ ClientData clientData)
+{
+ char *copy;
+ size_t len;
+
+ if (clientData == NULL) {
+ return NULL;
+ }
+ /*
+ * ASCII representation when running on Unix.
+ */
+
+ len = (strlen((const char*) clientData) + 1) * sizeof(char);
+
+ copy = ckalloc(len);
+ memcpy(copy, clientData, len);
+ return copy;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TclpUtime --
+ *
+ * Set the modification date for a file.
+ *
+ * Results:
+ * 0 on success, -1 on error.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+TclpUtime(
+ Tcl_Obj *pathPtr, /* File to modify */
+ struct utimbuf *tval) /* New modification date structure */
+{
+ return utime(Tcl_FSGetNativePath(pathPtr), tval);
+}
+
+#ifdef __CYGWIN__
+
+int
+TclOSstat(
+ const char *name,
+ void *cygstat)
+{
+ struct stat buf;
+ Tcl_StatBuf *statBuf = cygstat;
+ int result = stat(name, &buf);
+
+ statBuf->st_mode = buf.st_mode;
+ statBuf->st_ino = buf.st_ino;
+ statBuf->st_dev = buf.st_dev;
+ statBuf->st_rdev = buf.st_rdev;
+ statBuf->st_nlink = buf.st_nlink;
+ statBuf->st_uid = buf.st_uid;
+ statBuf->st_gid = buf.st_gid;
+ statBuf->st_size = buf.st_size;
+ statBuf->st_atime = buf.st_atime;
+ statBuf->st_mtime = buf.st_mtime;
+ statBuf->st_ctime = buf.st_ctime;
return result;
}
+int
+TclOSlstat(
+ const char *name,
+ void *cygstat)
+{
+ struct stat buf;
+ Tcl_StatBuf *statBuf = cygstat;
+ int result = lstat(name, &buf);
+
+ statBuf->st_mode = buf.st_mode;
+ statBuf->st_ino = buf.st_ino;
+ statBuf->st_dev = buf.st_dev;
+ statBuf->st_rdev = buf.st_rdev;
+ statBuf->st_nlink = buf.st_nlink;
+ statBuf->st_uid = buf.st_uid;
+ statBuf->st_gid = buf.st_gid;
+ statBuf->st_size = buf.st_size;
+ statBuf->st_atime = buf.st_atime;
+ statBuf->st_mtime = buf.st_mtime;
+ statBuf->st_ctime = buf.st_ctime;
+ return result;
+}
+#endif /* CYGWIN */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */