tclUnixFile.cGo to the documentation of this file.00001 /* 00002 * tclUnixFile.c -- 00003 * 00004 * This file contains wrappers around UNIX file handling functions. 00005 * These wrappers mask differences between Windows and UNIX. 00006 * 00007 * Copyright (c) 1995-1998 Sun Microsystems, Inc. 00008 * 00009 * See the file "license.terms" for information on usage and redistribution of 00010 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00011 * 00012 * RCS: @(#) $Id: tclUnixFile.c,v 1.52 2007/12/13 15:28:42 dgp Exp $ 00013 */ 00014 00015 #include "tclInt.h" 00016 #include "tclFileSystem.h" 00017 00018 static int NativeMatchType(Tcl_Interp *interp, CONST char* nativeEntry, 00019 CONST char* nativeName, Tcl_GlobTypeData *types); 00020 00021 /* 00022 *--------------------------------------------------------------------------- 00023 * 00024 * TclpFindExecutable -- 00025 * 00026 * This function computes the absolute path name of the current 00027 * application, given its argv[0] value. 00028 * 00029 * Results: 00030 * None. 00031 * 00032 * Side effects: 00033 * The computed path name is stored as a ProcessGlobalValue. 00034 * 00035 *--------------------------------------------------------------------------- 00036 */ 00037 00038 void 00039 TclpFindExecutable( 00040 CONST char *argv0) /* The value of the application's argv[0] 00041 * (native). */ 00042 { 00043 CONST char *name, *p; 00044 Tcl_StatBuf statBuf; 00045 Tcl_DString buffer, nameString, cwd, utfName; 00046 Tcl_Encoding encoding; 00047 00048 if (argv0 == NULL) { 00049 return; 00050 } 00051 Tcl_DStringInit(&buffer); 00052 00053 name = argv0; 00054 for (p = name; *p != '\0'; p++) { 00055 if (*p == '/') { 00056 /* 00057 * The name contains a slash, so use the name directly without 00058 * doing a path search. 00059 */ 00060 00061 goto gotName; 00062 } 00063 } 00064 00065 p = getenv("PATH"); /* INTL: Native. */ 00066 if (p == NULL) { 00067 /* 00068 * There's no PATH environment variable; use the default that is used 00069 * by sh. 00070 */ 00071 00072 p = ":/bin:/usr/bin"; 00073 } else if (*p == '\0') { 00074 /* 00075 * An empty path is equivalent to ".". 00076 */ 00077 00078 p = "./"; 00079 } 00080 00081 /* 00082 * Search through all the directories named in the PATH variable to see if 00083 * argv[0] is in one of them. If so, use that file name. 00084 */ 00085 00086 while (1) { 00087 while (isspace(UCHAR(*p))) { /* INTL: BUG */ 00088 p++; 00089 } 00090 name = p; 00091 while ((*p != ':') && (*p != 0)) { 00092 p++; 00093 } 00094 Tcl_DStringSetLength(&buffer, 0); 00095 if (p != name) { 00096 Tcl_DStringAppend(&buffer, name, p - name); 00097 if (p[-1] != '/') { 00098 Tcl_DStringAppend(&buffer, "/", 1); 00099 } 00100 } 00101 name = Tcl_DStringAppend(&buffer, argv0, -1); 00102 00103 /* 00104 * INTL: The following calls to access() and stat() should not be 00105 * converted to Tclp routines because they need to operate on native 00106 * strings directly. 00107 */ 00108 00109 if ((access(name, X_OK) == 0) /* INTL: Native. */ 00110 && (TclOSstat(name, &statBuf) == 0) /* INTL: Native. */ 00111 && S_ISREG(statBuf.st_mode)) { 00112 goto gotName; 00113 } 00114 if (*p == '\0') { 00115 break; 00116 } else if (*(p+1) == 0) { 00117 p = "./"; 00118 } else { 00119 p++; 00120 } 00121 } 00122 TclSetObjNameOfExecutable(Tcl_NewObj(), NULL); 00123 goto done; 00124 00125 /* 00126 * If the name starts with "/" then just store it 00127 */ 00128 00129 gotName: 00130 #ifdef DJGPP 00131 if (name[1] == ':') 00132 #else 00133 if (name[0] == '/') 00134 #endif 00135 { 00136 encoding = Tcl_GetEncoding(NULL, NULL); 00137 Tcl_ExternalToUtfDString(encoding, name, -1, &utfName); 00138 TclSetObjNameOfExecutable( 00139 Tcl_NewStringObj(Tcl_DStringValue(&utfName), -1), encoding); 00140 Tcl_DStringFree(&utfName); 00141 goto done; 00142 } 00143 00144 /* 00145 * The name is relative to the current working directory. First strip off 00146 * a leading "./", if any, then add the full path name of the current 00147 * working directory. 00148 */ 00149 00150 if ((name[0] == '.') && (name[1] == '/')) { 00151 name += 2; 00152 } 00153 00154 Tcl_DStringInit(&nameString); 00155 Tcl_DStringAppend(&nameString, name, -1); 00156 00157 TclpGetCwd(NULL, &cwd); 00158 00159 Tcl_DStringFree(&buffer); 00160 Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&cwd), 00161 Tcl_DStringLength(&cwd), &buffer); 00162 if (Tcl_DStringValue(&cwd)[Tcl_DStringLength(&cwd) -1] != '/') { 00163 Tcl_DStringAppend(&buffer, "/", 1); 00164 } 00165 Tcl_DStringFree(&cwd); 00166 Tcl_DStringAppend(&buffer, Tcl_DStringValue(&nameString), 00167 Tcl_DStringLength(&nameString)); 00168 Tcl_DStringFree(&nameString); 00169 00170 encoding = Tcl_GetEncoding(NULL, NULL); 00171 Tcl_ExternalToUtfDString(encoding, Tcl_DStringValue(&buffer), -1, 00172 &utfName); 00173 TclSetObjNameOfExecutable( 00174 Tcl_NewStringObj(Tcl_DStringValue(&utfName), -1), encoding); 00175 Tcl_DStringFree(&utfName); 00176 00177 done: 00178 Tcl_DStringFree(&buffer); 00179 } 00180 00181 /* 00182 *---------------------------------------------------------------------- 00183 * 00184 * TclpMatchInDirectory -- 00185 * 00186 * This routine is used by the globbing code to search a directory for 00187 * all files which match a given pattern. 00188 * 00189 * Results: 00190 * The return value is a standard Tcl result indicating whether an error 00191 * occurred in globbing. Errors are left in interp, good results are 00192 * [lappend]ed to resultPtr (which must be a valid object). 00193 * 00194 * Side effects: 00195 * None. 00196 * 00197 *---------------------------------------------------------------------- 00198 */ 00199 00200 int 00201 TclpMatchInDirectory( 00202 Tcl_Interp *interp, /* Interpreter to receive errors. */ 00203 Tcl_Obj *resultPtr, /* List object to lappend results. */ 00204 Tcl_Obj *pathPtr, /* Contains path to directory to search. */ 00205 CONST char *pattern, /* Pattern to match against. */ 00206 Tcl_GlobTypeData *types) /* Object containing list of acceptable types. 00207 * May be NULL. In particular the directory 00208 * flag is very important. */ 00209 { 00210 CONST char *native; 00211 Tcl_Obj *fileNamePtr; 00212 int matchResult = 0; 00213 00214 if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) { 00215 /* 00216 * The native filesystem never adds mounts. 00217 */ 00218 00219 return TCL_OK; 00220 } 00221 00222 fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr); 00223 if (fileNamePtr == NULL) { 00224 return TCL_ERROR; 00225 } 00226 00227 if (pattern == NULL || (*pattern == '\0')) { 00228 /* 00229 * Match a file directly. 00230 */ 00231 Tcl_Obj *tailPtr; 00232 CONST char *nativeTail; 00233 00234 native = (CONST char*) Tcl_FSGetNativePath(pathPtr); 00235 tailPtr = TclPathPart(interp, pathPtr, TCL_PATH_TAIL); 00236 nativeTail = (CONST char*) Tcl_FSGetNativePath(tailPtr); 00237 matchResult = NativeMatchType(interp, native, nativeTail, types); 00238 if (matchResult == 1) { 00239 Tcl_ListObjAppendElement(interp, resultPtr, pathPtr); 00240 } 00241 Tcl_DecrRefCount(tailPtr); 00242 Tcl_DecrRefCount(fileNamePtr); 00243 } else { 00244 DIR *d; 00245 Tcl_DirEntry *entryPtr; 00246 CONST char *dirName; 00247 int dirLength; 00248 int matchHidden, matchHiddenPat; 00249 int nativeDirLen; 00250 Tcl_StatBuf statBuf; 00251 Tcl_DString ds; /* native encoding of dir */ 00252 Tcl_DString dsOrig; /* utf-8 encoding of dir */ 00253 00254 Tcl_DStringInit(&dsOrig); 00255 dirName = Tcl_GetStringFromObj(fileNamePtr, &dirLength); 00256 Tcl_DStringAppend(&dsOrig, dirName, dirLength); 00257 00258 /* 00259 * Make sure that the directory part of the name really is a 00260 * directory. If the directory name is "", use the name "." instead, 00261 * because some UNIX systems don't treat "" like "." automatically. 00262 * Keep the "" for use in generating file names, otherwise "glob 00263 * foo.c" would return "./foo.c". 00264 */ 00265 00266 if (dirLength == 0) { 00267 dirName = "."; 00268 } else { 00269 dirName = Tcl_DStringValue(&dsOrig); 00270 00271 /* 00272 * Make sure we have a trailing directory delimiter. 00273 */ 00274 00275 if (dirName[dirLength-1] != '/') { 00276 dirName = Tcl_DStringAppend(&dsOrig, "/", 1); 00277 dirLength++; 00278 } 00279 } 00280 00281 /* 00282 * Now open the directory for reading and iterate over the contents. 00283 */ 00284 00285 native = Tcl_UtfToExternalDString(NULL, dirName, -1, &ds); 00286 00287 if ((TclOSstat(native, &statBuf) != 0) /* INTL: Native. */ 00288 || !S_ISDIR(statBuf.st_mode)) { 00289 Tcl_DStringFree(&dsOrig); 00290 Tcl_DStringFree(&ds); 00291 Tcl_DecrRefCount(fileNamePtr); 00292 return TCL_OK; 00293 } 00294 00295 d = opendir(native); /* INTL: Native. */ 00296 if (d == NULL) { 00297 Tcl_DStringFree(&ds); 00298 if (interp != NULL) { 00299 Tcl_ResetResult(interp); 00300 Tcl_AppendResult(interp, "couldn't read directory \"", 00301 Tcl_DStringValue(&dsOrig), "\": ", 00302 Tcl_PosixError(interp), (char *) NULL); 00303 } 00304 Tcl_DStringFree(&dsOrig); 00305 Tcl_DecrRefCount(fileNamePtr); 00306 return TCL_ERROR; 00307 } 00308 00309 nativeDirLen = Tcl_DStringLength(&ds); 00310 00311 /* 00312 * Check to see if -type or the pattern requests hidden files. 00313 */ 00314 00315 matchHiddenPat = (pattern[0] == '.') 00316 || ((pattern[0] == '\\') && (pattern[1] == '.')); 00317 matchHidden = matchHiddenPat 00318 || (types && (types->perm & TCL_GLOB_PERM_HIDDEN)); 00319 while ((entryPtr = TclOSreaddir(d)) != NULL) { /* INTL: Native. */ 00320 Tcl_DString utfDs; 00321 CONST char *utfname; 00322 00323 /* 00324 * Skip this file if it doesn't agree with the hidden parameters 00325 * requested by the user (via -type or pattern). 00326 */ 00327 00328 if (*entryPtr->d_name == '.') { 00329 if (!matchHidden) continue; 00330 } else { 00331 #ifdef MAC_OSX_TCL 00332 if (matchHiddenPat) continue; 00333 /* Also need to check HFS hidden flag in TclMacOSXMatchType. */ 00334 #else 00335 if (matchHidden) continue; 00336 #endif 00337 } 00338 00339 /* 00340 * Now check to see if the file matches, according to both type 00341 * and pattern. If so, add the file to the result. 00342 */ 00343 00344 utfname = Tcl_ExternalToUtfDString(NULL, entryPtr->d_name, -1, 00345 &utfDs); 00346 if (Tcl_StringCaseMatch(utfname, pattern, 0)) { 00347 int typeOk = 1; 00348 00349 if (types != NULL) { 00350 Tcl_DStringSetLength(&ds, nativeDirLen); 00351 native = Tcl_DStringAppend(&ds, entryPtr->d_name, -1); 00352 matchResult = NativeMatchType(interp, native, 00353 entryPtr->d_name, types); 00354 typeOk = (matchResult == 1); 00355 } 00356 if (typeOk) { 00357 Tcl_ListObjAppendElement(interp, resultPtr, 00358 TclNewFSPathObj(pathPtr, utfname, 00359 Tcl_DStringLength(&utfDs))); 00360 } 00361 } 00362 Tcl_DStringFree(&utfDs); 00363 if (matchResult < 0) { 00364 break; 00365 } 00366 } 00367 00368 closedir(d); 00369 Tcl_DStringFree(&ds); 00370 Tcl_DStringFree(&dsOrig); 00371 Tcl_DecrRefCount(fileNamePtr); 00372 } 00373 if (matchResult < 0) { 00374 return TCL_ERROR; 00375 } else { 00376 return TCL_OK; 00377 } 00378 } 00379 00380 /* 00381 *---------------------------------------------------------------------- 00382 * 00383 * NativeMatchType -- 00384 * 00385 * This routine is used by the globbing code to check if a file 00386 * matches a given type description. 00387 * 00388 * Results: 00389 * The return value is 1, 0 or -1 indicating whether the file 00390 * matches the given criteria, does not match them, or an error 00391 * occurred (in wich case an error is left in interp). 00392 * 00393 * Side effects: 00394 * None. 00395 * 00396 *---------------------------------------------------------------------- 00397 */ 00398 00399 static int 00400 NativeMatchType( 00401 Tcl_Interp *interp, /* Interpreter to receive errors. */ 00402 CONST char *nativeEntry, /* Native path to check. */ 00403 CONST char *nativeName, /* Native filename to check. */ 00404 Tcl_GlobTypeData *types) /* Type description to match against. */ 00405 { 00406 Tcl_StatBuf buf; 00407 if (types == NULL) { 00408 /* 00409 * Simply check for the file's existence, but do it with lstat, in 00410 * case it is a link to a file which doesn't exist (since that case 00411 * would not show up if we used 'access' or 'stat') 00412 */ 00413 00414 if (TclOSlstat(nativeEntry, &buf) != 0) { 00415 return 0; 00416 } 00417 } else { 00418 if (types->perm != 0) { 00419 if (TclOSstat(nativeEntry, &buf) != 0) { 00420 /* 00421 * Either the file has disappeared between the 'readdir' call 00422 * and the 'stat' call, or the file is a link to a file which 00423 * doesn't exist (which we could ascertain with lstat), or 00424 * there is some other strange problem. In all these cases, we 00425 * define this to mean the file does not match any defined 00426 * permission, and therefore it is not added to the list of 00427 * files to return. 00428 */ 00429 00430 return 0; 00431 } 00432 00433 /* 00434 * readonly means that there are NO write permissions (even for 00435 * user), but execute is OK for anybody OR that the user immutable 00436 * flag is set (where supported). 00437 */ 00438 00439 if (((types->perm & TCL_GLOB_PERM_RONLY) && 00440 #if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) 00441 !(buf.st_flags & UF_IMMUTABLE) && 00442 #endif 00443 (buf.st_mode & (S_IWOTH|S_IWGRP|S_IWUSR))) || 00444 ((types->perm & TCL_GLOB_PERM_R) && 00445 (access(nativeEntry, R_OK) != 0)) || 00446 ((types->perm & TCL_GLOB_PERM_W) && 00447 (access(nativeEntry, W_OK) != 0)) || 00448 ((types->perm & TCL_GLOB_PERM_X) && 00449 (access(nativeEntry, X_OK) != 0)) 00450 #ifndef MAC_OSX_TCL 00451 || ((types->perm & TCL_GLOB_PERM_HIDDEN) && 00452 (*nativeName != '.')) 00453 #endif 00454 ) { 00455 return 0; 00456 } 00457 } 00458 if (types->type != 0) { 00459 if (types->perm == 0) { 00460 /* 00461 * We haven't yet done a stat on the file. 00462 */ 00463 00464 if (TclOSstat(nativeEntry, &buf) != 0) { 00465 /* 00466 * Posix error occurred. The only ok case is if this is a 00467 * link to a nonexistent file, and the user did 'glob -l'. 00468 * So we check that here: 00469 */ 00470 00471 if (types->type & TCL_GLOB_TYPE_LINK) { 00472 if (TclOSlstat(nativeEntry, &buf) == 0) { 00473 if (S_ISLNK(buf.st_mode)) { 00474 return 1; 00475 } 00476 } 00477 } 00478 return 0; 00479 } 00480 } 00481 00482 /* 00483 * In order bcdpfls as in 'find -t' 00484 */ 00485 00486 if (((types->type & TCL_GLOB_TYPE_BLOCK)&& S_ISBLK(buf.st_mode)) || 00487 ((types->type & TCL_GLOB_TYPE_CHAR) && S_ISCHR(buf.st_mode)) || 00488 ((types->type & TCL_GLOB_TYPE_DIR) && S_ISDIR(buf.st_mode)) || 00489 ((types->type & TCL_GLOB_TYPE_PIPE) && S_ISFIFO(buf.st_mode))|| 00490 ((types->type & TCL_GLOB_TYPE_FILE) && S_ISREG(buf.st_mode)) 00491 #ifdef S_ISSOCK 00492 ||((types->type & TCL_GLOB_TYPE_SOCK) && S_ISSOCK(buf.st_mode)) 00493 #endif /* S_ISSOCK */ 00494 ) { 00495 /* 00496 * Do nothing - this file is ok. 00497 */ 00498 } else { 00499 #ifdef S_ISLNK 00500 if (types->type & TCL_GLOB_TYPE_LINK) { 00501 if (TclOSlstat(nativeEntry, &buf) == 0) { 00502 if (S_ISLNK(buf.st_mode)) { 00503 goto filetypeOK; 00504 } 00505 } 00506 } 00507 #endif /* S_ISLNK */ 00508 return 0; 00509 } 00510 } 00511 filetypeOK: ; 00512 #ifdef MAC_OSX_TCL 00513 if (types->macType != NULL || types->macCreator != NULL || 00514 (types->perm & TCL_GLOB_PERM_HIDDEN)) { 00515 int matchResult; 00516 00517 if (types->perm == 0 && types->type == 0) { 00518 /* 00519 * We haven't yet done a stat on the file. 00520 */ 00521 00522 if (TclOSstat(nativeEntry, &buf) != 0) { 00523 return 0; 00524 } 00525 } 00526 00527 matchResult = TclMacOSXMatchType(interp, nativeEntry, nativeName, 00528 &buf, types); 00529 if (matchResult != 1) { 00530 return matchResult; 00531 } 00532 } 00533 #endif 00534 } 00535 return 1; 00536 } 00537 00538 /* 00539 *--------------------------------------------------------------------------- 00540 * 00541 * TclpGetUserHome -- 00542 * 00543 * This function takes the specified user name and finds their home 00544 * directory. 00545 * 00546 * Results: 00547 * The result is a pointer to a string specifying the user's home 00548 * directory, or NULL if the user's home directory could not be 00549 * determined. Storage for the result string is allocated in bufferPtr; 00550 * the caller must call Tcl_DStringFree() when the result is no longer 00551 * needed. 00552 * 00553 * Side effects: 00554 * None. 00555 * 00556 *---------------------------------------------------------------------- 00557 */ 00558 00559 char * 00560 TclpGetUserHome( 00561 CONST char *name, /* User name for desired home directory. */ 00562 Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with 00563 * name of user's home directory. */ 00564 { 00565 struct passwd *pwPtr; 00566 Tcl_DString ds; 00567 CONST char *native; 00568 00569 native = Tcl_UtfToExternalDString(NULL, name, -1, &ds); 00570 pwPtr = getpwnam(native); /* INTL: Native. */ 00571 Tcl_DStringFree(&ds); 00572 00573 if (pwPtr == NULL) { 00574 endpwent(); 00575 return NULL; 00576 } 00577 Tcl_ExternalToUtfDString(NULL, pwPtr->pw_dir, -1, bufferPtr); 00578 endpwent(); 00579 return Tcl_DStringValue(bufferPtr); 00580 } 00581 00582 /* 00583 *--------------------------------------------------------------------------- 00584 * 00585 * TclpObjAccess -- 00586 * 00587 * This function replaces the library version of access(). 00588 * 00589 * Results: 00590 * See access() documentation. 00591 * 00592 * Side effects: 00593 * See access() documentation. 00594 * 00595 *--------------------------------------------------------------------------- 00596 */ 00597 00598 int 00599 TclpObjAccess( 00600 Tcl_Obj *pathPtr, /* Path of file to access */ 00601 int mode) /* Permission setting. */ 00602 { 00603 CONST char *path = Tcl_FSGetNativePath(pathPtr); 00604 if (path == NULL) { 00605 return -1; 00606 } else { 00607 return access(path, mode); 00608 } 00609 } 00610 00611 /* 00612 *--------------------------------------------------------------------------- 00613 * 00614 * TclpObjChdir -- 00615 * 00616 * This function replaces the library version of chdir(). 00617 * 00618 * Results: 00619 * See chdir() documentation. 00620 * 00621 * Side effects: 00622 * See chdir() documentation. 00623 * 00624 *--------------------------------------------------------------------------- 00625 */ 00626 00627 int 00628 TclpObjChdir( 00629 Tcl_Obj *pathPtr) /* Path to new working directory */ 00630 { 00631 CONST char *path = Tcl_FSGetNativePath(pathPtr); 00632 if (path == NULL) { 00633 return -1; 00634 } else { 00635 return chdir(path); 00636 } 00637 } 00638 00639 /* 00640 *---------------------------------------------------------------------- 00641 * 00642 * TclpObjLstat -- 00643 * 00644 * This function replaces the library version of lstat(). 00645 * 00646 * Results: 00647 * See lstat() documentation. 00648 * 00649 * Side effects: 00650 * See lstat() documentation. 00651 * 00652 *---------------------------------------------------------------------- 00653 */ 00654 00655 int 00656 TclpObjLstat( 00657 Tcl_Obj *pathPtr, /* Path of file to stat */ 00658 Tcl_StatBuf *bufPtr) /* Filled with results of stat call. */ 00659 { 00660 return TclOSlstat(Tcl_FSGetNativePath(pathPtr), bufPtr); 00661 } 00662 00663 /* 00664 *--------------------------------------------------------------------------- 00665 * 00666 * TclpGetNativeCwd -- 00667 * 00668 * This function replaces the library version of getcwd(). 00669 * 00670 * Results: 00671 * The input and output are filesystem paths in native form. The result 00672 * is either the given clientData, if the working directory hasn't 00673 * changed, or a new clientData (owned by our caller), giving the new 00674 * native path, or NULL if the current directory could not be determined. 00675 * If NULL is returned, the caller can examine the standard posix error 00676 * codes to determine the cause of the problem. 00677 * 00678 * Side effects: 00679 * None. 00680 * 00681 *---------------------------------------------------------------------- 00682 */ 00683 00684 ClientData 00685 TclpGetNativeCwd( 00686 ClientData clientData) 00687 { 00688 char buffer[MAXPATHLEN+1]; 00689 00690 #ifdef USEGETWD 00691 if (getwd(buffer) == NULL) /* INTL: Native. */ 00692 #else 00693 if (getcwd(buffer, MAXPATHLEN+1) == NULL) /* INTL: Native. */ 00694 #endif 00695 { 00696 return NULL; 00697 } 00698 if ((clientData != NULL) && strcmp(buffer, (CONST char*)clientData) == 0) { 00699 /* 00700 * No change to pwd. 00701 */ 00702 00703 return clientData; 00704 } else { 00705 char *newCd = (char *) ckalloc((unsigned) (strlen(buffer) + 1)); 00706 strcpy(newCd, buffer); 00707 return (ClientData) newCd; 00708 } 00709 } 00710 00711 /* 00712 *--------------------------------------------------------------------------- 00713 * 00714 * TclpGetCwd -- 00715 * 00716 * This function replaces the library version of getcwd(). (Obsolete 00717 * function, only retained for old extensions which may call it 00718 * directly). 00719 * 00720 * Results: 00721 * The result is a pointer to a string specifying the current directory, 00722 * or NULL if the current directory could not be determined. If NULL is 00723 * returned, an error message is left in the interp's result. Storage for 00724 * the result string is allocated in bufferPtr; the caller must call 00725 * Tcl_DStringFree() when the result is no longer needed. 00726 * 00727 * Side effects: 00728 * None. 00729 * 00730 *---------------------------------------------------------------------- 00731 */ 00732 00733 CONST char * 00734 TclpGetCwd( 00735 Tcl_Interp *interp, /* If non-NULL, used for error reporting. */ 00736 Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with 00737 * name of current directory. */ 00738 { 00739 char buffer[MAXPATHLEN+1]; 00740 00741 #ifdef USEGETWD 00742 if (getwd(buffer) == NULL) /* INTL: Native. */ 00743 #else 00744 if (getcwd(buffer, MAXPATHLEN+1) == NULL) /* INTL: Native. */ 00745 #endif 00746 { 00747 if (interp != NULL) { 00748 Tcl_AppendResult(interp, 00749 "error getting working directory name: ", 00750 Tcl_PosixError(interp), NULL); 00751 } 00752 return NULL; 00753 } 00754 return Tcl_ExternalToUtfDString(NULL, buffer, -1, bufferPtr); 00755 } 00756 00757 /* 00758 *--------------------------------------------------------------------------- 00759 * 00760 * TclpReadlink -- 00761 * 00762 * This function replaces the library version of readlink(). 00763 * 00764 * Results: 00765 * The result is a pointer to a string specifying the contents of the 00766 * symbolic link given by 'path', or NULL if the symbolic link could not 00767 * be read. Storage for the result string is allocated in bufferPtr; the 00768 * caller must call Tcl_DStringFree() when the result is no longer 00769 * needed. 00770 * 00771 * Side effects: 00772 * See readlink() documentation. 00773 * 00774 *--------------------------------------------------------------------------- 00775 */ 00776 00777 char * 00778 TclpReadlink( 00779 CONST char *path, /* Path of file to readlink (UTF-8). */ 00780 Tcl_DString *linkPtr) /* Uninitialized or free DString filled with 00781 * contents of link (UTF-8). */ 00782 { 00783 #ifndef DJGPP 00784 char link[MAXPATHLEN]; 00785 int length; 00786 CONST char *native; 00787 Tcl_DString ds; 00788 00789 native = Tcl_UtfToExternalDString(NULL, path, -1, &ds); 00790 length = readlink(native, link, sizeof(link)); /* INTL: Native. */ 00791 Tcl_DStringFree(&ds); 00792 00793 if (length < 0) { 00794 return NULL; 00795 } 00796 00797 Tcl_ExternalToUtfDString(NULL, link, length, linkPtr); 00798 return Tcl_DStringValue(linkPtr); 00799 #else 00800 return NULL; 00801 #endif 00802 } 00803 00804 /* 00805 *---------------------------------------------------------------------- 00806 * 00807 * TclpObjStat -- 00808 * 00809 * This function replaces the library version of stat(). 00810 * 00811 * Results: 00812 * See stat() documentation. 00813 * 00814 * Side effects: 00815 * See stat() documentation. 00816 * 00817 *---------------------------------------------------------------------- 00818 */ 00819 00820 int 00821 TclpObjStat( 00822 Tcl_Obj *pathPtr, /* Path of file to stat */ 00823 Tcl_StatBuf *bufPtr) /* Filled with results of stat call. */ 00824 { 00825 CONST char *path = Tcl_FSGetNativePath(pathPtr); 00826 if (path == NULL) { 00827 return -1; 00828 } else { 00829 return TclOSstat(path, bufPtr); 00830 } 00831 } 00832 00833 #ifdef S_IFLNK 00834 00835 Tcl_Obj* 00836 TclpObjLink( 00837 Tcl_Obj *pathPtr, 00838 Tcl_Obj *toPtr, 00839 int linkAction) 00840 { 00841 if (toPtr != NULL) { 00842 CONST char *src = Tcl_FSGetNativePath(pathPtr); 00843 CONST char *target = NULL; 00844 00845 if (src == NULL) { 00846 return NULL; 00847 } 00848 00849 /* 00850 * If we're making a symbolic link and the path is relative, then we 00851 * must check whether it exists _relative_ to the directory in which 00852 * the src is found (not relative to the current cwd which is just not 00853 * relevant in this case). 00854 * 00855 * If we're making a hard link, then a relative path is just converted 00856 * to absolute relative to the cwd. 00857 */ 00858 00859 if ((linkAction & TCL_CREATE_SYMBOLIC_LINK) 00860 && (Tcl_FSGetPathType(toPtr) == TCL_PATH_RELATIVE)) { 00861 Tcl_Obj *dirPtr, *absPtr; 00862 00863 dirPtr = TclPathPart(NULL, pathPtr, TCL_PATH_DIRNAME); 00864 if (dirPtr == NULL) { 00865 return NULL; 00866 } 00867 absPtr = Tcl_FSJoinToPath(dirPtr, 1, &toPtr); 00868 Tcl_IncrRefCount(absPtr); 00869 if (Tcl_FSAccess(absPtr, F_OK) == -1) { 00870 Tcl_DecrRefCount(absPtr); 00871 Tcl_DecrRefCount(dirPtr); 00872 00873 /* 00874 * Target doesn't exist. 00875 */ 00876 00877 errno = ENOENT; 00878 return NULL; 00879 } 00880 00881 /* 00882 * Target exists; we'll construct the relative path we want below. 00883 */ 00884 00885 Tcl_DecrRefCount(absPtr); 00886 Tcl_DecrRefCount(dirPtr); 00887 } else { 00888 target = Tcl_FSGetNativePath(toPtr); 00889 if (target == NULL) { 00890 return NULL; 00891 } 00892 if (access(target, F_OK) == -1) { 00893 /* 00894 * Target doesn't exist. 00895 */ 00896 00897 errno = ENOENT; 00898 return NULL; 00899 } 00900 } 00901 00902 if (access(src, F_OK) != -1) { 00903 /* 00904 * Src exists. 00905 */ 00906 00907 errno = EEXIST; 00908 return NULL; 00909 } 00910 00911 /* 00912 * Check symbolic link flag first, since we prefer to create these. 00913 */ 00914 00915 if (linkAction & TCL_CREATE_SYMBOLIC_LINK) { 00916 int targetLen; 00917 Tcl_DString ds; 00918 Tcl_Obj *transPtr; 00919 00920 /* 00921 * Now we don't want to link to the absolute, normalized path. 00922 * Relative links are quite acceptable (but links to ~user are not 00923 * -- these must be expanded first). 00924 */ 00925 00926 transPtr = Tcl_FSGetTranslatedPath(NULL, toPtr); 00927 if (transPtr == NULL) { 00928 return NULL; 00929 } 00930 target = Tcl_GetStringFromObj(transPtr, &targetLen); 00931 target = Tcl_UtfToExternalDString(NULL, target, targetLen, &ds); 00932 Tcl_DecrRefCount(transPtr); 00933 00934 if (symlink(target, src) != 0) { 00935 toPtr = NULL; 00936 } 00937 Tcl_DStringFree(&ds); 00938 } else if (linkAction & TCL_CREATE_HARD_LINK) { 00939 if (link(target, src) != 0) { 00940 return NULL; 00941 } 00942 } else { 00943 errno = ENODEV; 00944 return NULL; 00945 } 00946 return toPtr; 00947 } else { 00948 Tcl_Obj *linkPtr = NULL; 00949 00950 char link[MAXPATHLEN]; 00951 int length; 00952 Tcl_DString ds; 00953 Tcl_Obj *transPtr; 00954 00955 transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); 00956 if (transPtr == NULL) { 00957 return NULL; 00958 } 00959 Tcl_DecrRefCount(transPtr); 00960 00961 length = readlink(Tcl_FSGetNativePath(pathPtr), link, sizeof(link)); 00962 if (length < 0) { 00963 return NULL; 00964 } 00965 00966 Tcl_ExternalToUtfDString(NULL, link, length, &ds); 00967 linkPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), 00968 Tcl_DStringLength(&ds)); 00969 Tcl_DStringFree(&ds); 00970 if (linkPtr != NULL) { 00971 Tcl_IncrRefCount(linkPtr); 00972 } 00973 return linkPtr; 00974 } 00975 } 00976 #endif /* S_IFLNK */ 00977 00978 /* 00979 *--------------------------------------------------------------------------- 00980 * 00981 * TclpFilesystemPathType -- 00982 * 00983 * This function is part of the native filesystem support, and returns 00984 * the path type of the given path. Right now it simply returns NULL. In 00985 * the future it could return specific path types, like 'nfs', 'samba', 00986 * 'FAT32', etc. 00987 * 00988 * Results: 00989 * NULL at present. 00990 * 00991 * Side effects: 00992 * None. 00993 * 00994 *--------------------------------------------------------------------------- 00995 */ 00996 00997 Tcl_Obj * 00998 TclpFilesystemPathType( 00999 Tcl_Obj *pathPtr) 01000 { 01001 /* 01002 * All native paths are of the same type. 01003 */ 01004 01005 return NULL; 01006 } 01007 01008 /* 01009 *--------------------------------------------------------------------------- 01010 * 01011 * TclpNativeToNormalized -- 01012 * 01013 * Convert native format to a normalized path object, with refCount of 01014 * zero. 01015 * 01016 * Currently assumes all native paths are actually normalized already, so 01017 * if the path given is not normalized this will actually just convert to 01018 * a valid string path, but not necessarily a normalized one. 01019 * 01020 * Results: 01021 * A valid normalized path. 01022 * 01023 * Side effects: 01024 * None. 01025 * 01026 *--------------------------------------------------------------------------- 01027 */ 01028 01029 Tcl_Obj * 01030 TclpNativeToNormalized( 01031 ClientData clientData) 01032 { 01033 Tcl_DString ds; 01034 Tcl_Obj *objPtr; 01035 int len; 01036 01037 CONST char *copy; 01038 Tcl_ExternalToUtfDString(NULL, (CONST char*)clientData, -1, &ds); 01039 01040 copy = Tcl_DStringValue(&ds); 01041 len = Tcl_DStringLength(&ds); 01042 01043 objPtr = Tcl_NewStringObj(copy,len); 01044 Tcl_DStringFree(&ds); 01045 01046 return objPtr; 01047 } 01048 01049 /* 01050 *--------------------------------------------------------------------------- 01051 * 01052 * TclNativeCreateNativeRep -- 01053 * 01054 * Create a native representation for the given path. 01055 * 01056 * Results: 01057 * The nativePath representation. 01058 * 01059 * Side effects: 01060 * Memory will be allocated. The path may need to be normalized. 01061 * 01062 *--------------------------------------------------------------------------- 01063 */ 01064 01065 ClientData 01066 TclNativeCreateNativeRep( 01067 Tcl_Obj *pathPtr) 01068 { 01069 char *nativePathPtr; 01070 Tcl_DString ds; 01071 Tcl_Obj *validPathPtr; 01072 int len; 01073 char *str; 01074 01075 if (TclFSCwdIsNative()) { 01076 /* 01077 * The cwd is native, which means we can use the translated path 01078 * without worrying about normalization (this will also usually be 01079 * shorter so the utf-to-external conversion will be somewhat faster). 01080 */ 01081 01082 validPathPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); 01083 if (validPathPtr == NULL) { 01084 return NULL; 01085 } 01086 } else { 01087 /* 01088 * Make sure the normalized path is set. 01089 */ 01090 01091 validPathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr); 01092 if (validPathPtr == NULL) { 01093 return NULL; 01094 } 01095 Tcl_IncrRefCount(validPathPtr); 01096 } 01097 01098 str = Tcl_GetStringFromObj(validPathPtr, &len); 01099 Tcl_UtfToExternalDString(NULL, str, len, &ds); 01100 len = Tcl_DStringLength(&ds) + sizeof(char); 01101 Tcl_DecrRefCount(validPathPtr); 01102 nativePathPtr = ckalloc((unsigned) len); 01103 memcpy((void*)nativePathPtr, (void*)Tcl_DStringValue(&ds), (size_t) len); 01104 01105 Tcl_DStringFree(&ds); 01106 return (ClientData)nativePathPtr; 01107 } 01108 01109 /* 01110 *--------------------------------------------------------------------------- 01111 * 01112 * TclNativeDupInternalRep -- 01113 * 01114 * Duplicate the native representation. 01115 * 01116 * Results: 01117 * The copied native representation, or NULL if it is not possible to 01118 * copy the representation. 01119 * 01120 * Side effects: 01121 * Memory will be allocated for the copy. 01122 * 01123 *--------------------------------------------------------------------------- 01124 */ 01125 01126 ClientData 01127 TclNativeDupInternalRep( 01128 ClientData clientData) 01129 { 01130 char *copy; 01131 size_t len; 01132 01133 if (clientData == NULL) { 01134 return NULL; 01135 } 01136 01137 /* 01138 * ASCII representation when running on Unix. 01139 */ 01140 01141 len = sizeof(char) + (strlen((CONST char*) clientData) * sizeof(char)); 01142 01143 copy = (char *) ckalloc(len); 01144 memcpy((void *) copy, (void *) clientData, len); 01145 return (ClientData)copy; 01146 } 01147 01148 /* 01149 *--------------------------------------------------------------------------- 01150 * 01151 * TclpUtime -- 01152 * 01153 * Set the modification date for a file. 01154 * 01155 * Results: 01156 * 0 on success, -1 on error. 01157 * 01158 * Side effects: 01159 * None. 01160 * 01161 *--------------------------------------------------------------------------- 01162 */ 01163 01164 int 01165 TclpUtime( 01166 Tcl_Obj *pathPtr, /* File to modify */ 01167 struct utimbuf *tval) /* New modification date structure */ 01168 { 01169 return utime(Tcl_FSGetNativePath(pathPtr), tval); 01170 } 01171 01172 /* 01173 * Local Variables: 01174 * mode: c 01175 * c-basic-offset: 4 01176 * fill-column: 78 01177 * End: 01178 */
Generated on Wed Mar 12 12:18:26 2008 by 1.5.1 |