tclUnixFile.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:21k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclUnixFile.c --
  3.  *
  4.  *      This file contains wrappers around UNIX file handling functions.
  5.  *      These wrappers mask differences between Windows and UNIX.
  6.  *
  7.  * Copyright (c) 1995-1998 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tclUnixFile.c,v 1.32.2.2 2003/10/31 08:46:41 vincentdarley Exp $
  13.  */
  14. #include "tclInt.h"
  15. #include "tclPort.h"
  16. static int NativeMatchType(CONST char* nativeName, Tcl_GlobTypeData *types);
  17. /*
  18.  *---------------------------------------------------------------------------
  19.  *
  20.  * TclpFindExecutable --
  21.  *
  22.  * This procedure computes the absolute path name of the current
  23.  * application, given its argv[0] value.
  24.  *
  25.  * Results:
  26.  * A dirty UTF string that is the path to the executable.  At this
  27.  * point we may not know the system encoding.  Convert the native
  28.  * string value to UTF using the default encoding.  The assumption
  29.  * is that we will still be able to parse the path given the path
  30.  * name contains ASCII string and '/' chars do not conflict with
  31.  * other UTF chars.
  32.  *
  33.  * Side effects:
  34.  * The variable tclNativeExecutableName gets filled in with the file
  35.  * name for the application, if we figured it out.  If we couldn't
  36.  * figure it out, tclNativeExecutableName is set to NULL.
  37.  *
  38.  *---------------------------------------------------------------------------
  39.  */
  40. char *
  41. TclpFindExecutable(argv0)
  42.     CONST char *argv0; /* The value of the application's argv[0]
  43.  * (native). */
  44. {
  45.     CONST char *name, *p;
  46.     Tcl_StatBuf statBuf;
  47.     int length;
  48.     Tcl_DString buffer, nameString;
  49.     if (argv0 == NULL) {
  50. return NULL;
  51.     }
  52.     if (tclNativeExecutableName != NULL) {
  53. return tclNativeExecutableName;
  54.     }
  55.     Tcl_DStringInit(&buffer);
  56.     name = argv0;
  57.     for (p = name; *p != ''; p++) {
  58. if (*p == '/') {
  59.     /*
  60.      * The name contains a slash, so use the name directly
  61.      * without doing a path search.
  62.      */
  63.     goto gotName;
  64. }
  65.     }
  66.     p = getenv("PATH"); /* INTL: Native. */
  67.     if (p == NULL) {
  68. /*
  69.  * There's no PATH environment variable; use the default that
  70.  * is used by sh.
  71.  */
  72. p = ":/bin:/usr/bin";
  73.     } else if (*p == '') {
  74. /*
  75.  * An empty path is equivalent to ".".
  76.  */
  77. p = "./";
  78.     }
  79.     /*
  80.      * Search through all the directories named in the PATH variable
  81.      * to see if argv[0] is in one of them.  If so, use that file
  82.      * name.
  83.      */
  84.     while (1) {
  85. while (isspace(UCHAR(*p))) { /* INTL: BUG */
  86.     p++;
  87. }
  88. name = p;
  89. while ((*p != ':') && (*p != 0)) {
  90.     p++;
  91. }
  92. Tcl_DStringSetLength(&buffer, 0);
  93. if (p != name) {
  94.     Tcl_DStringAppend(&buffer, name, p - name);
  95.     if (p[-1] != '/') {
  96. Tcl_DStringAppend(&buffer, "/", 1);
  97.     }
  98. }
  99. name = Tcl_DStringAppend(&buffer, argv0, -1);
  100. /*
  101.  * INTL: The following calls to access() and stat() should not be
  102.  * converted to Tclp routines because they need to operate on native
  103.  * strings directly.
  104.  */
  105. if ((access(name, X_OK) == 0) /* INTL: Native. */
  106. && (TclOSstat(name, &statBuf) == 0) /* INTL: Native. */
  107. && S_ISREG(statBuf.st_mode)) {
  108.     goto gotName;
  109. }
  110. if (*p == '') {
  111.     break;
  112. } else if (*(p+1) == 0) {
  113.     p = "./";
  114. } else {
  115.     p++;
  116. }
  117.     }
  118.     goto done;
  119.     /*
  120.      * If the name starts with "/" then just copy it to tclExecutableName.
  121.      */
  122. gotName:
  123. #ifdef DJGPP
  124.     if (name[1] == ':')  {
  125. #else
  126.     if (name[0] == '/')  {
  127. #endif
  128. Tcl_ExternalToUtfDString(NULL, name, -1, &nameString);
  129. tclNativeExecutableName = (char *)
  130. ckalloc((unsigned) (Tcl_DStringLength(&nameString) + 1));
  131. strcpy(tclNativeExecutableName, Tcl_DStringValue(&nameString));
  132. Tcl_DStringFree(&nameString);
  133. goto done;
  134.     }
  135.     /*
  136.      * The name is relative to the current working directory.  First
  137.      * strip off a leading "./", if any, then add the full path name of
  138.      * the current working directory.
  139.      */
  140.     if ((name[0] == '.') && (name[1] == '/')) {
  141. name += 2;
  142.     }
  143.     Tcl_ExternalToUtfDString(NULL, name, -1, &nameString);
  144.     Tcl_DStringFree(&buffer);
  145.     TclpGetCwd(NULL, &buffer);
  146.     length = Tcl_DStringLength(&buffer) + Tcl_DStringLength(&nameString) + 2;
  147.     tclNativeExecutableName = (char *) ckalloc((unsigned) length);
  148.     strcpy(tclNativeExecutableName, Tcl_DStringValue(&buffer));
  149.     tclNativeExecutableName[Tcl_DStringLength(&buffer)] = '/';
  150.     strcpy(tclNativeExecutableName + Tcl_DStringLength(&buffer) + 1,
  151.     Tcl_DStringValue(&nameString));
  152.     Tcl_DStringFree(&nameString);
  153.     
  154. done:
  155.     Tcl_DStringFree(&buffer);
  156.     return tclNativeExecutableName;
  157. }
  158. /*
  159.  *----------------------------------------------------------------------
  160.  *
  161.  * TclpMatchInDirectory --
  162.  *
  163.  * This routine is used by the globbing code to search a
  164.  * directory for all files which match a given pattern.
  165.  *
  166.  * Results: 
  167.  * The return value is a standard Tcl result indicating whether an
  168.  * error occurred in globbing.  Errors are left in interp, good
  169.  * results are lappended to resultPtr (which must be a valid object)
  170.  *
  171.  * Side effects:
  172.  * None.
  173.  *
  174.  *---------------------------------------------------------------------- */
  175. int
  176. TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types)
  177.     Tcl_Interp *interp; /* Interpreter to receive errors. */
  178.     Tcl_Obj *resultPtr; /* List object to lappend results. */
  179.     Tcl_Obj *pathPtr;         /* Contains path to directory to search. */
  180.     CONST char *pattern; /* Pattern to match against. */
  181.     Tcl_GlobTypeData *types; /* Object containing list of acceptable types.
  182.  * May be NULL. In particular the directory
  183.  * flag is very important. */
  184. {
  185.     CONST char *native;
  186.     Tcl_Obj *fileNamePtr;
  187.     fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr);
  188.     if (fileNamePtr == NULL) {
  189. return TCL_ERROR;
  190.     }
  191.     
  192.     if (pattern == NULL || (*pattern == '')) {
  193. /* Match a file directly */
  194. native = (CONST char*) Tcl_FSGetNativePath(pathPtr);
  195. if (NativeMatchType(native, types)) {
  196.     Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
  197. }
  198. Tcl_DecrRefCount(fileNamePtr);
  199. return TCL_OK;
  200.     } else {
  201. DIR *d;
  202. Tcl_DirEntry *entryPtr;
  203. CONST char *dirName;
  204. int dirLength;
  205. int matchHidden;
  206. int nativeDirLen;
  207. Tcl_StatBuf statBuf;
  208. Tcl_DString ds;      /* native encoding of dir */
  209. Tcl_DString dsOrig;  /* utf-8 encoding of dir */
  210. Tcl_DStringInit(&dsOrig);
  211. dirName = Tcl_GetStringFromObj(fileNamePtr, &dirLength);
  212. Tcl_DStringAppend(&dsOrig, dirName, dirLength);
  213. /*
  214.  * Make sure that the directory part of the name really is a
  215.  * directory.  If the directory name is "", use the name "."
  216.  * instead, because some UNIX systems don't treat "" like "."
  217.  * automatically.  Keep the "" for use in generating file names,
  218.  * otherwise "glob foo.c" would return "./foo.c".
  219.  */
  220. if (dirLength == 0) {
  221.     dirName = ".";
  222. } else {
  223.     dirName = Tcl_DStringValue(&dsOrig);
  224.     /* Make sure we have a trailing directory delimiter */
  225.     if (dirName[dirLength-1] != '/') {
  226. dirName = Tcl_DStringAppend(&dsOrig, "/", 1);
  227. dirLength++;
  228.     }
  229. }
  230. Tcl_DecrRefCount(fileNamePtr);
  231. /*
  232.  * Now open the directory for reading and iterate over the contents.
  233.  */
  234. native = Tcl_UtfToExternalDString(NULL, dirName, -1, &ds);
  235. if ((TclOSstat(native, &statBuf) != 0) /* INTL: Native. */
  236. || !S_ISDIR(statBuf.st_mode)) {
  237.     Tcl_DStringFree(&dsOrig);
  238.     Tcl_DStringFree(&ds);
  239.     return TCL_OK;
  240. }
  241. d = opendir(native); /* INTL: Native. */
  242. if (d == NULL) {
  243.     Tcl_DStringFree(&ds);
  244.     Tcl_ResetResult(interp);
  245.     Tcl_AppendResult(interp, "couldn't read directory "",
  246.     Tcl_DStringValue(&dsOrig), "": ",
  247.     Tcl_PosixError(interp), (char *) NULL);
  248.     Tcl_DStringFree(&dsOrig);
  249.     return TCL_ERROR;
  250. }
  251. nativeDirLen = Tcl_DStringLength(&ds);
  252. /*
  253.  * Check to see if -type or the pattern requests hidden files.
  254.  */
  255. matchHidden = ((types && (types->perm & TCL_GLOB_PERM_HIDDEN)) ||
  256. ((pattern[0] == '.')
  257. || ((pattern[0] == '\') && (pattern[1] == '.'))));
  258. while ((entryPtr = TclOSreaddir(d)) != NULL) { /* INTL: Native. */
  259.     Tcl_DString utfDs;
  260.     CONST char *utfname;
  261.     /* 
  262.      * Skip this file if it doesn't agree with the hidden
  263.      * parameters requested by the user (via -type or pattern).
  264.      */
  265.     if (*entryPtr->d_name == '.') {
  266. if (!matchHidden) continue;
  267.     } else {
  268. if (matchHidden) continue;
  269.     }
  270.     /*
  271.      * Now check to see if the file matches, according to both type
  272.      * and pattern.  If so, add the file to the result.
  273.      */
  274.     utfname = Tcl_ExternalToUtfDString(NULL, entryPtr->d_name,
  275.     -1, &utfDs);
  276.     if (Tcl_StringCaseMatch(utfname, pattern, 0)) {
  277. int typeOk = 1;
  278. if (types != NULL) {
  279.     Tcl_DStringSetLength(&ds, nativeDirLen);
  280.     native = Tcl_DStringAppend(&ds, entryPtr->d_name, -1);
  281.     typeOk = NativeMatchType(native, types);
  282. }
  283. if (typeOk) {
  284.     Tcl_ListObjAppendElement(interp, resultPtr, 
  285.     TclNewFSPathObj(pathPtr, utfname,
  286.     Tcl_DStringLength(&utfDs)));
  287. }
  288.     }
  289.     Tcl_DStringFree(&utfDs);
  290. }
  291. closedir(d);
  292. Tcl_DStringFree(&ds);
  293. Tcl_DStringFree(&dsOrig);
  294. return TCL_OK;
  295.     }
  296. }
  297. static int 
  298. NativeMatchType(
  299.     CONST char* nativeEntry,  /* Native path to check */
  300.     Tcl_GlobTypeData *types)  /* Type description to match against */
  301. {
  302.     Tcl_StatBuf buf;
  303.     if (types == NULL) {
  304. /* 
  305.  * Simply check for the file's existence, but do it
  306.  * with lstat, in case it is a link to a file which
  307.  * doesn't exist (since that case would not show up
  308.  * if we used 'access' or 'stat')
  309.  */
  310. if (TclOSlstat(nativeEntry, &buf) != 0) {
  311.     return 0;
  312. }
  313.     } else {
  314. if (types->perm != 0) {
  315.     if (TclOSstat(nativeEntry, &buf) != 0) {
  316. /* 
  317.  * Either the file has disappeared between the
  318.  * 'readdir' call and the 'stat' call, or
  319.  * the file is a link to a file which doesn't
  320.  * exist (which we could ascertain with
  321.  * lstat), or there is some other strange
  322.  * problem.  In all these cases, we define this
  323.  * to mean the file does not match any defined
  324.  * permission, and therefore it is not 
  325.  * added to the list of files to return.
  326.  */
  327. return 0;
  328.     }
  329.     
  330.     /* 
  331.      * readonly means that there are NO write permissions
  332.      * (even for user), but execute is OK for anybody
  333.      */
  334.     if (((types->perm & TCL_GLOB_PERM_RONLY) &&
  335. (buf.st_mode & (S_IWOTH|S_IWGRP|S_IWUSR))) ||
  336. ((types->perm & TCL_GLOB_PERM_R) &&
  337. (access(nativeEntry, R_OK) != 0)) ||
  338. ((types->perm & TCL_GLOB_PERM_W) &&
  339. (access(nativeEntry, W_OK) != 0)) ||
  340. ((types->perm & TCL_GLOB_PERM_X) &&
  341. (access(nativeEntry, X_OK) != 0))
  342. ) {
  343. return 0;
  344.     }
  345. }
  346. if (types->type != 0) {
  347.     if (types->perm == 0) {
  348. /* We haven't yet done a stat on the file */
  349. if (TclOSstat(nativeEntry, &buf) != 0) {
  350.     /* 
  351.      * Posix error occurred.  The only ok
  352.      * case is if this is a link to a nonexistent
  353.      * file, and the user did 'glob -l'. So
  354.      * we check that here:
  355.      */
  356.     if (types->type & TCL_GLOB_TYPE_LINK) {
  357. if (TclOSlstat(nativeEntry, &buf) == 0) {
  358.     if (S_ISLNK(buf.st_mode)) {
  359. return 1;
  360.     }
  361. }
  362.     }
  363.     return 0;
  364. }
  365.     }
  366.     /*
  367.      * In order bcdpfls as in 'find -t'
  368.      */
  369.     if (
  370. ((types->type & TCL_GLOB_TYPE_BLOCK) &&
  371. S_ISBLK(buf.st_mode)) ||
  372. ((types->type & TCL_GLOB_TYPE_CHAR) &&
  373. S_ISCHR(buf.st_mode)) ||
  374. ((types->type & TCL_GLOB_TYPE_DIR) &&
  375. S_ISDIR(buf.st_mode)) ||
  376. ((types->type & TCL_GLOB_TYPE_PIPE) &&
  377. S_ISFIFO(buf.st_mode)) ||
  378. ((types->type & TCL_GLOB_TYPE_FILE) &&
  379. S_ISREG(buf.st_mode))
  380. #ifdef S_ISSOCK
  381. || ((types->type & TCL_GLOB_TYPE_SOCK) &&
  382. S_ISSOCK(buf.st_mode))
  383. #endif /* S_ISSOCK */
  384. ) {
  385. /* Do nothing -- this file is ok */
  386.     } else {
  387. #ifdef S_ISLNK
  388. if (types->type & TCL_GLOB_TYPE_LINK) {
  389.     if (TclOSlstat(nativeEntry, &buf) == 0) {
  390. if (S_ISLNK(buf.st_mode)) {
  391.     return 1;
  392. }
  393.     }
  394. }
  395. #endif /* S_ISLNK */
  396. return 0;
  397.     }
  398. }
  399.     }
  400.     return 1;
  401. }
  402. /*
  403.  *---------------------------------------------------------------------------
  404.  *
  405.  * TclpGetUserHome --
  406.  *
  407.  * This function takes the specified user name and finds their
  408.  * home directory.
  409.  *
  410.  * Results:
  411.  * The result is a pointer to a string specifying the user's home
  412.  * directory, or NULL if the user's home directory could not be
  413.  * determined.  Storage for the result string is allocated in
  414.  * bufferPtr; the caller must call Tcl_DStringFree() when the result
  415.  * is no longer needed.
  416.  *
  417.  * Side effects:
  418.  * None.
  419.  *
  420.  *----------------------------------------------------------------------
  421.  */
  422. char *
  423. TclpGetUserHome(name, bufferPtr)
  424.     CONST char *name; /* User name for desired home directory. */
  425.     Tcl_DString *bufferPtr; /* Uninitialized or free DString filled
  426.  * with name of user's home directory. */
  427. {
  428.     struct passwd *pwPtr;
  429.     Tcl_DString ds;
  430.     CONST char *native;
  431.     native = Tcl_UtfToExternalDString(NULL, name, -1, &ds);
  432.     pwPtr = getpwnam(native); /* INTL: Native. */
  433.     Tcl_DStringFree(&ds);
  434.     
  435.     if (pwPtr == NULL) {
  436. endpwent();
  437. return NULL;
  438.     }
  439.     Tcl_ExternalToUtfDString(NULL, pwPtr->pw_dir, -1, bufferPtr);
  440.     endpwent();
  441.     return Tcl_DStringValue(bufferPtr);
  442. }
  443. /*
  444.  *---------------------------------------------------------------------------
  445.  *
  446.  * TclpObjAccess --
  447.  *
  448.  * This function replaces the library version of access().
  449.  *
  450.  * Results:
  451.  * See access() documentation.
  452.  *
  453.  * Side effects:
  454.  * See access() documentation.
  455.  *
  456.  *---------------------------------------------------------------------------
  457.  */
  458. int 
  459. TclpObjAccess(pathPtr, mode)
  460.     Tcl_Obj *pathPtr;        /* Path of file to access */
  461.     int mode;                /* Permission setting. */
  462. {
  463.     CONST char *path = Tcl_FSGetNativePath(pathPtr);
  464.     if (path == NULL) {
  465. return -1;
  466.     } else {
  467. return access(path, mode);
  468.     }
  469. }
  470. /*
  471.  *---------------------------------------------------------------------------
  472.  *
  473.  * TclpObjChdir --
  474.  *
  475.  * This function replaces the library version of chdir().
  476.  *
  477.  * Results:
  478.  * See chdir() documentation.
  479.  *
  480.  * Side effects:
  481.  * See chdir() documentation.  
  482.  *
  483.  *---------------------------------------------------------------------------
  484.  */
  485. int 
  486. TclpObjChdir(pathPtr)
  487.     Tcl_Obj *pathPtr;          /* Path to new working directory */
  488. {
  489.     CONST char *path = Tcl_FSGetNativePath(pathPtr);
  490.     if (path == NULL) {
  491. return -1;
  492.     } else {
  493. return chdir(path);
  494.     }
  495. }
  496. /*
  497.  *----------------------------------------------------------------------
  498.  *
  499.  * TclpObjLstat --
  500.  *
  501.  * This function replaces the library version of lstat().
  502.  *
  503.  * Results:
  504.  * See lstat() documentation.
  505.  *
  506.  * Side effects:
  507.  * See lstat() documentation.
  508.  *
  509.  *----------------------------------------------------------------------
  510.  */
  511. int 
  512. TclpObjLstat(pathPtr, bufPtr)
  513.     Tcl_Obj *pathPtr; /* Path of file to stat */
  514.     Tcl_StatBuf *bufPtr; /* Filled with results of stat call. */
  515. {
  516.     return TclOSlstat(Tcl_FSGetNativePath(pathPtr), bufPtr);
  517. }
  518. /*
  519.  *---------------------------------------------------------------------------
  520.  *
  521.  * TclpObjGetCwd --
  522.  *
  523.  * This function replaces the library version of getcwd().
  524.  *
  525.  * Results:
  526.  * The result is a pointer to a string specifying the current
  527.  * directory, or NULL if the current directory could not be
  528.  * determined.  If NULL is returned, an error message is left in the
  529.  * interp's result.  Storage for the result string is allocated in
  530.  * bufferPtr; the caller must call Tcl_DStringFree() when the result
  531.  * is no longer needed.
  532.  *
  533.  * Side effects:
  534.  * None.
  535.  *
  536.  *----------------------------------------------------------------------
  537.  */
  538. Tcl_Obj* 
  539. TclpObjGetCwd(interp)
  540.     Tcl_Interp *interp;
  541. {
  542.     Tcl_DString ds;
  543.     if (TclpGetCwd(interp, &ds) != NULL) {
  544. Tcl_Obj *cwdPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
  545. Tcl_IncrRefCount(cwdPtr);
  546. Tcl_DStringFree(&ds);
  547. return cwdPtr;
  548.     } else {
  549. return NULL;
  550.     }
  551. }
  552. /* Older string based version */
  553. CONST char *
  554. TclpGetCwd(interp, bufferPtr)
  555.     Tcl_Interp *interp; /* If non-NULL, used for error reporting. */
  556.     Tcl_DString *bufferPtr; /* Uninitialized or free DString filled
  557.  * with name of current directory. */
  558. {
  559.     char buffer[MAXPATHLEN+1];
  560. #ifdef USEGETWD
  561.     if (getwd(buffer) == NULL) { /* INTL: Native. */
  562. #else
  563.     if (getcwd(buffer, MAXPATHLEN + 1) == NULL) { /* INTL: Native. */
  564. #endif
  565. if (interp != NULL) {
  566.     Tcl_AppendResult(interp,
  567.     "error getting working directory name: ",
  568.     Tcl_PosixError(interp), (char *) NULL);
  569. }
  570. return NULL;
  571.     }
  572.     return Tcl_ExternalToUtfDString(NULL, buffer, -1, bufferPtr);
  573. }
  574. /*
  575.  *---------------------------------------------------------------------------
  576.  *
  577.  * TclpReadlink --
  578.  *
  579.  * This function replaces the library version of readlink().
  580.  *
  581.  * Results:
  582.  * The result is a pointer to a string specifying the contents
  583.  * of the symbolic link given by 'path', or NULL if the symbolic
  584.  * link could not be read.  Storage for the result string is
  585.  * allocated in bufferPtr; the caller must call Tcl_DStringFree()
  586.  * when the result is no longer needed.
  587.  *
  588.  * Side effects:
  589.  * See readlink() documentation.
  590.  *
  591.  *---------------------------------------------------------------------------
  592.  */
  593. char *
  594. TclpReadlink(path, linkPtr)
  595.     CONST char *path; /* Path of file to readlink (UTF-8). */
  596.     Tcl_DString *linkPtr; /* Uninitialized or free DString filled
  597.  * with contents of link (UTF-8). */
  598. {
  599. #ifndef DJGPP
  600.     char link[MAXPATHLEN];
  601.     int length;
  602.     CONST char *native;
  603.     Tcl_DString ds;
  604.     native = Tcl_UtfToExternalDString(NULL, path, -1, &ds);
  605.     length = readlink(native, link, sizeof(link)); /* INTL: Native. */
  606.     Tcl_DStringFree(&ds);
  607.     
  608.     if (length < 0) {
  609. return NULL;
  610.     }
  611.     Tcl_ExternalToUtfDString(NULL, link, length, linkPtr);
  612.     return Tcl_DStringValue(linkPtr);
  613. #else
  614.     return NULL;
  615. #endif
  616. }
  617. /*
  618.  *----------------------------------------------------------------------
  619.  *
  620.  * TclpObjStat --
  621.  *
  622.  * This function replaces the library version of stat().
  623.  *
  624.  * Results:
  625.  * See stat() documentation.
  626.  *
  627.  * Side effects:
  628.  * See stat() documentation.
  629.  *
  630.  *----------------------------------------------------------------------
  631.  */
  632. int 
  633. TclpObjStat(pathPtr, bufPtr)
  634.     Tcl_Obj *pathPtr; /* Path of file to stat */
  635.     Tcl_StatBuf *bufPtr; /* Filled with results of stat call. */
  636. {
  637.     CONST char *path = Tcl_FSGetNativePath(pathPtr);
  638.     if (path == NULL) {
  639. return -1;
  640.     } else {
  641. return TclOSstat(path, bufPtr);
  642.     }
  643. }
  644. #ifdef S_IFLNK
  645. Tcl_Obj* 
  646. TclpObjLink(pathPtr, toPtr, linkAction)
  647.     Tcl_Obj *pathPtr;
  648.     Tcl_Obj *toPtr;
  649.     int linkAction;
  650. {
  651.     if (toPtr != NULL) {
  652. CONST char *src = Tcl_FSGetNativePath(pathPtr);
  653. CONST char *target = Tcl_FSGetNativePath(toPtr);
  654. if (src == NULL || target == NULL) {
  655.     return NULL;
  656. }
  657. if (access(src, F_OK) != -1) {
  658.     /* src exists */
  659.     errno = EEXIST;
  660.     return NULL;
  661. }
  662. if (access(target, F_OK) == -1) {
  663.     /* target doesn't exist */
  664.     errno = ENOENT;
  665.     return NULL;
  666. }
  667. /* 
  668.  * Check symbolic link flag first, since we prefer to
  669.  * create these.
  670.  */
  671. if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
  672.     if (symlink(target, src) != 0) return NULL;
  673. } else if (linkAction & TCL_CREATE_HARD_LINK) {
  674.     if (link(target, src) != 0) return NULL;
  675. } else {
  676.     errno = ENODEV;
  677.     return NULL;
  678. }
  679. return toPtr;
  680.     } else {
  681. Tcl_Obj* linkPtr = NULL;
  682. char link[MAXPATHLEN];
  683. int length;
  684. Tcl_DString ds;
  685. Tcl_Obj *transPtr;
  686. transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr);
  687. if (transPtr == NULL) {
  688.     return NULL;
  689. }
  690. Tcl_DecrRefCount(transPtr);
  691. length = readlink(Tcl_FSGetNativePath(pathPtr), link, sizeof(link));
  692. if (length < 0) {
  693.     return NULL;
  694. }
  695. Tcl_ExternalToUtfDString(NULL, link, length, &ds);
  696. linkPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), 
  697.    Tcl_DStringLength(&ds));
  698. Tcl_DStringFree(&ds);
  699. if (linkPtr != NULL) {
  700.     Tcl_IncrRefCount(linkPtr);
  701. }
  702. return linkPtr;
  703.     }
  704. }
  705. #endif
  706. /*
  707.  *---------------------------------------------------------------------------
  708.  *
  709.  * TclpFilesystemPathType --
  710.  *
  711.  *      This function is part of the native filesystem support, and
  712.  *      returns the path type of the given path.  Right now it simply
  713.  *      returns NULL.  In the future it could return specific path
  714.  *      types, like 'nfs', 'samba', 'FAT32', etc.
  715.  *
  716.  * Results:
  717.  *      NULL at present.
  718.  *
  719.  * Side effects:
  720.  * None.
  721.  *
  722.  *---------------------------------------------------------------------------
  723.  */
  724. Tcl_Obj*
  725. TclpFilesystemPathType(pathObjPtr)
  726.     Tcl_Obj* pathObjPtr;
  727. {
  728.     /* All native paths are of the same type */
  729.     return NULL;
  730. }
  731. /*
  732.  *---------------------------------------------------------------------------
  733.  *
  734.  * TclpUtime --
  735.  *
  736.  * Set the modification date for a file.
  737.  *
  738.  * Results:
  739.  * 0 on success, -1 on error.
  740.  *
  741.  * Side effects:
  742.  * None.
  743.  *
  744.  *---------------------------------------------------------------------------
  745.  */
  746. int 
  747. TclpUtime(pathPtr, tval)
  748.     Tcl_Obj *pathPtr;      /* File to modify */
  749.     struct utimbuf *tval;  /* New modification date structure */
  750. {
  751.     return utime(Tcl_FSGetNativePath(pathPtr),tval);
  752. }