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 | */ |
---|