[25] | 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 of |
---|
| 10 | * this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
| 11 | * |
---|
| 12 | * RCS: @(#) $Id: tclUnixFile.c,v 1.52 2007/12/13 15:28:42 dgp Exp $ |
---|
| 13 | */ |
---|
| 14 | |
---|
| 15 | #include "tclInt.h" |
---|
| 16 | #include "tclFileSystem.h" |
---|
| 17 | |
---|
| 18 | static int NativeMatchType(Tcl_Interp *interp, CONST char* nativeEntry, |
---|
| 19 | CONST char* nativeName, Tcl_GlobTypeData *types); |
---|
| 20 | |
---|
| 21 | /* |
---|
| 22 | *--------------------------------------------------------------------------- |
---|
| 23 | * |
---|
| 24 | * TclpFindExecutable -- |
---|
| 25 | * |
---|
| 26 | * This function computes the absolute path name of the current |
---|
| 27 | * application, given its argv[0] value. |
---|
| 28 | * |
---|
| 29 | * Results: |
---|
| 30 | * None. |
---|
| 31 | * |
---|
| 32 | * Side effects: |
---|
| 33 | * The computed path name is stored as a ProcessGlobalValue. |
---|
| 34 | * |
---|
| 35 | *--------------------------------------------------------------------------- |
---|
| 36 | */ |
---|
| 37 | |
---|
| 38 | void |
---|
| 39 | TclpFindExecutable( |
---|
| 40 | CONST char *argv0) /* The value of the application's argv[0] |
---|
| 41 | * (native). */ |
---|
| 42 | { |
---|
| 43 | CONST char *name, *p; |
---|
| 44 | Tcl_StatBuf statBuf; |
---|
| 45 | Tcl_DString buffer, nameString, cwd, utfName; |
---|
| 46 | Tcl_Encoding encoding; |
---|
| 47 | |
---|
| 48 | if (argv0 == NULL) { |
---|
| 49 | return; |
---|
| 50 | } |
---|
| 51 | Tcl_DStringInit(&buffer); |
---|
| 52 | |
---|
| 53 | name = argv0; |
---|
| 54 | for (p = name; *p != '\0'; p++) { |
---|
| 55 | if (*p == '/') { |
---|
| 56 | /* |
---|
| 57 | * The name contains a slash, so use the name directly without |
---|
| 58 | * doing a path search. |
---|
| 59 | */ |
---|
| 60 | |
---|
| 61 | goto gotName; |
---|
| 62 | } |
---|
| 63 | } |
---|
| 64 | |
---|
| 65 | p = getenv("PATH"); /* INTL: Native. */ |
---|
| 66 | if (p == NULL) { |
---|
| 67 | /* |
---|
| 68 | * There's no PATH environment variable; use the default that is used |
---|
| 69 | * by sh. |
---|
| 70 | */ |
---|
| 71 | |
---|
| 72 | p = ":/bin:/usr/bin"; |
---|
| 73 | } else if (*p == '\0') { |
---|
| 74 | /* |
---|
| 75 | * An empty path is equivalent to ".". |
---|
| 76 | */ |
---|
| 77 | |
---|
| 78 | p = "./"; |
---|
| 79 | } |
---|
| 80 | |
---|
| 81 | /* |
---|
| 82 | * Search through all the directories named in the PATH variable to see if |
---|
| 83 | * argv[0] is in one of them. If so, use that file name. |
---|
| 84 | */ |
---|
| 85 | |
---|
| 86 | while (1) { |
---|
| 87 | while (isspace(UCHAR(*p))) { /* INTL: BUG */ |
---|
| 88 | p++; |
---|
| 89 | } |
---|
| 90 | name = p; |
---|
| 91 | while ((*p != ':') && (*p != 0)) { |
---|
| 92 | p++; |
---|
| 93 | } |
---|
| 94 | Tcl_DStringSetLength(&buffer, 0); |
---|
| 95 | if (p != name) { |
---|
| 96 | Tcl_DStringAppend(&buffer, name, p - name); |
---|
| 97 | if (p[-1] != '/') { |
---|
| 98 | Tcl_DStringAppend(&buffer, "/", 1); |
---|
| 99 | } |
---|
| 100 | } |
---|
| 101 | name = Tcl_DStringAppend(&buffer, argv0, -1); |
---|
| 102 | |
---|
| 103 | /* |
---|
| 104 | * INTL: The following calls to access() and stat() should not be |
---|
| 105 | * converted to Tclp routines because they need to operate on native |
---|
| 106 | * strings directly. |
---|
| 107 | */ |
---|
| 108 | |
---|
| 109 | if ((access(name, X_OK) == 0) /* INTL: Native. */ |
---|
| 110 | && (TclOSstat(name, &statBuf) == 0) /* INTL: Native. */ |
---|
| 111 | && S_ISREG(statBuf.st_mode)) { |
---|
| 112 | goto gotName; |
---|
| 113 | } |
---|
| 114 | if (*p == '\0') { |
---|
| 115 | break; |
---|
| 116 | } else if (*(p+1) == 0) { |
---|
| 117 | p = "./"; |
---|
| 118 | } else { |
---|
| 119 | p++; |
---|
| 120 | } |
---|
| 121 | } |
---|
| 122 | TclSetObjNameOfExecutable(Tcl_NewObj(), NULL); |
---|
| 123 | goto done; |
---|
| 124 | |
---|
| 125 | /* |
---|
| 126 | * If the name starts with "/" then just store it |
---|
| 127 | */ |
---|
| 128 | |
---|
| 129 | gotName: |
---|
| 130 | #ifdef DJGPP |
---|
| 131 | if (name[1] == ':') |
---|
| 132 | #else |
---|
| 133 | if (name[0] == '/') |
---|
| 134 | #endif |
---|
| 135 | { |
---|
| 136 | encoding = Tcl_GetEncoding(NULL, NULL); |
---|
| 137 | Tcl_ExternalToUtfDString(encoding, name, -1, &utfName); |
---|
| 138 | TclSetObjNameOfExecutable( |
---|
| 139 | Tcl_NewStringObj(Tcl_DStringValue(&utfName), -1), encoding); |
---|
| 140 | Tcl_DStringFree(&utfName); |
---|
| 141 | goto done; |
---|
| 142 | } |
---|
| 143 | |
---|
| 144 | /* |
---|
| 145 | * The name is relative to the current working directory. First strip off |
---|
| 146 | * a leading "./", if any, then add the full path name of the current |
---|
| 147 | * working directory. |
---|
| 148 | */ |
---|
| 149 | |
---|
| 150 | if ((name[0] == '.') && (name[1] == '/')) { |
---|
| 151 | name += 2; |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | Tcl_DStringInit(&nameString); |
---|
| 155 | Tcl_DStringAppend(&nameString, name, -1); |
---|
| 156 | |
---|
| 157 | TclpGetCwd(NULL, &cwd); |
---|
| 158 | |
---|
| 159 | Tcl_DStringFree(&buffer); |
---|
| 160 | Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&cwd), |
---|
| 161 | Tcl_DStringLength(&cwd), &buffer); |
---|
| 162 | if (Tcl_DStringValue(&cwd)[Tcl_DStringLength(&cwd) -1] != '/') { |
---|
| 163 | Tcl_DStringAppend(&buffer, "/", 1); |
---|
| 164 | } |
---|
| 165 | Tcl_DStringFree(&cwd); |
---|
| 166 | Tcl_DStringAppend(&buffer, Tcl_DStringValue(&nameString), |
---|
| 167 | Tcl_DStringLength(&nameString)); |
---|
| 168 | Tcl_DStringFree(&nameString); |
---|
| 169 | |
---|
| 170 | encoding = Tcl_GetEncoding(NULL, NULL); |
---|
| 171 | Tcl_ExternalToUtfDString(encoding, Tcl_DStringValue(&buffer), -1, |
---|
| 172 | &utfName); |
---|
| 173 | TclSetObjNameOfExecutable( |
---|
| 174 | Tcl_NewStringObj(Tcl_DStringValue(&utfName), -1), encoding); |
---|
| 175 | Tcl_DStringFree(&utfName); |
---|
| 176 | |
---|
| 177 | done: |
---|
| 178 | Tcl_DStringFree(&buffer); |
---|
| 179 | } |
---|
| 180 | |
---|
| 181 | /* |
---|
| 182 | *---------------------------------------------------------------------- |
---|
| 183 | * |
---|
| 184 | * TclpMatchInDirectory -- |
---|
| 185 | * |
---|
| 186 | * This routine is used by the globbing code to search a directory for |
---|
| 187 | * all files which match a given pattern. |
---|
| 188 | * |
---|
| 189 | * Results: |
---|
| 190 | * The return value is a standard Tcl result indicating whether an error |
---|
| 191 | * occurred in globbing. Errors are left in interp, good results are |
---|
| 192 | * [lappend]ed to resultPtr (which must be a valid object). |
---|
| 193 | * |
---|
| 194 | * Side effects: |
---|
| 195 | * None. |
---|
| 196 | * |
---|
| 197 | *---------------------------------------------------------------------- |
---|
| 198 | */ |
---|
| 199 | |
---|
| 200 | int |
---|
| 201 | TclpMatchInDirectory( |
---|
| 202 | Tcl_Interp *interp, /* Interpreter to receive errors. */ |
---|
| 203 | Tcl_Obj *resultPtr, /* List object to lappend results. */ |
---|
| 204 | Tcl_Obj *pathPtr, /* Contains path to directory to search. */ |
---|
| 205 | CONST char *pattern, /* Pattern to match against. */ |
---|
| 206 | Tcl_GlobTypeData *types) /* Object containing list of acceptable types. |
---|
| 207 | * May be NULL. In particular the directory |
---|
| 208 | * flag is very important. */ |
---|
| 209 | { |
---|
| 210 | CONST char *native; |
---|
| 211 | Tcl_Obj *fileNamePtr; |
---|
| 212 | int matchResult = 0; |
---|
| 213 | |
---|
| 214 | if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) { |
---|
| 215 | /* |
---|
| 216 | * The native filesystem never adds mounts. |
---|
| 217 | */ |
---|
| 218 | |
---|
| 219 | return TCL_OK; |
---|
| 220 | } |
---|
| 221 | |
---|
| 222 | fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr); |
---|
| 223 | if (fileNamePtr == NULL) { |
---|
| 224 | return TCL_ERROR; |
---|
| 225 | } |
---|
| 226 | |
---|
| 227 | if (pattern == NULL || (*pattern == '\0')) { |
---|
| 228 | /* |
---|
| 229 | * Match a file directly. |
---|
| 230 | */ |
---|
| 231 | Tcl_Obj *tailPtr; |
---|
| 232 | CONST char *nativeTail; |
---|
| 233 | |
---|
| 234 | native = (CONST char*) Tcl_FSGetNativePath(pathPtr); |
---|
| 235 | tailPtr = TclPathPart(interp, pathPtr, TCL_PATH_TAIL); |
---|
| 236 | nativeTail = (CONST char*) Tcl_FSGetNativePath(tailPtr); |
---|
| 237 | matchResult = NativeMatchType(interp, native, nativeTail, types); |
---|
| 238 | if (matchResult == 1) { |
---|
| 239 | Tcl_ListObjAppendElement(interp, resultPtr, pathPtr); |
---|
| 240 | } |
---|
| 241 | Tcl_DecrRefCount(tailPtr); |
---|
| 242 | Tcl_DecrRefCount(fileNamePtr); |
---|
| 243 | } else { |
---|
| 244 | DIR *d; |
---|
| 245 | Tcl_DirEntry *entryPtr; |
---|
| 246 | CONST char *dirName; |
---|
| 247 | int dirLength; |
---|
| 248 | int matchHidden, matchHiddenPat; |
---|
| 249 | int nativeDirLen; |
---|
| 250 | Tcl_StatBuf statBuf; |
---|
| 251 | Tcl_DString ds; /* native encoding of dir */ |
---|
| 252 | Tcl_DString dsOrig; /* utf-8 encoding of dir */ |
---|
| 253 | |
---|
| 254 | Tcl_DStringInit(&dsOrig); |
---|
| 255 | dirName = Tcl_GetStringFromObj(fileNamePtr, &dirLength); |
---|
| 256 | Tcl_DStringAppend(&dsOrig, dirName, dirLength); |
---|
| 257 | |
---|
| 258 | /* |
---|
| 259 | * Make sure that the directory part of the name really is a |
---|
| 260 | * directory. If the directory name is "", use the name "." instead, |
---|
| 261 | * because some UNIX systems don't treat "" like "." automatically. |
---|
| 262 | * Keep the "" for use in generating file names, otherwise "glob |
---|
| 263 | * foo.c" would return "./foo.c". |
---|
| 264 | */ |
---|
| 265 | |
---|
| 266 | if (dirLength == 0) { |
---|
| 267 | dirName = "."; |
---|
| 268 | } else { |
---|
| 269 | dirName = Tcl_DStringValue(&dsOrig); |
---|
| 270 | |
---|
| 271 | /* |
---|
| 272 | * Make sure we have a trailing directory delimiter. |
---|
| 273 | */ |
---|
| 274 | |
---|
| 275 | if (dirName[dirLength-1] != '/') { |
---|
| 276 | dirName = Tcl_DStringAppend(&dsOrig, "/", 1); |
---|
| 277 | dirLength++; |
---|
| 278 | } |
---|
| 279 | } |
---|
| 280 | |
---|
| 281 | /* |
---|
| 282 | * Now open the directory for reading and iterate over the contents. |
---|
| 283 | */ |
---|
| 284 | |
---|
| 285 | native = Tcl_UtfToExternalDString(NULL, dirName, -1, &ds); |
---|
| 286 | |
---|
| 287 | if ((TclOSstat(native, &statBuf) != 0) /* INTL: Native. */ |
---|
| 288 | || !S_ISDIR(statBuf.st_mode)) { |
---|
| 289 | Tcl_DStringFree(&dsOrig); |
---|
| 290 | Tcl_DStringFree(&ds); |
---|
| 291 | Tcl_DecrRefCount(fileNamePtr); |
---|
| 292 | return TCL_OK; |
---|
| 293 | } |
---|
| 294 | |
---|
| 295 | d = opendir(native); /* INTL: Native. */ |
---|
| 296 | if (d == NULL) { |
---|
| 297 | Tcl_DStringFree(&ds); |
---|
| 298 | if (interp != NULL) { |
---|
| 299 | Tcl_ResetResult(interp); |
---|
| 300 | Tcl_AppendResult(interp, "couldn't read directory \"", |
---|
| 301 | Tcl_DStringValue(&dsOrig), "\": ", |
---|
| 302 | Tcl_PosixError(interp), (char *) NULL); |
---|
| 303 | } |
---|
| 304 | Tcl_DStringFree(&dsOrig); |
---|
| 305 | Tcl_DecrRefCount(fileNamePtr); |
---|
| 306 | return TCL_ERROR; |
---|
| 307 | } |
---|
| 308 | |
---|
| 309 | nativeDirLen = Tcl_DStringLength(&ds); |
---|
| 310 | |
---|
| 311 | /* |
---|
| 312 | * Check to see if -type or the pattern requests hidden files. |
---|
| 313 | */ |
---|
| 314 | |
---|
| 315 | matchHiddenPat = (pattern[0] == '.') |
---|
| 316 | || ((pattern[0] == '\\') && (pattern[1] == '.')); |
---|
| 317 | matchHidden = matchHiddenPat |
---|
| 318 | || (types && (types->perm & TCL_GLOB_PERM_HIDDEN)); |
---|
| 319 | while ((entryPtr = TclOSreaddir(d)) != NULL) { /* INTL: Native. */ |
---|
| 320 | Tcl_DString utfDs; |
---|
| 321 | CONST char *utfname; |
---|
| 322 | |
---|
| 323 | /* |
---|
| 324 | * Skip this file if it doesn't agree with the hidden parameters |
---|
| 325 | * requested by the user (via -type or pattern). |
---|
| 326 | */ |
---|
| 327 | |
---|
| 328 | if (*entryPtr->d_name == '.') { |
---|
| 329 | if (!matchHidden) continue; |
---|
| 330 | } else { |
---|
| 331 | #ifdef MAC_OSX_TCL |
---|
| 332 | if (matchHiddenPat) continue; |
---|
| 333 | /* Also need to check HFS hidden flag in TclMacOSXMatchType. */ |
---|
| 334 | #else |
---|
| 335 | if (matchHidden) continue; |
---|
| 336 | #endif |
---|
| 337 | } |
---|
| 338 | |
---|
| 339 | /* |
---|
| 340 | * Now check to see if the file matches, according to both type |
---|
| 341 | * and pattern. If so, add the file to the result. |
---|
| 342 | */ |
---|
| 343 | |
---|
| 344 | utfname = Tcl_ExternalToUtfDString(NULL, entryPtr->d_name, -1, |
---|
| 345 | &utfDs); |
---|
| 346 | if (Tcl_StringCaseMatch(utfname, pattern, 0)) { |
---|
| 347 | int typeOk = 1; |
---|
| 348 | |
---|
| 349 | if (types != NULL) { |
---|
| 350 | Tcl_DStringSetLength(&ds, nativeDirLen); |
---|
| 351 | native = Tcl_DStringAppend(&ds, entryPtr->d_name, -1); |
---|
| 352 | matchResult = NativeMatchType(interp, native, |
---|
| 353 | entryPtr->d_name, types); |
---|
| 354 | typeOk = (matchResult == 1); |
---|
| 355 | } |
---|
| 356 | if (typeOk) { |
---|
| 357 | Tcl_ListObjAppendElement(interp, resultPtr, |
---|
| 358 | TclNewFSPathObj(pathPtr, utfname, |
---|
| 359 | Tcl_DStringLength(&utfDs))); |
---|
| 360 | } |
---|
| 361 | } |
---|
| 362 | Tcl_DStringFree(&utfDs); |
---|
| 363 | if (matchResult < 0) { |
---|
| 364 | break; |
---|
| 365 | } |
---|
| 366 | } |
---|
| 367 | |
---|
| 368 | closedir(d); |
---|
| 369 | Tcl_DStringFree(&ds); |
---|
| 370 | Tcl_DStringFree(&dsOrig); |
---|
| 371 | Tcl_DecrRefCount(fileNamePtr); |
---|
| 372 | } |
---|
| 373 | if (matchResult < 0) { |
---|
| 374 | return TCL_ERROR; |
---|
| 375 | } else { |
---|
| 376 | return TCL_OK; |
---|
| 377 | } |
---|
| 378 | } |
---|
| 379 | |
---|
| 380 | /* |
---|
| 381 | *---------------------------------------------------------------------- |
---|
| 382 | * |
---|
| 383 | * NativeMatchType -- |
---|
| 384 | * |
---|
| 385 | * This routine is used by the globbing code to check if a file |
---|
| 386 | * matches a given type description. |
---|
| 387 | * |
---|
| 388 | * Results: |
---|
| 389 | * The return value is 1, 0 or -1 indicating whether the file |
---|
| 390 | * matches the given criteria, does not match them, or an error |
---|
| 391 | * occurred (in wich case an error is left in interp). |
---|
| 392 | * |
---|
| 393 | * Side effects: |
---|
| 394 | * None. |
---|
| 395 | * |
---|
| 396 | *---------------------------------------------------------------------- |
---|
| 397 | */ |
---|
| 398 | |
---|
| 399 | static int |
---|
| 400 | NativeMatchType( |
---|
| 401 | Tcl_Interp *interp, /* Interpreter to receive errors. */ |
---|
| 402 | CONST char *nativeEntry, /* Native path to check. */ |
---|
| 403 | CONST char *nativeName, /* Native filename to check. */ |
---|
| 404 | Tcl_GlobTypeData *types) /* Type description to match against. */ |
---|
| 405 | { |
---|
| 406 | Tcl_StatBuf buf; |
---|
| 407 | if (types == NULL) { |
---|
| 408 | /* |
---|
| 409 | * Simply check for the file's existence, but do it with lstat, in |
---|
| 410 | * case it is a link to a file which doesn't exist (since that case |
---|
| 411 | * would not show up if we used 'access' or 'stat') |
---|
| 412 | */ |
---|
| 413 | |
---|
| 414 | if (TclOSlstat(nativeEntry, &buf) != 0) { |
---|
| 415 | return 0; |
---|
| 416 | } |
---|
| 417 | } else { |
---|
| 418 | if (types->perm != 0) { |
---|
| 419 | if (TclOSstat(nativeEntry, &buf) != 0) { |
---|
| 420 | /* |
---|
| 421 | * Either the file has disappeared between the 'readdir' call |
---|
| 422 | * and the 'stat' call, or the file is a link to a file which |
---|
| 423 | * doesn't exist (which we could ascertain with lstat), or |
---|
| 424 | * there is some other strange problem. In all these cases, we |
---|
| 425 | * define this to mean the file does not match any defined |
---|
| 426 | * permission, and therefore it is not added to the list of |
---|
| 427 | * files to return. |
---|
| 428 | */ |
---|
| 429 | |
---|
| 430 | return 0; |
---|
| 431 | } |
---|
| 432 | |
---|
| 433 | /* |
---|
| 434 | * readonly means that there are NO write permissions (even for |
---|
| 435 | * user), but execute is OK for anybody OR that the user immutable |
---|
| 436 | * flag is set (where supported). |
---|
| 437 | */ |
---|
| 438 | |
---|
| 439 | if (((types->perm & TCL_GLOB_PERM_RONLY) && |
---|
| 440 | #if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) |
---|
| 441 | !(buf.st_flags & UF_IMMUTABLE) && |
---|
| 442 | #endif |
---|
| 443 | (buf.st_mode & (S_IWOTH|S_IWGRP|S_IWUSR))) || |
---|
| 444 | ((types->perm & TCL_GLOB_PERM_R) && |
---|
| 445 | (access(nativeEntry, R_OK) != 0)) || |
---|
| 446 | ((types->perm & TCL_GLOB_PERM_W) && |
---|
| 447 | (access(nativeEntry, W_OK) != 0)) || |
---|
| 448 | ((types->perm & TCL_GLOB_PERM_X) && |
---|
| 449 | (access(nativeEntry, X_OK) != 0)) |
---|
| 450 | #ifndef MAC_OSX_TCL |
---|
| 451 | || ((types->perm & TCL_GLOB_PERM_HIDDEN) && |
---|
| 452 | (*nativeName != '.')) |
---|
| 453 | #endif |
---|
| 454 | ) { |
---|
| 455 | return 0; |
---|
| 456 | } |
---|
| 457 | } |
---|
| 458 | if (types->type != 0) { |
---|
| 459 | if (types->perm == 0) { |
---|
| 460 | /* |
---|
| 461 | * We haven't yet done a stat on the file. |
---|
| 462 | */ |
---|
| 463 | |
---|
| 464 | if (TclOSstat(nativeEntry, &buf) != 0) { |
---|
| 465 | /* |
---|
| 466 | * Posix error occurred. The only ok case is if this is a |
---|
| 467 | * link to a nonexistent file, and the user did 'glob -l'. |
---|
| 468 | * So we check that here: |
---|
| 469 | */ |
---|
| 470 | |
---|
| 471 | if (types->type & TCL_GLOB_TYPE_LINK) { |
---|
| 472 | if (TclOSlstat(nativeEntry, &buf) == 0) { |
---|
| 473 | if (S_ISLNK(buf.st_mode)) { |
---|
| 474 | return 1; |
---|
| 475 | } |
---|
| 476 | } |
---|
| 477 | } |
---|
| 478 | return 0; |
---|
| 479 | } |
---|
| 480 | } |
---|
| 481 | |
---|
| 482 | /* |
---|
| 483 | * In order bcdpfls as in 'find -t' |
---|
| 484 | */ |
---|
| 485 | |
---|
| 486 | if (((types->type & TCL_GLOB_TYPE_BLOCK)&& S_ISBLK(buf.st_mode)) || |
---|
| 487 | ((types->type & TCL_GLOB_TYPE_CHAR) && S_ISCHR(buf.st_mode)) || |
---|
| 488 | ((types->type & TCL_GLOB_TYPE_DIR) && S_ISDIR(buf.st_mode)) || |
---|
| 489 | ((types->type & TCL_GLOB_TYPE_PIPE) && S_ISFIFO(buf.st_mode))|| |
---|
| 490 | ((types->type & TCL_GLOB_TYPE_FILE) && S_ISREG(buf.st_mode)) |
---|
| 491 | #ifdef S_ISSOCK |
---|
| 492 | ||((types->type & TCL_GLOB_TYPE_SOCK) && S_ISSOCK(buf.st_mode)) |
---|
| 493 | #endif /* S_ISSOCK */ |
---|
| 494 | ) { |
---|
| 495 | /* |
---|
| 496 | * Do nothing - this file is ok. |
---|
| 497 | */ |
---|
| 498 | } else { |
---|
| 499 | #ifdef S_ISLNK |
---|
| 500 | if (types->type & TCL_GLOB_TYPE_LINK) { |
---|
| 501 | if (TclOSlstat(nativeEntry, &buf) == 0) { |
---|
| 502 | if (S_ISLNK(buf.st_mode)) { |
---|
| 503 | goto filetypeOK; |
---|
| 504 | } |
---|
| 505 | } |
---|
| 506 | } |
---|
| 507 | #endif /* S_ISLNK */ |
---|
| 508 | return 0; |
---|
| 509 | } |
---|
| 510 | } |
---|
| 511 | filetypeOK: ; |
---|
| 512 | #ifdef MAC_OSX_TCL |
---|
| 513 | if (types->macType != NULL || types->macCreator != NULL || |
---|
| 514 | (types->perm & TCL_GLOB_PERM_HIDDEN)) { |
---|
| 515 | int matchResult; |
---|
| 516 | |
---|
| 517 | if (types->perm == 0 && types->type == 0) { |
---|
| 518 | /* |
---|
| 519 | * We haven't yet done a stat on the file. |
---|
| 520 | */ |
---|
| 521 | |
---|
| 522 | if (TclOSstat(nativeEntry, &buf) != 0) { |
---|
| 523 | return 0; |
---|
| 524 | } |
---|
| 525 | } |
---|
| 526 | |
---|
| 527 | matchResult = TclMacOSXMatchType(interp, nativeEntry, nativeName, |
---|
| 528 | &buf, types); |
---|
| 529 | if (matchResult != 1) { |
---|
| 530 | return matchResult; |
---|
| 531 | } |
---|
| 532 | } |
---|
| 533 | #endif |
---|
| 534 | } |
---|
| 535 | return 1; |
---|
| 536 | } |
---|
| 537 | |
---|
| 538 | /* |
---|
| 539 | *--------------------------------------------------------------------------- |
---|
| 540 | * |
---|
| 541 | * TclpGetUserHome -- |
---|
| 542 | * |
---|
| 543 | * This function takes the specified user name and finds their home |
---|
| 544 | * directory. |
---|
| 545 | * |
---|
| 546 | * Results: |
---|
| 547 | * The result is a pointer to a string specifying the user's home |
---|
| 548 | * directory, or NULL if the user's home directory could not be |
---|
| 549 | * determined. Storage for the result string is allocated in bufferPtr; |
---|
| 550 | * the caller must call Tcl_DStringFree() when the result is no longer |
---|
| 551 | * needed. |
---|
| 552 | * |
---|
| 553 | * Side effects: |
---|
| 554 | * None. |
---|
| 555 | * |
---|
| 556 | *---------------------------------------------------------------------- |
---|
| 557 | */ |
---|
| 558 | |
---|
| 559 | char * |
---|
| 560 | TclpGetUserHome( |
---|
| 561 | CONST char *name, /* User name for desired home directory. */ |
---|
| 562 | Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with |
---|
| 563 | * name of user's home directory. */ |
---|
| 564 | { |
---|
| 565 | struct passwd *pwPtr; |
---|
| 566 | Tcl_DString ds; |
---|
| 567 | CONST char *native; |
---|
| 568 | |
---|
| 569 | native = Tcl_UtfToExternalDString(NULL, name, -1, &ds); |
---|
| 570 | pwPtr = getpwnam(native); /* INTL: Native. */ |
---|
| 571 | Tcl_DStringFree(&ds); |
---|
| 572 | |
---|
| 573 | if (pwPtr == NULL) { |
---|
| 574 | endpwent(); |
---|
| 575 | return NULL; |
---|
| 576 | } |
---|
| 577 | Tcl_ExternalToUtfDString(NULL, pwPtr->pw_dir, -1, bufferPtr); |
---|
| 578 | endpwent(); |
---|
| 579 | return Tcl_DStringValue(bufferPtr); |
---|
| 580 | } |
---|
| 581 | |
---|
| 582 | /* |
---|
| 583 | *--------------------------------------------------------------------------- |
---|
| 584 | * |
---|
| 585 | * TclpObjAccess -- |
---|
| 586 | * |
---|
| 587 | * This function replaces the library version of access(). |
---|
| 588 | * |
---|
| 589 | * Results: |
---|
| 590 | * See access() documentation. |
---|
| 591 | * |
---|
| 592 | * Side effects: |
---|
| 593 | * See access() documentation. |
---|
| 594 | * |
---|
| 595 | *--------------------------------------------------------------------------- |
---|
| 596 | */ |
---|
| 597 | |
---|
| 598 | int |
---|
| 599 | TclpObjAccess( |
---|
| 600 | Tcl_Obj *pathPtr, /* Path of file to access */ |
---|
| 601 | int mode) /* Permission setting. */ |
---|
| 602 | { |
---|
| 603 | CONST char *path = Tcl_FSGetNativePath(pathPtr); |
---|
| 604 | if (path == NULL) { |
---|
| 605 | return -1; |
---|
| 606 | } else { |
---|
| 607 | return access(path, mode); |
---|
| 608 | } |
---|
| 609 | } |
---|
| 610 | |
---|
| 611 | /* |
---|
| 612 | *--------------------------------------------------------------------------- |
---|
| 613 | * |
---|
| 614 | * TclpObjChdir -- |
---|
| 615 | * |
---|
| 616 | * This function replaces the library version of chdir(). |
---|
| 617 | * |
---|
| 618 | * Results: |
---|
| 619 | * See chdir() documentation. |
---|
| 620 | * |
---|
| 621 | * Side effects: |
---|
| 622 | * See chdir() documentation. |
---|
| 623 | * |
---|
| 624 | *--------------------------------------------------------------------------- |
---|
| 625 | */ |
---|
| 626 | |
---|
| 627 | int |
---|
| 628 | TclpObjChdir( |
---|
| 629 | Tcl_Obj *pathPtr) /* Path to new working directory */ |
---|
| 630 | { |
---|
| 631 | CONST char *path = Tcl_FSGetNativePath(pathPtr); |
---|
| 632 | if (path == NULL) { |
---|
| 633 | return -1; |
---|
| 634 | } else { |
---|
| 635 | return chdir(path); |
---|
| 636 | } |
---|
| 637 | } |
---|
| 638 | |
---|
| 639 | /* |
---|
| 640 | *---------------------------------------------------------------------- |
---|
| 641 | * |
---|
| 642 | * TclpObjLstat -- |
---|
| 643 | * |
---|
| 644 | * This function replaces the library version of lstat(). |
---|
| 645 | * |
---|
| 646 | * Results: |
---|
| 647 | * See lstat() documentation. |
---|
| 648 | * |
---|
| 649 | * Side effects: |
---|
| 650 | * See lstat() documentation. |
---|
| 651 | * |
---|
| 652 | *---------------------------------------------------------------------- |
---|
| 653 | */ |
---|
| 654 | |
---|
| 655 | int |
---|
| 656 | TclpObjLstat( |
---|
| 657 | Tcl_Obj *pathPtr, /* Path of file to stat */ |
---|
| 658 | Tcl_StatBuf *bufPtr) /* Filled with results of stat call. */ |
---|
| 659 | { |
---|
| 660 | return TclOSlstat(Tcl_FSGetNativePath(pathPtr), bufPtr); |
---|
| 661 | } |
---|
| 662 | |
---|
| 663 | /* |
---|
| 664 | *--------------------------------------------------------------------------- |
---|
| 665 | * |
---|
| 666 | * TclpGetNativeCwd -- |
---|
| 667 | * |
---|
| 668 | * This function replaces the library version of getcwd(). |
---|
| 669 | * |
---|
| 670 | * Results: |
---|
| 671 | * The input and output are filesystem paths in native form. The result |
---|
| 672 | * is either the given clientData, if the working directory hasn't |
---|
| 673 | * changed, or a new clientData (owned by our caller), giving the new |
---|
| 674 | * native path, or NULL if the current directory could not be determined. |
---|
| 675 | * If NULL is returned, the caller can examine the standard posix error |
---|
| 676 | * codes to determine the cause of the problem. |
---|
| 677 | * |
---|
| 678 | * Side effects: |
---|
| 679 | * None. |
---|
| 680 | * |
---|
| 681 | *---------------------------------------------------------------------- |
---|
| 682 | */ |
---|
| 683 | |
---|
| 684 | ClientData |
---|
| 685 | TclpGetNativeCwd( |
---|
| 686 | ClientData clientData) |
---|
| 687 | { |
---|
| 688 | char buffer[MAXPATHLEN+1]; |
---|
| 689 | |
---|
| 690 | #ifdef USEGETWD |
---|
| 691 | if (getwd(buffer) == NULL) /* INTL: Native. */ |
---|
| 692 | #else |
---|
| 693 | if (getcwd(buffer, MAXPATHLEN+1) == NULL) /* INTL: Native. */ |
---|
| 694 | #endif |
---|
| 695 | { |
---|
| 696 | return NULL; |
---|
| 697 | } |
---|
| 698 | if ((clientData != NULL) && strcmp(buffer, (CONST char*)clientData) == 0) { |
---|
| 699 | /* |
---|
| 700 | * No change to pwd. |
---|
| 701 | */ |
---|
| 702 | |
---|
| 703 | return clientData; |
---|
| 704 | } else { |
---|
| 705 | char *newCd = (char *) ckalloc((unsigned) (strlen(buffer) + 1)); |
---|
| 706 | strcpy(newCd, buffer); |
---|
| 707 | return (ClientData) newCd; |
---|
| 708 | } |
---|
| 709 | } |
---|
| 710 | |
---|
| 711 | /* |
---|
| 712 | *--------------------------------------------------------------------------- |
---|
| 713 | * |
---|
| 714 | * TclpGetCwd -- |
---|
| 715 | * |
---|
| 716 | * This function replaces the library version of getcwd(). (Obsolete |
---|
| 717 | * function, only retained for old extensions which may call it |
---|
| 718 | * directly). |
---|
| 719 | * |
---|
| 720 | * Results: |
---|
| 721 | * The result is a pointer to a string specifying the current directory, |
---|
| 722 | * or NULL if the current directory could not be determined. If NULL is |
---|
| 723 | * returned, an error message is left in the interp's result. Storage for |
---|
| 724 | * the result string is allocated in bufferPtr; the caller must call |
---|
| 725 | * Tcl_DStringFree() when the result is no longer needed. |
---|
| 726 | * |
---|
| 727 | * Side effects: |
---|
| 728 | * None. |
---|
| 729 | * |
---|
| 730 | *---------------------------------------------------------------------- |
---|
| 731 | */ |
---|
| 732 | |
---|
| 733 | CONST char * |
---|
| 734 | TclpGetCwd( |
---|
| 735 | Tcl_Interp *interp, /* If non-NULL, used for error reporting. */ |
---|
| 736 | Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with |
---|
| 737 | * name of current directory. */ |
---|
| 738 | { |
---|
| 739 | char buffer[MAXPATHLEN+1]; |
---|
| 740 | |
---|
| 741 | #ifdef USEGETWD |
---|
| 742 | if (getwd(buffer) == NULL) /* INTL: Native. */ |
---|
| 743 | #else |
---|
| 744 | if (getcwd(buffer, MAXPATHLEN+1) == NULL) /* INTL: Native. */ |
---|
| 745 | #endif |
---|
| 746 | { |
---|
| 747 | if (interp != NULL) { |
---|
| 748 | Tcl_AppendResult(interp, |
---|
| 749 | "error getting working directory name: ", |
---|
| 750 | Tcl_PosixError(interp), NULL); |
---|
| 751 | } |
---|
| 752 | return NULL; |
---|
| 753 | } |
---|
| 754 | return Tcl_ExternalToUtfDString(NULL, buffer, -1, bufferPtr); |
---|
| 755 | } |
---|
| 756 | |
---|
| 757 | /* |
---|
| 758 | *--------------------------------------------------------------------------- |
---|
| 759 | * |
---|
| 760 | * TclpReadlink -- |
---|
| 761 | * |
---|
| 762 | * This function replaces the library version of readlink(). |
---|
| 763 | * |
---|
| 764 | * Results: |
---|
| 765 | * The result is a pointer to a string specifying the contents of the |
---|
| 766 | * symbolic link given by 'path', or NULL if the symbolic link could not |
---|
| 767 | * be read. Storage for the result string is allocated in bufferPtr; the |
---|
| 768 | * caller must call Tcl_DStringFree() when the result is no longer |
---|
| 769 | * needed. |
---|
| 770 | * |
---|
| 771 | * Side effects: |
---|
| 772 | * See readlink() documentation. |
---|
| 773 | * |
---|
| 774 | *--------------------------------------------------------------------------- |
---|
| 775 | */ |
---|
| 776 | |
---|
| 777 | char * |
---|
| 778 | TclpReadlink( |
---|
| 779 | CONST char *path, /* Path of file to readlink (UTF-8). */ |
---|
| 780 | Tcl_DString *linkPtr) /* Uninitialized or free DString filled with |
---|
| 781 | * contents of link (UTF-8). */ |
---|
| 782 | { |
---|
| 783 | #ifndef DJGPP |
---|
| 784 | char link[MAXPATHLEN]; |
---|
| 785 | int length; |
---|
| 786 | CONST char *native; |
---|
| 787 | Tcl_DString ds; |
---|
| 788 | |
---|
| 789 | native = Tcl_UtfToExternalDString(NULL, path, -1, &ds); |
---|
| 790 | length = readlink(native, link, sizeof(link)); /* INTL: Native. */ |
---|
| 791 | Tcl_DStringFree(&ds); |
---|
| 792 | |
---|
| 793 | if (length < 0) { |
---|
| 794 | return NULL; |
---|
| 795 | } |
---|
| 796 | |
---|
| 797 | Tcl_ExternalToUtfDString(NULL, link, length, linkPtr); |
---|
| 798 | return Tcl_DStringValue(linkPtr); |
---|
| 799 | #else |
---|
| 800 | return NULL; |
---|
| 801 | #endif |
---|
| 802 | } |
---|
| 803 | |
---|
| 804 | /* |
---|
| 805 | *---------------------------------------------------------------------- |
---|
| 806 | * |
---|
| 807 | * TclpObjStat -- |
---|
| 808 | * |
---|
| 809 | * This function replaces the library version of stat(). |
---|
| 810 | * |
---|
| 811 | * Results: |
---|
| 812 | * See stat() documentation. |
---|
| 813 | * |
---|
| 814 | * Side effects: |
---|
| 815 | * See stat() documentation. |
---|
| 816 | * |
---|
| 817 | *---------------------------------------------------------------------- |
---|
| 818 | */ |
---|
| 819 | |
---|
| 820 | int |
---|
| 821 | TclpObjStat( |
---|
| 822 | Tcl_Obj *pathPtr, /* Path of file to stat */ |
---|
| 823 | Tcl_StatBuf *bufPtr) /* Filled with results of stat call. */ |
---|
| 824 | { |
---|
| 825 | CONST char *path = Tcl_FSGetNativePath(pathPtr); |
---|
| 826 | if (path == NULL) { |
---|
| 827 | return -1; |
---|
| 828 | } else { |
---|
| 829 | return TclOSstat(path, bufPtr); |
---|
| 830 | } |
---|
| 831 | } |
---|
| 832 | |
---|
| 833 | #ifdef S_IFLNK |
---|
| 834 | |
---|
| 835 | Tcl_Obj* |
---|
| 836 | TclpObjLink( |
---|
| 837 | Tcl_Obj *pathPtr, |
---|
| 838 | Tcl_Obj *toPtr, |
---|
| 839 | int linkAction) |
---|
| 840 | { |
---|
| 841 | if (toPtr != NULL) { |
---|
| 842 | CONST char *src = Tcl_FSGetNativePath(pathPtr); |
---|
| 843 | CONST char *target = NULL; |
---|
| 844 | |
---|
| 845 | if (src == NULL) { |
---|
| 846 | return NULL; |
---|
| 847 | } |
---|
| 848 | |
---|
| 849 | /* |
---|
| 850 | * If we're making a symbolic link and the path is relative, then we |
---|
| 851 | * must check whether it exists _relative_ to the directory in which |
---|
| 852 | * the src is found (not relative to the current cwd which is just not |
---|
| 853 | * relevant in this case). |
---|
| 854 | * |
---|
| 855 | * If we're making a hard link, then a relative path is just converted |
---|
| 856 | * to absolute relative to the cwd. |
---|
| 857 | */ |
---|
| 858 | |
---|
| 859 | if ((linkAction & TCL_CREATE_SYMBOLIC_LINK) |
---|
| 860 | && (Tcl_FSGetPathType(toPtr) == TCL_PATH_RELATIVE)) { |
---|
| 861 | Tcl_Obj *dirPtr, *absPtr; |
---|
| 862 | |
---|
| 863 | dirPtr = TclPathPart(NULL, pathPtr, TCL_PATH_DIRNAME); |
---|
| 864 | if (dirPtr == NULL) { |
---|
| 865 | return NULL; |
---|
| 866 | } |
---|
| 867 | absPtr = Tcl_FSJoinToPath(dirPtr, 1, &toPtr); |
---|
| 868 | Tcl_IncrRefCount(absPtr); |
---|
| 869 | if (Tcl_FSAccess(absPtr, F_OK) == -1) { |
---|
| 870 | Tcl_DecrRefCount(absPtr); |
---|
| 871 | Tcl_DecrRefCount(dirPtr); |
---|
| 872 | |
---|
| 873 | /* |
---|
| 874 | * Target doesn't exist. |
---|
| 875 | */ |
---|
| 876 | |
---|
| 877 | errno = ENOENT; |
---|
| 878 | return NULL; |
---|
| 879 | } |
---|
| 880 | |
---|
| 881 | /* |
---|
| 882 | * Target exists; we'll construct the relative path we want below. |
---|
| 883 | */ |
---|
| 884 | |
---|
| 885 | Tcl_DecrRefCount(absPtr); |
---|
| 886 | Tcl_DecrRefCount(dirPtr); |
---|
| 887 | } else { |
---|
| 888 | target = Tcl_FSGetNativePath(toPtr); |
---|
| 889 | if (target == NULL) { |
---|
| 890 | return NULL; |
---|
| 891 | } |
---|
| 892 | if (access(target, F_OK) == -1) { |
---|
| 893 | /* |
---|
| 894 | * Target doesn't exist. |
---|
| 895 | */ |
---|
| 896 | |
---|
| 897 | errno = ENOENT; |
---|
| 898 | return NULL; |
---|
| 899 | } |
---|
| 900 | } |
---|
| 901 | |
---|
| 902 | if (access(src, F_OK) != -1) { |
---|
| 903 | /* |
---|
| 904 | * Src exists. |
---|
| 905 | */ |
---|
| 906 | |
---|
| 907 | errno = EEXIST; |
---|
| 908 | return NULL; |
---|
| 909 | } |
---|
| 910 | |
---|
| 911 | /* |
---|
| 912 | * Check symbolic link flag first, since we prefer to create these. |
---|
| 913 | */ |
---|
| 914 | |
---|
| 915 | if (linkAction & TCL_CREATE_SYMBOLIC_LINK) { |
---|
| 916 | int targetLen; |
---|
| 917 | Tcl_DString ds; |
---|
| 918 | Tcl_Obj *transPtr; |
---|
| 919 | |
---|
| 920 | /* |
---|
| 921 | * Now we don't want to link to the absolute, normalized path. |
---|
| 922 | * Relative links are quite acceptable (but links to ~user are not |
---|
| 923 | * -- these must be expanded first). |
---|
| 924 | */ |
---|
| 925 | |
---|
| 926 | transPtr = Tcl_FSGetTranslatedPath(NULL, toPtr); |
---|
| 927 | if (transPtr == NULL) { |
---|
| 928 | return NULL; |
---|
| 929 | } |
---|
| 930 | target = Tcl_GetStringFromObj(transPtr, &targetLen); |
---|
| 931 | target = Tcl_UtfToExternalDString(NULL, target, targetLen, &ds); |
---|
| 932 | Tcl_DecrRefCount(transPtr); |
---|
| 933 | |
---|
| 934 | if (symlink(target, src) != 0) { |
---|
| 935 | toPtr = NULL; |
---|
| 936 | } |
---|
| 937 | Tcl_DStringFree(&ds); |
---|
| 938 | } else if (linkAction & TCL_CREATE_HARD_LINK) { |
---|
| 939 | if (link(target, src) != 0) { |
---|
| 940 | return NULL; |
---|
| 941 | } |
---|
| 942 | } else { |
---|
| 943 | errno = ENODEV; |
---|
| 944 | return NULL; |
---|
| 945 | } |
---|
| 946 | return toPtr; |
---|
| 947 | } else { |
---|
| 948 | Tcl_Obj *linkPtr = NULL; |
---|
| 949 | |
---|
| 950 | char link[MAXPATHLEN]; |
---|
| 951 | int length; |
---|
| 952 | Tcl_DString ds; |
---|
| 953 | Tcl_Obj *transPtr; |
---|
| 954 | |
---|
| 955 | transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); |
---|
| 956 | if (transPtr == NULL) { |
---|
| 957 | return NULL; |
---|
| 958 | } |
---|
| 959 | Tcl_DecrRefCount(transPtr); |
---|
| 960 | |
---|
| 961 | length = readlink(Tcl_FSGetNativePath(pathPtr), link, sizeof(link)); |
---|
| 962 | if (length < 0) { |
---|
| 963 | return NULL; |
---|
| 964 | } |
---|
| 965 | |
---|
| 966 | Tcl_ExternalToUtfDString(NULL, link, length, &ds); |
---|
| 967 | linkPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), |
---|
| 968 | Tcl_DStringLength(&ds)); |
---|
| 969 | Tcl_DStringFree(&ds); |
---|
| 970 | if (linkPtr != NULL) { |
---|
| 971 | Tcl_IncrRefCount(linkPtr); |
---|
| 972 | } |
---|
| 973 | return linkPtr; |
---|
| 974 | } |
---|
| 975 | } |
---|
| 976 | #endif /* S_IFLNK */ |
---|
| 977 | |
---|
| 978 | /* |
---|
| 979 | *--------------------------------------------------------------------------- |
---|
| 980 | * |
---|
| 981 | * TclpFilesystemPathType -- |
---|
| 982 | * |
---|
| 983 | * This function is part of the native filesystem support, and returns |
---|
| 984 | * the path type of the given path. Right now it simply returns NULL. In |
---|
| 985 | * the future it could return specific path types, like 'nfs', 'samba', |
---|
| 986 | * 'FAT32', etc. |
---|
| 987 | * |
---|
| 988 | * Results: |
---|
| 989 | * NULL at present. |
---|
| 990 | * |
---|
| 991 | * Side effects: |
---|
| 992 | * None. |
---|
| 993 | * |
---|
| 994 | *--------------------------------------------------------------------------- |
---|
| 995 | */ |
---|
| 996 | |
---|
| 997 | Tcl_Obj * |
---|
| 998 | TclpFilesystemPathType( |
---|
| 999 | Tcl_Obj *pathPtr) |
---|
| 1000 | { |
---|
| 1001 | /* |
---|
| 1002 | * All native paths are of the same type. |
---|
| 1003 | */ |
---|
| 1004 | |
---|
| 1005 | return NULL; |
---|
| 1006 | } |
---|
| 1007 | |
---|
| 1008 | /* |
---|
| 1009 | *--------------------------------------------------------------------------- |
---|
| 1010 | * |
---|
| 1011 | * TclpNativeToNormalized -- |
---|
| 1012 | * |
---|
| 1013 | * Convert native format to a normalized path object, with refCount of |
---|
| 1014 | * zero. |
---|
| 1015 | * |
---|
| 1016 | * Currently assumes all native paths are actually normalized already, so |
---|
| 1017 | * if the path given is not normalized this will actually just convert to |
---|
| 1018 | * a valid string path, but not necessarily a normalized one. |
---|
| 1019 | * |
---|
| 1020 | * Results: |
---|
| 1021 | * A valid normalized path. |
---|
| 1022 | * |
---|
| 1023 | * Side effects: |
---|
| 1024 | * None. |
---|
| 1025 | * |
---|
| 1026 | *--------------------------------------------------------------------------- |
---|
| 1027 | */ |
---|
| 1028 | |
---|
| 1029 | Tcl_Obj * |
---|
| 1030 | TclpNativeToNormalized( |
---|
| 1031 | ClientData clientData) |
---|
| 1032 | { |
---|
| 1033 | Tcl_DString ds; |
---|
| 1034 | Tcl_Obj *objPtr; |
---|
| 1035 | int len; |
---|
| 1036 | |
---|
| 1037 | CONST char *copy; |
---|
| 1038 | Tcl_ExternalToUtfDString(NULL, (CONST char*)clientData, -1, &ds); |
---|
| 1039 | |
---|
| 1040 | copy = Tcl_DStringValue(&ds); |
---|
| 1041 | len = Tcl_DStringLength(&ds); |
---|
| 1042 | |
---|
| 1043 | objPtr = Tcl_NewStringObj(copy,len); |
---|
| 1044 | Tcl_DStringFree(&ds); |
---|
| 1045 | |
---|
| 1046 | return objPtr; |
---|
| 1047 | } |
---|
| 1048 | |
---|
| 1049 | /* |
---|
| 1050 | *--------------------------------------------------------------------------- |
---|
| 1051 | * |
---|
| 1052 | * TclNativeCreateNativeRep -- |
---|
| 1053 | * |
---|
| 1054 | * Create a native representation for the given path. |
---|
| 1055 | * |
---|
| 1056 | * Results: |
---|
| 1057 | * The nativePath representation. |
---|
| 1058 | * |
---|
| 1059 | * Side effects: |
---|
| 1060 | * Memory will be allocated. The path may need to be normalized. |
---|
| 1061 | * |
---|
| 1062 | *--------------------------------------------------------------------------- |
---|
| 1063 | */ |
---|
| 1064 | |
---|
| 1065 | ClientData |
---|
| 1066 | TclNativeCreateNativeRep( |
---|
| 1067 | Tcl_Obj *pathPtr) |
---|
| 1068 | { |
---|
| 1069 | char *nativePathPtr; |
---|
| 1070 | Tcl_DString ds; |
---|
| 1071 | Tcl_Obj *validPathPtr; |
---|
| 1072 | int len; |
---|
| 1073 | char *str; |
---|
| 1074 | |
---|
| 1075 | if (TclFSCwdIsNative()) { |
---|
| 1076 | /* |
---|
| 1077 | * The cwd is native, which means we can use the translated path |
---|
| 1078 | * without worrying about normalization (this will also usually be |
---|
| 1079 | * shorter so the utf-to-external conversion will be somewhat faster). |
---|
| 1080 | */ |
---|
| 1081 | |
---|
| 1082 | validPathPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); |
---|
| 1083 | if (validPathPtr == NULL) { |
---|
| 1084 | return NULL; |
---|
| 1085 | } |
---|
| 1086 | } else { |
---|
| 1087 | /* |
---|
| 1088 | * Make sure the normalized path is set. |
---|
| 1089 | */ |
---|
| 1090 | |
---|
| 1091 | validPathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr); |
---|
| 1092 | if (validPathPtr == NULL) { |
---|
| 1093 | return NULL; |
---|
| 1094 | } |
---|
| 1095 | Tcl_IncrRefCount(validPathPtr); |
---|
| 1096 | } |
---|
| 1097 | |
---|
| 1098 | str = Tcl_GetStringFromObj(validPathPtr, &len); |
---|
| 1099 | Tcl_UtfToExternalDString(NULL, str, len, &ds); |
---|
| 1100 | len = Tcl_DStringLength(&ds) + sizeof(char); |
---|
| 1101 | Tcl_DecrRefCount(validPathPtr); |
---|
| 1102 | nativePathPtr = ckalloc((unsigned) len); |
---|
| 1103 | memcpy((void*)nativePathPtr, (void*)Tcl_DStringValue(&ds), (size_t) len); |
---|
| 1104 | |
---|
| 1105 | Tcl_DStringFree(&ds); |
---|
| 1106 | return (ClientData)nativePathPtr; |
---|
| 1107 | } |
---|
| 1108 | |
---|
| 1109 | /* |
---|
| 1110 | *--------------------------------------------------------------------------- |
---|
| 1111 | * |
---|
| 1112 | * TclNativeDupInternalRep -- |
---|
| 1113 | * |
---|
| 1114 | * Duplicate the native representation. |
---|
| 1115 | * |
---|
| 1116 | * Results: |
---|
| 1117 | * The copied native representation, or NULL if it is not possible to |
---|
| 1118 | * copy the representation. |
---|
| 1119 | * |
---|
| 1120 | * Side effects: |
---|
| 1121 | * Memory will be allocated for the copy. |
---|
| 1122 | * |
---|
| 1123 | *--------------------------------------------------------------------------- |
---|
| 1124 | */ |
---|
| 1125 | |
---|
| 1126 | ClientData |
---|
| 1127 | TclNativeDupInternalRep( |
---|
| 1128 | ClientData clientData) |
---|
| 1129 | { |
---|
| 1130 | char *copy; |
---|
| 1131 | size_t len; |
---|
| 1132 | |
---|
| 1133 | if (clientData == NULL) { |
---|
| 1134 | return NULL; |
---|
| 1135 | } |
---|
| 1136 | |
---|
| 1137 | /* |
---|
| 1138 | * ASCII representation when running on Unix. |
---|
| 1139 | */ |
---|
| 1140 | |
---|
| 1141 | len = sizeof(char) + (strlen((CONST char*) clientData) * sizeof(char)); |
---|
| 1142 | |
---|
| 1143 | copy = (char *) ckalloc(len); |
---|
| 1144 | memcpy((void *) copy, (void *) clientData, len); |
---|
| 1145 | return (ClientData)copy; |
---|
| 1146 | } |
---|
| 1147 | |
---|
| 1148 | /* |
---|
| 1149 | *--------------------------------------------------------------------------- |
---|
| 1150 | * |
---|
| 1151 | * TclpUtime -- |
---|
| 1152 | * |
---|
| 1153 | * Set the modification date for a file. |
---|
| 1154 | * |
---|
| 1155 | * Results: |
---|
| 1156 | * 0 on success, -1 on error. |
---|
| 1157 | * |
---|
| 1158 | * Side effects: |
---|
| 1159 | * None. |
---|
| 1160 | * |
---|
| 1161 | *--------------------------------------------------------------------------- |
---|
| 1162 | */ |
---|
| 1163 | |
---|
| 1164 | int |
---|
| 1165 | TclpUtime( |
---|
| 1166 | Tcl_Obj *pathPtr, /* File to modify */ |
---|
| 1167 | struct utimbuf *tval) /* New modification date structure */ |
---|
| 1168 | { |
---|
| 1169 | return utime(Tcl_FSGetNativePath(pathPtr), tval); |
---|
| 1170 | } |
---|
| 1171 | |
---|
| 1172 | /* |
---|
| 1173 | * Local Variables: |
---|
| 1174 | * mode: c |
---|
| 1175 | * c-basic-offset: 4 |
---|
| 1176 | * fill-column: 78 |
---|
| 1177 | * End: |
---|
| 1178 | */ |
---|