1 | /* |
---|
2 | * tclMacOSXFCmd.c |
---|
3 | * |
---|
4 | * This file implements the MacOSX specific portion of file manipulation |
---|
5 | * subcommands of the "file" command. |
---|
6 | * |
---|
7 | * Copyright (c) 2003-2007 Daniel A. Steffen <das@users.sourceforge.net> |
---|
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: tclMacOSXFCmd.c,v 1.12 2007/04/23 20:46:14 das Exp $ |
---|
13 | */ |
---|
14 | |
---|
15 | #include "tclInt.h" |
---|
16 | |
---|
17 | #ifdef HAVE_GETATTRLIST |
---|
18 | #include <sys/attr.h> |
---|
19 | #include <sys/paths.h> |
---|
20 | #include <libkern/OSByteOrder.h> |
---|
21 | #endif |
---|
22 | |
---|
23 | /* Darwin 8 copyfile API. */ |
---|
24 | #ifdef HAVE_COPYFILE |
---|
25 | #ifdef HAVE_COPYFILE_H |
---|
26 | #include <copyfile.h> |
---|
27 | #if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 |
---|
28 | /* Support for weakly importing copyfile. */ |
---|
29 | #define WEAK_IMPORT_COPYFILE |
---|
30 | extern int copyfile(const char *from, const char *to, copyfile_state_t state, |
---|
31 | copyfile_flags_t flags) WEAK_IMPORT_ATTRIBUTE; |
---|
32 | #endif /* HAVE_WEAK_IMPORT */ |
---|
33 | #else /* HAVE_COPYFILE_H */ |
---|
34 | int copyfile(const char *from, const char *to, void *state, uint32_t flags); |
---|
35 | #define COPYFILE_ACL (1<<0) |
---|
36 | #define COPYFILE_XATTR (1<<2) |
---|
37 | #define COPYFILE_NOFOLLOW_SRC (1<<18) |
---|
38 | #if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 |
---|
39 | /* Support for weakly importing copyfile. */ |
---|
40 | #define WEAK_IMPORT_COPYFILE |
---|
41 | extern int copyfile(const char *from, const char *to, void *state, |
---|
42 | uint32_t flags) WEAK_IMPORT_ATTRIBUTE; |
---|
43 | #endif /* HAVE_WEAK_IMPORT */ |
---|
44 | #endif /* HAVE_COPYFILE_H */ |
---|
45 | #endif /* HAVE_COPYFILE */ |
---|
46 | |
---|
47 | #include <libkern/OSByteOrder.h> |
---|
48 | |
---|
49 | /* |
---|
50 | * Constants for file attributes subcommand. Need to be kept in sync with |
---|
51 | * tclUnixFCmd.c ! |
---|
52 | */ |
---|
53 | |
---|
54 | enum { |
---|
55 | UNIX_GROUP_ATTRIBUTE, |
---|
56 | UNIX_OWNER_ATTRIBUTE, |
---|
57 | UNIX_PERMISSIONS_ATTRIBUTE, |
---|
58 | #ifdef HAVE_CHFLAGS |
---|
59 | UNIX_READONLY_ATTRIBUTE, |
---|
60 | #endif |
---|
61 | #ifdef MAC_OSX_TCL |
---|
62 | MACOSX_CREATOR_ATTRIBUTE, |
---|
63 | MACOSX_TYPE_ATTRIBUTE, |
---|
64 | MACOSX_HIDDEN_ATTRIBUTE, |
---|
65 | MACOSX_RSRCLENGTH_ATTRIBUTE, |
---|
66 | #endif |
---|
67 | }; |
---|
68 | |
---|
69 | typedef u_int32_t OSType; |
---|
70 | |
---|
71 | static int GetOSTypeFromObj(Tcl_Interp *interp, |
---|
72 | Tcl_Obj *objPtr, OSType *osTypePtr); |
---|
73 | static Tcl_Obj * NewOSTypeObj(const OSType newOSType); |
---|
74 | static int SetOSTypeFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); |
---|
75 | static void UpdateStringOfOSType(Tcl_Obj *objPtr); |
---|
76 | |
---|
77 | static Tcl_ObjType tclOSTypeType = { |
---|
78 | "osType", /* name */ |
---|
79 | NULL, /* freeIntRepProc */ |
---|
80 | NULL, /* dupIntRepProc */ |
---|
81 | UpdateStringOfOSType, /* updateStringProc */ |
---|
82 | SetOSTypeFromAny /* setFromAnyProc */ |
---|
83 | }; |
---|
84 | |
---|
85 | enum { |
---|
86 | kIsInvisible = 0x4000, |
---|
87 | }; |
---|
88 | |
---|
89 | #define kFinfoIsInvisible (OSSwapHostToBigConstInt16(kIsInvisible)) |
---|
90 | |
---|
91 | typedef struct finderinfo { |
---|
92 | u_int32_t type; |
---|
93 | u_int32_t creator; |
---|
94 | u_int16_t fdFlags; |
---|
95 | u_int32_t location; |
---|
96 | u_int16_t reserved; |
---|
97 | u_int32_t extendedFileInfo[4]; |
---|
98 | } __attribute__ ((__packed__)) finderinfo; |
---|
99 | |
---|
100 | typedef struct fileinfobuf { |
---|
101 | u_int32_t info_length; |
---|
102 | u_int32_t data[8]; |
---|
103 | } fileinfobuf; |
---|
104 | |
---|
105 | /* |
---|
106 | *---------------------------------------------------------------------- |
---|
107 | * |
---|
108 | * TclMacOSXGetFileAttribute |
---|
109 | * |
---|
110 | * Gets a MacOSX attribute of a file. Which attribute is controlled by |
---|
111 | * objIndex. The object will have ref count 0. |
---|
112 | * |
---|
113 | * Results: |
---|
114 | * Standard TCL result. Returns a new Tcl_Obj in attributePtrPtr if there |
---|
115 | * is no error. |
---|
116 | * |
---|
117 | * Side effects: |
---|
118 | * A new object is allocated. |
---|
119 | * |
---|
120 | *---------------------------------------------------------------------- |
---|
121 | */ |
---|
122 | |
---|
123 | int |
---|
124 | TclMacOSXGetFileAttribute( |
---|
125 | Tcl_Interp *interp, /* The interp we are using for errors. */ |
---|
126 | int objIndex, /* The index of the attribute. */ |
---|
127 | Tcl_Obj *fileName, /* The name of the file (UTF-8). */ |
---|
128 | Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ |
---|
129 | { |
---|
130 | #ifdef HAVE_GETATTRLIST |
---|
131 | int result; |
---|
132 | Tcl_StatBuf statBuf; |
---|
133 | struct attrlist alist; |
---|
134 | fileinfobuf finfo; |
---|
135 | finderinfo *finder = (finderinfo*)(&finfo.data); |
---|
136 | off_t *rsrcForkSize = (off_t*)(&finfo.data); |
---|
137 | const char *native; |
---|
138 | |
---|
139 | result = TclpObjStat(fileName, &statBuf); |
---|
140 | |
---|
141 | if (result != 0) { |
---|
142 | Tcl_AppendResult(interp, "could not read \"", |
---|
143 | TclGetString(fileName), "\": ", Tcl_PosixError(interp), NULL); |
---|
144 | return TCL_ERROR; |
---|
145 | } |
---|
146 | |
---|
147 | if (S_ISDIR(statBuf.st_mode) && objIndex != MACOSX_HIDDEN_ATTRIBUTE) { |
---|
148 | /* |
---|
149 | * Directories only support attribute "-hidden". |
---|
150 | */ |
---|
151 | |
---|
152 | errno = EISDIR; |
---|
153 | Tcl_AppendResult(interp, "invalid attribute: ", |
---|
154 | Tcl_PosixError(interp), NULL); |
---|
155 | return TCL_ERROR; |
---|
156 | } |
---|
157 | |
---|
158 | bzero(&alist, sizeof(struct attrlist)); |
---|
159 | alist.bitmapcount = ATTR_BIT_MAP_COUNT; |
---|
160 | if (objIndex == MACOSX_RSRCLENGTH_ATTRIBUTE) { |
---|
161 | alist.fileattr = ATTR_FILE_RSRCLENGTH; |
---|
162 | } else { |
---|
163 | alist.commonattr = ATTR_CMN_FNDRINFO; |
---|
164 | } |
---|
165 | native = Tcl_FSGetNativePath(fileName); |
---|
166 | result = getattrlist(native, &alist, &finfo, sizeof(fileinfobuf), 0); |
---|
167 | |
---|
168 | if (result != 0) { |
---|
169 | Tcl_AppendResult(interp, "could not read attributes of \"", |
---|
170 | TclGetString(fileName), "\": ", Tcl_PosixError(interp), NULL); |
---|
171 | return TCL_ERROR; |
---|
172 | } |
---|
173 | |
---|
174 | switch (objIndex) { |
---|
175 | case MACOSX_CREATOR_ATTRIBUTE: |
---|
176 | *attributePtrPtr = NewOSTypeObj( |
---|
177 | OSSwapBigToHostInt32(finder->creator)); |
---|
178 | break; |
---|
179 | case MACOSX_TYPE_ATTRIBUTE: |
---|
180 | *attributePtrPtr = NewOSTypeObj( |
---|
181 | OSSwapBigToHostInt32(finder->type)); |
---|
182 | break; |
---|
183 | case MACOSX_HIDDEN_ATTRIBUTE: |
---|
184 | *attributePtrPtr = Tcl_NewBooleanObj( |
---|
185 | (finder->fdFlags & kFinfoIsInvisible) != 0); |
---|
186 | break; |
---|
187 | case MACOSX_RSRCLENGTH_ATTRIBUTE: |
---|
188 | *attributePtrPtr = Tcl_NewWideIntObj(*rsrcForkSize); |
---|
189 | break; |
---|
190 | } |
---|
191 | return TCL_OK; |
---|
192 | #else |
---|
193 | Tcl_AppendResult(interp, "Mac OS X file attributes not supported", NULL); |
---|
194 | return TCL_ERROR; |
---|
195 | #endif |
---|
196 | } |
---|
197 | |
---|
198 | /* |
---|
199 | *--------------------------------------------------------------------------- |
---|
200 | * |
---|
201 | * TclMacOSXSetFileAttribute -- |
---|
202 | * |
---|
203 | * Sets a MacOSX attribute of a file. Which attribute is controlled by |
---|
204 | * objIndex. |
---|
205 | * |
---|
206 | * Results: |
---|
207 | * Standard TCL result. |
---|
208 | * |
---|
209 | * Side effects: |
---|
210 | * As above. |
---|
211 | * |
---|
212 | *--------------------------------------------------------------------------- |
---|
213 | */ |
---|
214 | |
---|
215 | int |
---|
216 | TclMacOSXSetFileAttribute( |
---|
217 | Tcl_Interp *interp, /* The interp for error reporting. */ |
---|
218 | int objIndex, /* The index of the attribute. */ |
---|
219 | Tcl_Obj *fileName, /* The name of the file (UTF-8). */ |
---|
220 | Tcl_Obj *attributePtr) /* New owner for file. */ |
---|
221 | { |
---|
222 | #ifdef HAVE_GETATTRLIST |
---|
223 | int result; |
---|
224 | Tcl_StatBuf statBuf; |
---|
225 | struct attrlist alist; |
---|
226 | fileinfobuf finfo; |
---|
227 | finderinfo *finder = (finderinfo*)(&finfo.data); |
---|
228 | off_t *rsrcForkSize = (off_t*)(&finfo.data); |
---|
229 | const char *native; |
---|
230 | |
---|
231 | result = TclpObjStat(fileName, &statBuf); |
---|
232 | |
---|
233 | if (result != 0) { |
---|
234 | Tcl_AppendResult(interp, "could not read \"", |
---|
235 | TclGetString(fileName), "\": ", Tcl_PosixError(interp), NULL); |
---|
236 | return TCL_ERROR; |
---|
237 | } |
---|
238 | |
---|
239 | if (S_ISDIR(statBuf.st_mode) && objIndex != MACOSX_HIDDEN_ATTRIBUTE) { |
---|
240 | /* |
---|
241 | * Directories only support attribute "-hidden". |
---|
242 | */ |
---|
243 | |
---|
244 | errno = EISDIR; |
---|
245 | Tcl_AppendResult(interp, "invalid attribute: ", |
---|
246 | Tcl_PosixError(interp), NULL); |
---|
247 | return TCL_ERROR; |
---|
248 | } |
---|
249 | |
---|
250 | bzero(&alist, sizeof(struct attrlist)); |
---|
251 | alist.bitmapcount = ATTR_BIT_MAP_COUNT; |
---|
252 | if (objIndex == MACOSX_RSRCLENGTH_ATTRIBUTE) { |
---|
253 | alist.fileattr = ATTR_FILE_RSRCLENGTH; |
---|
254 | } else { |
---|
255 | alist.commonattr = ATTR_CMN_FNDRINFO; |
---|
256 | } |
---|
257 | native = Tcl_FSGetNativePath(fileName); |
---|
258 | result = getattrlist(native, &alist, &finfo, sizeof(fileinfobuf), 0); |
---|
259 | |
---|
260 | if (result != 0) { |
---|
261 | Tcl_AppendResult(interp, "could not read attributes of \"", |
---|
262 | TclGetString(fileName), "\": ", Tcl_PosixError(interp), NULL); |
---|
263 | return TCL_ERROR; |
---|
264 | } |
---|
265 | |
---|
266 | if (objIndex != MACOSX_RSRCLENGTH_ATTRIBUTE) { |
---|
267 | OSType t; |
---|
268 | int h; |
---|
269 | |
---|
270 | switch (objIndex) { |
---|
271 | case MACOSX_CREATOR_ATTRIBUTE: |
---|
272 | if (GetOSTypeFromObj(interp, attributePtr, &t) != TCL_OK) { |
---|
273 | return TCL_ERROR; |
---|
274 | } |
---|
275 | finder->creator = OSSwapHostToBigInt32(t); |
---|
276 | break; |
---|
277 | case MACOSX_TYPE_ATTRIBUTE: |
---|
278 | if (GetOSTypeFromObj(interp, attributePtr, &t) != TCL_OK) { |
---|
279 | return TCL_ERROR; |
---|
280 | } |
---|
281 | finder->type = OSSwapHostToBigInt32(t); |
---|
282 | break; |
---|
283 | case MACOSX_HIDDEN_ATTRIBUTE: |
---|
284 | if (Tcl_GetBooleanFromObj(interp, attributePtr, &h) != TCL_OK) { |
---|
285 | return TCL_ERROR; |
---|
286 | } |
---|
287 | if (h) { |
---|
288 | finder->fdFlags |= kFinfoIsInvisible; |
---|
289 | } else { |
---|
290 | finder->fdFlags &= ~kFinfoIsInvisible; |
---|
291 | } |
---|
292 | break; |
---|
293 | } |
---|
294 | |
---|
295 | result = setattrlist(native, &alist, |
---|
296 | &finfo.data, sizeof(finfo.data), 0); |
---|
297 | |
---|
298 | if (result != 0) { |
---|
299 | Tcl_AppendResult(interp, "could not set attributes of \"", |
---|
300 | TclGetString(fileName), "\": ", |
---|
301 | Tcl_PosixError(interp), NULL); |
---|
302 | return TCL_ERROR; |
---|
303 | } |
---|
304 | } else { |
---|
305 | Tcl_WideInt newRsrcForkSize; |
---|
306 | |
---|
307 | if (Tcl_GetWideIntFromObj(interp, attributePtr, |
---|
308 | &newRsrcForkSize) != TCL_OK) { |
---|
309 | return TCL_ERROR; |
---|
310 | } |
---|
311 | |
---|
312 | if (newRsrcForkSize != *rsrcForkSize) { |
---|
313 | Tcl_DString ds; |
---|
314 | |
---|
315 | /* |
---|
316 | * Only setting rsrclength to 0 to strip a file's resource fork is |
---|
317 | * supported. |
---|
318 | */ |
---|
319 | |
---|
320 | if(newRsrcForkSize != 0) { |
---|
321 | Tcl_AppendResult(interp, |
---|
322 | "setting nonzero rsrclength not supported", NULL); |
---|
323 | return TCL_ERROR; |
---|
324 | } |
---|
325 | |
---|
326 | /* |
---|
327 | * Construct path to resource fork. |
---|
328 | */ |
---|
329 | |
---|
330 | Tcl_DStringInit(&ds); |
---|
331 | Tcl_DStringAppend(&ds, native, -1); |
---|
332 | Tcl_DStringAppend(&ds, _PATH_RSRCFORKSPEC, -1); |
---|
333 | |
---|
334 | result = truncate(Tcl_DStringValue(&ds), (off_t)0); |
---|
335 | if (result != 0) { |
---|
336 | /* |
---|
337 | * truncate() on a valid resource fork path may fail with |
---|
338 | * a permission error in some OS releases, try truncating |
---|
339 | * with open() instead: |
---|
340 | */ |
---|
341 | int fd = open(Tcl_DStringValue(&ds), O_WRONLY | O_TRUNC); |
---|
342 | if (fd > 0) { |
---|
343 | result = close(fd); |
---|
344 | } |
---|
345 | } |
---|
346 | |
---|
347 | Tcl_DStringFree(&ds); |
---|
348 | |
---|
349 | if (result != 0) { |
---|
350 | Tcl_AppendResult(interp, |
---|
351 | "could not truncate resource fork of \"", |
---|
352 | TclGetString(fileName), "\": ", |
---|
353 | Tcl_PosixError(interp), NULL); |
---|
354 | return TCL_ERROR; |
---|
355 | } |
---|
356 | } |
---|
357 | } |
---|
358 | return TCL_OK; |
---|
359 | #else |
---|
360 | Tcl_AppendResult(interp, "Mac OS X file attributes not supported", NULL); |
---|
361 | return TCL_ERROR; |
---|
362 | #endif |
---|
363 | } |
---|
364 | |
---|
365 | /* |
---|
366 | *--------------------------------------------------------------------------- |
---|
367 | * |
---|
368 | * TclMacOSXCopyFileAttributes -- |
---|
369 | * |
---|
370 | * Copy the MacOSX attributes and resource fork (if present) from one |
---|
371 | * file to another. |
---|
372 | * |
---|
373 | * Results: |
---|
374 | * Standard Tcl result. |
---|
375 | * |
---|
376 | * Side effects: |
---|
377 | * MacOSX attributes and resource fork are updated in the new file to |
---|
378 | * reflect the old file. |
---|
379 | * |
---|
380 | *--------------------------------------------------------------------------- |
---|
381 | */ |
---|
382 | |
---|
383 | int |
---|
384 | TclMacOSXCopyFileAttributes( |
---|
385 | CONST char *src, /* Path name of source file (native). */ |
---|
386 | CONST char *dst, /* Path name of target file (native). */ |
---|
387 | CONST Tcl_StatBuf *statBufPtr) |
---|
388 | /* Stat info for source file */ |
---|
389 | { |
---|
390 | #ifdef WEAK_IMPORT_COPYFILE |
---|
391 | if (copyfile != NULL) { |
---|
392 | #endif |
---|
393 | #ifdef HAVE_COPYFILE |
---|
394 | if (copyfile(src, dst, NULL, COPYFILE_XATTR | |
---|
395 | (S_ISLNK(statBufPtr->st_mode) ? COPYFILE_NOFOLLOW_SRC : |
---|
396 | COPYFILE_ACL)) < 0) { |
---|
397 | return TCL_ERROR; |
---|
398 | } |
---|
399 | return TCL_OK; |
---|
400 | #endif /* HAVE_COPYFILE */ |
---|
401 | #ifdef WEAK_IMPORT_COPYFILE |
---|
402 | } else { |
---|
403 | #endif |
---|
404 | #if !defined(HAVE_COPYFILE) || defined(WEAK_IMPORT_COPYFILE) |
---|
405 | #ifdef HAVE_GETATTRLIST |
---|
406 | struct attrlist alist; |
---|
407 | fileinfobuf finfo; |
---|
408 | off_t *rsrcForkSize = (off_t*)(&finfo.data); |
---|
409 | |
---|
410 | bzero(&alist, sizeof(struct attrlist)); |
---|
411 | alist.bitmapcount = ATTR_BIT_MAP_COUNT; |
---|
412 | alist.commonattr = ATTR_CMN_FNDRINFO; |
---|
413 | |
---|
414 | if (getattrlist(src, &alist, &finfo, sizeof(fileinfobuf), 0)) { |
---|
415 | return TCL_ERROR; |
---|
416 | } |
---|
417 | |
---|
418 | if (setattrlist(dst, &alist, &finfo.data, sizeof(finfo.data), 0)) { |
---|
419 | return TCL_ERROR; |
---|
420 | } |
---|
421 | |
---|
422 | if (!S_ISDIR(statBufPtr->st_mode)) { |
---|
423 | /* |
---|
424 | * Only copy non-empty resource fork. |
---|
425 | */ |
---|
426 | |
---|
427 | alist.commonattr = 0; |
---|
428 | alist.fileattr = ATTR_FILE_RSRCLENGTH; |
---|
429 | |
---|
430 | if (getattrlist(src, &alist, &finfo, sizeof(fileinfobuf), 0)) { |
---|
431 | return TCL_ERROR; |
---|
432 | } |
---|
433 | |
---|
434 | if(*rsrcForkSize > 0) { |
---|
435 | int result; |
---|
436 | Tcl_DString ds_src, ds_dst; |
---|
437 | |
---|
438 | /* |
---|
439 | * Construct paths to resource forks. |
---|
440 | */ |
---|
441 | |
---|
442 | Tcl_DStringInit(&ds_src); |
---|
443 | Tcl_DStringAppend(&ds_src, src, -1); |
---|
444 | Tcl_DStringAppend(&ds_src, _PATH_RSRCFORKSPEC, -1); |
---|
445 | Tcl_DStringInit(&ds_dst); |
---|
446 | Tcl_DStringAppend(&ds_dst, dst, -1); |
---|
447 | Tcl_DStringAppend(&ds_dst, _PATH_RSRCFORKSPEC, -1); |
---|
448 | |
---|
449 | result = TclUnixCopyFile(Tcl_DStringValue(&ds_src), |
---|
450 | Tcl_DStringValue(&ds_dst), statBufPtr, 1); |
---|
451 | |
---|
452 | Tcl_DStringFree(&ds_src); |
---|
453 | Tcl_DStringFree(&ds_dst); |
---|
454 | |
---|
455 | if (result != 0) { |
---|
456 | return TCL_ERROR; |
---|
457 | } |
---|
458 | } |
---|
459 | } |
---|
460 | return TCL_OK; |
---|
461 | #else |
---|
462 | return TCL_ERROR; |
---|
463 | #endif /* HAVE_GETATTRLIST */ |
---|
464 | #endif /* !defined(HAVE_COPYFILE) || defined(WEAK_IMPORT_COPYFILE) */ |
---|
465 | #ifdef WEAK_IMPORT_COPYFILE |
---|
466 | } |
---|
467 | #endif |
---|
468 | } |
---|
469 | |
---|
470 | /* |
---|
471 | *---------------------------------------------------------------------- |
---|
472 | * |
---|
473 | * TclMacOSXMatchType -- |
---|
474 | * |
---|
475 | * This routine is used by the globbing code to check if a file |
---|
476 | * matches a given mac type and/or creator code. |
---|
477 | * |
---|
478 | * Results: |
---|
479 | * The return value is 1, 0 or -1 indicating whether the file |
---|
480 | * matches the given criteria, does not match them, or an error |
---|
481 | * occurred (in wich case an error is left in interp). |
---|
482 | * |
---|
483 | * Side effects: |
---|
484 | * None. |
---|
485 | * |
---|
486 | *---------------------------------------------------------------------- |
---|
487 | */ |
---|
488 | |
---|
489 | int |
---|
490 | TclMacOSXMatchType( |
---|
491 | Tcl_Interp *interp, /* Interpreter to receive errors. */ |
---|
492 | CONST char *pathName, /* Native path to check. */ |
---|
493 | CONST char *fileName, /* Native filename to check. */ |
---|
494 | Tcl_StatBuf *statBufPtr, /* Stat info for file to check */ |
---|
495 | Tcl_GlobTypeData *types) /* Type description to match against. */ |
---|
496 | { |
---|
497 | #ifdef HAVE_GETATTRLIST |
---|
498 | struct attrlist alist; |
---|
499 | fileinfobuf finfo; |
---|
500 | finderinfo *finder = (finderinfo*)(&finfo.data); |
---|
501 | OSType osType; |
---|
502 | |
---|
503 | bzero(&alist, sizeof(struct attrlist)); |
---|
504 | alist.bitmapcount = ATTR_BIT_MAP_COUNT; |
---|
505 | alist.commonattr = ATTR_CMN_FNDRINFO; |
---|
506 | if (getattrlist(pathName, &alist, &finfo, sizeof(fileinfobuf), 0) != 0) { |
---|
507 | return 0; |
---|
508 | } |
---|
509 | if ((types->perm & TCL_GLOB_PERM_HIDDEN) && |
---|
510 | !((finder->fdFlags & kFinfoIsInvisible) || (*fileName == '.'))) { |
---|
511 | return 0; |
---|
512 | } |
---|
513 | if (S_ISDIR(statBufPtr->st_mode) && (types->macType || types->macCreator)) { |
---|
514 | /* Directories don't support types or creators */ |
---|
515 | return 0; |
---|
516 | } |
---|
517 | if (types->macType) { |
---|
518 | if (GetOSTypeFromObj(interp, types->macType, &osType) != TCL_OK) { |
---|
519 | return -1; |
---|
520 | } |
---|
521 | if (osType != OSSwapBigToHostInt32(finder->type)) { |
---|
522 | return 0; |
---|
523 | } |
---|
524 | } |
---|
525 | if (types->macCreator) { |
---|
526 | if (GetOSTypeFromObj(interp, types->macCreator, &osType) != TCL_OK) { |
---|
527 | return -1; |
---|
528 | } |
---|
529 | if (osType != OSSwapBigToHostInt32(finder->creator)) { |
---|
530 | return 0; |
---|
531 | } |
---|
532 | } |
---|
533 | #endif |
---|
534 | return 1; |
---|
535 | } |
---|
536 | |
---|
537 | /* |
---|
538 | *---------------------------------------------------------------------- |
---|
539 | * |
---|
540 | * GetOSTypeFromObj -- |
---|
541 | * |
---|
542 | * Attempt to return an OSType from the Tcl object "objPtr". |
---|
543 | * |
---|
544 | * Results: |
---|
545 | * Standard TCL result. If an error occurs during conversion, an error |
---|
546 | * message is left in interp->objResult. |
---|
547 | * |
---|
548 | * Side effects: |
---|
549 | * The string representation of objPtr will be updated if necessary. |
---|
550 | * |
---|
551 | *---------------------------------------------------------------------- |
---|
552 | */ |
---|
553 | |
---|
554 | static int |
---|
555 | GetOSTypeFromObj( |
---|
556 | Tcl_Interp *interp, /* Used for error reporting if not NULL. */ |
---|
557 | Tcl_Obj *objPtr, /* The object from which to get an OSType. */ |
---|
558 | OSType *osTypePtr) /* Place to store resulting OSType. */ |
---|
559 | { |
---|
560 | int result = TCL_OK; |
---|
561 | |
---|
562 | if (objPtr->typePtr != &tclOSTypeType) { |
---|
563 | result = tclOSTypeType.setFromAnyProc(interp, objPtr); |
---|
564 | }; |
---|
565 | *osTypePtr = (OSType) objPtr->internalRep.longValue; |
---|
566 | return result; |
---|
567 | } |
---|
568 | |
---|
569 | /* |
---|
570 | *---------------------------------------------------------------------- |
---|
571 | * |
---|
572 | * NewOSTypeObj -- |
---|
573 | * |
---|
574 | * Create a new OSType object. |
---|
575 | * |
---|
576 | * Results: |
---|
577 | * The newly created OSType object is returned, it has ref count 0. |
---|
578 | * |
---|
579 | * Side effects: |
---|
580 | * None. |
---|
581 | * |
---|
582 | *---------------------------------------------------------------------- |
---|
583 | */ |
---|
584 | |
---|
585 | static Tcl_Obj * |
---|
586 | NewOSTypeObj( |
---|
587 | const OSType osType) /* OSType used to initialize the new object. */ |
---|
588 | { |
---|
589 | Tcl_Obj *objPtr; |
---|
590 | |
---|
591 | TclNewObj(objPtr); |
---|
592 | Tcl_InvalidateStringRep(objPtr); |
---|
593 | objPtr->internalRep.longValue = (long) osType; |
---|
594 | objPtr->typePtr = &tclOSTypeType; |
---|
595 | return objPtr; |
---|
596 | } |
---|
597 | |
---|
598 | /* |
---|
599 | *---------------------------------------------------------------------- |
---|
600 | * |
---|
601 | * SetOSTypeFromAny -- |
---|
602 | * |
---|
603 | * Attempts to force the internal representation for a Tcl object to |
---|
604 | * tclOSTypeType, specifically. |
---|
605 | * |
---|
606 | * Results: |
---|
607 | * The return value is a standard object Tcl result. If an error occurs |
---|
608 | * during conversion, an error message is left in the interpreter's |
---|
609 | * result unless "interp" is NULL. |
---|
610 | * |
---|
611 | *---------------------------------------------------------------------- |
---|
612 | */ |
---|
613 | |
---|
614 | static int |
---|
615 | SetOSTypeFromAny( |
---|
616 | Tcl_Interp *interp, /* Tcl interpreter */ |
---|
617 | Tcl_Obj *objPtr) /* Pointer to the object to convert */ |
---|
618 | { |
---|
619 | char *string; |
---|
620 | int length, result = TCL_OK; |
---|
621 | Tcl_DString ds; |
---|
622 | Tcl_Encoding encoding = Tcl_GetEncoding(NULL, "macRoman"); |
---|
623 | |
---|
624 | string = Tcl_GetStringFromObj(objPtr, &length); |
---|
625 | Tcl_UtfToExternalDString(encoding, string, length, &ds); |
---|
626 | |
---|
627 | if (Tcl_DStringLength(&ds) > 4) { |
---|
628 | Tcl_AppendResult(interp, "expected Macintosh OS type but got \"", |
---|
629 | string, "\": ", NULL); |
---|
630 | result = TCL_ERROR; |
---|
631 | } else { |
---|
632 | OSType osType; |
---|
633 | char string[4] = {'\0','\0','\0','\0'}; |
---|
634 | memcpy(string, Tcl_DStringValue(&ds), |
---|
635 | (size_t) Tcl_DStringLength(&ds)); |
---|
636 | osType = (OSType) string[0] << 24 | |
---|
637 | (OSType) string[1] << 16 | |
---|
638 | (OSType) string[2] << 8 | |
---|
639 | (OSType) string[3]; |
---|
640 | TclFreeIntRep(objPtr); |
---|
641 | objPtr->internalRep.longValue = (long) osType; |
---|
642 | objPtr->typePtr = &tclOSTypeType; |
---|
643 | } |
---|
644 | Tcl_DStringFree(&ds); |
---|
645 | Tcl_FreeEncoding(encoding); |
---|
646 | return result; |
---|
647 | } |
---|
648 | |
---|
649 | /* |
---|
650 | *---------------------------------------------------------------------- |
---|
651 | * |
---|
652 | * UpdateStringOfOSType -- |
---|
653 | * |
---|
654 | * Update the string representation for an OSType object. Note: This |
---|
655 | * function does not free an existing old string rep so storage will be |
---|
656 | * lost if this has not already been done. |
---|
657 | * |
---|
658 | * Results: |
---|
659 | * None. |
---|
660 | * |
---|
661 | * Side effects: |
---|
662 | * The object's string is set to a valid string that results from the |
---|
663 | * OSType-to-string conversion. |
---|
664 | * |
---|
665 | *---------------------------------------------------------------------- |
---|
666 | */ |
---|
667 | |
---|
668 | static void |
---|
669 | UpdateStringOfOSType( |
---|
670 | register Tcl_Obj *objPtr) /* OSType object whose string rep to update. */ |
---|
671 | { |
---|
672 | char string[5]; |
---|
673 | OSType osType = (OSType) objPtr->internalRep.longValue; |
---|
674 | Tcl_DString ds; |
---|
675 | Tcl_Encoding encoding = Tcl_GetEncoding(NULL, "macRoman"); |
---|
676 | |
---|
677 | string[0] = (char) (osType >> 24); |
---|
678 | string[1] = (char) (osType >> 16); |
---|
679 | string[2] = (char) (osType >> 8); |
---|
680 | string[3] = (char) (osType); |
---|
681 | string[4] = '\0'; |
---|
682 | Tcl_ExternalToUtfDString(encoding, string, -1, &ds); |
---|
683 | objPtr->bytes = ckalloc((unsigned) Tcl_DStringLength(&ds) + 1); |
---|
684 | strcpy(objPtr->bytes, Tcl_DStringValue(&ds)); |
---|
685 | objPtr->length = Tcl_DStringLength(&ds); |
---|
686 | Tcl_DStringFree(&ds); |
---|
687 | Tcl_FreeEncoding(encoding); |
---|
688 | } |
---|
689 | |
---|
690 | /* |
---|
691 | * Local Variables: |
---|
692 | * mode: c |
---|
693 | * c-basic-offset: 4 |
---|
694 | * fill-column: 78 |
---|
695 | * End: |
---|
696 | */ |
---|