ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/extfs_macosx.mm
Revision: 1.10
Committed: 2007-11-01T15:33:22Z (17 years, 1 month ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +1 -1 lines
State: FILE REMOVED
Log Message:
Rewrite ExtFS support for MacOS X. This implementation uses xattrs (metadata)
on Tiger+ to store FInfo and FXInfo. Otherwise, plain old .finfo/ helpers are
used. "Safe" flags and fields are always synchronized to/from MacOS X.

BTW, CFString leak was fixed at the same time.

File Contents

# User Rev Content
1 nigel 1.1 /*
2 gbeauche 1.10 * $Id: extfs_macosx.mm,v 1.9 2007/01/24 02:37:06 asvitkine Exp $
3 nigel 1.1 *
4     * extfs_macosx.mm - Access Mac OS X Finder and resource information (using Carbon calls).
5     * Based on:
6     *
7     * extfs_unix.cpp - MacOS file system for access native file system access, Unix specific stuff
8     *
9 gbeauche 1.4 * Basilisk II (C) 1997-2005 Christian Bauer
10 nigel 1.1 *
11     * This program is free software; you can redistribute it and/or modify
12     * it under the terms of the GNU General Public License as published by
13     * the Free Software Foundation; either version 2 of the License, or
14     * (at your option) any later version.
15     *
16     * This program is distributed in the hope that it will be useful,
17     * but WITHOUT ANY WARRANTY; without even the implied warranty of
18     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19     * GNU General Public License for more details.
20     *
21     * You should have received a copy of the GNU General Public License
22     * along with this program; if not, write to the Free Software
23     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24     */
25    
26     #include <sys/types.h>
27     #include <sys/stat.h>
28     #include <stdio.h>
29     #include <stdlib.h>
30     #include <unistd.h>
31     #include <dirent.h>
32     #include <errno.h>
33    
34     #include "sysdeps.h"
35     #include "extfs_macosx.h"
36     #include "extfs.h"
37    
38     #define DEBUG 0
39     #include "debug.h"
40    
41    
42     // Default Finder flags
43     const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited;
44    
45    
46     /*
47     * Initialization
48     */
49    
50     void extfs_init(void)
51     {
52     }
53    
54    
55     /*
56     * Deinitialization
57     */
58    
59     void extfs_exit(void)
60     {
61     }
62    
63    
64     /*
65     * Add component to path name
66     */
67    
68     void add_path_component(char *path, const char *component)
69     {
70     int l = strlen(path);
71     if (l < MAX_PATH_LENGTH-1 && path[l-1] != '/') {
72     path[l] = '/';
73     path[l+1] = 0;
74     }
75     strncat(path, component, MAX_PATH_LENGTH-1);
76     }
77    
78    
79     /*
80 nigel 1.2 * Add /rsrc to path name. Note that the 'correct' way to do this is to
81     * append '/..namedfork/rsrc', but I use this short form to save chars.
82 nigel 1.1 */
83    
84     void add_rsrc(const char *path, char *dest)
85     {
86     int l = strlen(path);
87    
88     if ( l > MAX_PATH_LENGTH-5 ) // If there is no room to add "rsrc\0"
89     return;
90    
91     *dest = '\0';
92     strncat(dest, path, l);
93    
94     if (l < MAX_PATH_LENGTH-1 && path[l-1] != '/') {
95     dest[l] = '/';
96     dest[l+1] = 0;
97     }
98     strcat(dest, "rsrc");
99     }
100    
101    
102     /*
103     * Resource forks on Mac OS X are kept on a UFS volume as /path/file/rsrc
104     *
105     * On HFS volumes, there is of course the data and rsrc fork, but the Darwin
106 gbeauche 1.5 * filesystem layer presents the resource fork using the above pseudo path
107 nigel 1.1 */
108    
109     static int open_rsrc(const char *path, int flag)
110     {
111     char path_rsrc[MAX_PATH_LENGTH];
112    
113     add_rsrc(path, path_rsrc);
114     return open(path_rsrc, flag);
115     }
116    
117 gbeauche 1.6
118 nigel 1.1 /*
119     * Finder info is a little bit harder. We need to use Carbon library calls to access them
120     */
121    
122    
123     /*
124     * Get/set finder info for file/directory specified by full path
125     */
126    
127     struct ext2type {
128     const char *ext;
129     uint32 type;
130     uint32 creator;
131     };
132    
133     static const ext2type e2t_translation[] = {
134     {".Z", FOURCC('Z','I','V','M'), FOURCC('L','Z','I','V')},
135     {".gz", FOURCC('G','z','i','p'), FOURCC('G','z','i','p')},
136     {".hqx", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
137     {".bin", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
138     {".pdf", FOURCC('P','D','F',' '), FOURCC('C','A','R','O')},
139     {".ps", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')},
140     {".sit", FOURCC('S','I','T','!'), FOURCC('S','I','T','x')},
141     {".tar", FOURCC('T','A','R','F'), FOURCC('T','A','R',' ')},
142     {".uu", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
143     {".uue", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
144     {".zip", FOURCC('Z','I','P',' '), FOURCC('Z','I','P',' ')},
145     {".8svx", FOURCC('8','S','V','X'), FOURCC('S','N','D','M')},
146     {".aifc", FOURCC('A','I','F','C'), FOURCC('T','V','O','D')},
147     {".aiff", FOURCC('A','I','F','F'), FOURCC('T','V','O','D')},
148     {".au", FOURCC('U','L','A','W'), FOURCC('T','V','O','D')},
149     {".mid", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')},
150     {".midi", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')},
151     {".mp2", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')},
152     {".mp3", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')},
153     {".wav", FOURCC('W','A','V','E'), FOURCC('T','V','O','D')},
154     {".bmp", FOURCC('B','M','P','f'), FOURCC('o','g','l','e')},
155     {".gif", FOURCC('G','I','F','f'), FOURCC('o','g','l','e')},
156     {".lbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')},
157     {".ilbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')},
158     {".jpg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')},
159     {".jpeg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')},
160     {".pict", FOURCC('P','I','C','T'), FOURCC('o','g','l','e')},
161     {".png", FOURCC('P','N','G','f'), FOURCC('o','g','l','e')},
162     {".sgi", FOURCC('.','S','G','I'), FOURCC('o','g','l','e')},
163     {".tga", FOURCC('T','P','I','C'), FOURCC('o','g','l','e')},
164     {".tif", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')},
165     {".tiff", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')},
166     {".htm", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')},
167     {".html", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')},
168     {".txt", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')},
169     {".rtf", FOURCC('T','E','X','T'), FOURCC('M','S','W','D')},
170     {".c", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
171     {".C", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
172     {".cc", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
173     {".cpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
174     {".cxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
175     {".h", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
176     {".hh", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
177     {".hpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
178     {".hxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
179     {".s", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
180     {".S", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
181     {".i", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
182     {".mpg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')},
183     {".mpeg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')},
184     {".mov", FOURCC('M','o','o','V'), FOURCC('T','V','O','D')},
185     {".fli", FOURCC('F','L','I',' '), FOURCC('T','V','O','D')},
186     {".avi", FOURCC('V','f','W',' '), FOURCC('T','V','O','D')},
187     {".qxd", FOURCC('X','D','O','C'), FOURCC('X','P','R','3')},
188     {".hfv", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')},
189     {".dsk", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')},
190     {".img", FOURCC('r','o','h','d'), FOURCC('d','d','s','k')},
191     {NULL, 0, 0} // End marker
192     };
193    
194     // Mac OS X way of doing the above
195    
196     #import <Foundation/NSString.h>
197    
198     extern "C"
199     {
200     NSString *NSHFSTypeOfFile (const NSString *);
201     uint32 NSHFSTypeCodeFromFileType (const NSString *); // Actually returns an OSType
202     }
203    
204     uint32 fileType (const char *cPath)
205     {
206     NSString *copy = [NSString stringWithCString: cPath],
207     *type = NSHFSTypeOfFile(copy);
208    
209     if ( type == nil )
210     {
211     D(NSLog(@"No type for file %s", cPath));
212     return 0; // Should this be '????' or ' ' ?
213     }
214    
215     D(NSLog(@"Got type %@ for %s", type, cPath));
216     return NSHFSTypeCodeFromFileType(type);
217     }
218    
219    
220     void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir)
221     {
222     FSRef fsRef;
223     int32 status;
224     // Set default finder info
225     Mac_memset(finfo, 0, SIZEOF_FInfo);
226     if (fxinfo)
227     Mac_memset(fxinfo, 0, SIZEOF_FXInfo);
228     WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS);
229     WriteMacInt32(finfo + fdLocation, (uint32)-1);
230    
231     status = FSPathMakeRef((const uint8 *)path, &fsRef, NULL);
232     if ( status == noErr )
233     {
234     FSCatalogInfo cInfo;
235 gbeauche 1.5 uint32 AllFinderInfo = kFSCatInfoFinderInfo;
236    
237     if (fxinfo)
238     AllFinderInfo |= kFSCatInfoFinderXInfo;
239 nigel 1.1
240     status = FSGetCatalogInfo(&fsRef, AllFinderInfo, &cInfo, NULL, NULL, NULL);
241     if ( status == noErr )
242     {
243 asvitkine 1.7 // byte-swap them to big endian (network order) if necessary
244     ((FileInfo *)&cInfo.finderInfo)->fileType = htonl(((FileInfo *)&cInfo.finderInfo)->fileType);
245     ((FileInfo *)&cInfo.finderInfo)->fileCreator = htonl(((FileInfo *)&cInfo.finderInfo)->fileCreator);
246     ((FileInfo *)&cInfo.finderInfo)->finderFlags = htons(((FileInfo *)&cInfo.finderInfo)->finderFlags);
247 nigel 1.1 D(printf("get_finfo(%s,...) - Got info of '%16.16s'\n", path, cInfo.finderInfo));
248 gbeauche 1.5 Host2Mac_memcpy(finfo, &cInfo.finderInfo, SIZEOF_FInfo);
249 nigel 1.1 if (fxinfo)
250 gbeauche 1.5 Host2Mac_memcpy(fxinfo, &cInfo.extFinderInfo, SIZEOF_FXInfo);
251 nigel 1.1 return;
252     }
253     else
254     printf("get_finfo(%s,...) failed to get catalog info\n", path);
255     }
256     else
257     printf("get_finfo(%s,...) failed to get FSRef\n", path);
258    
259    
260     // No Finder info file, translate file name extension to MacOS type/creator
261     if (!is_dir) {
262     int path_len = strlen(path);
263     for (int i=0; e2t_translation[i].ext; i++) {
264     int ext_len = strlen(e2t_translation[i].ext);
265     if (path_len < ext_len)
266     continue;
267     if (!strcmp(path + path_len - ext_len, e2t_translation[i].ext)) {
268     WriteMacInt32(finfo + fdType, e2t_translation[i].type);
269     WriteMacInt32(finfo + fdCreator, e2t_translation[i].creator);
270     break;
271     }
272     }
273     }
274    
275    
276     // Use alternate code to get type
277     uint32 type = fileType(path);
278    
279     if ( type )
280     WriteMacInt32(finfo + fdType, type);
281     }
282    
283     void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir)
284     {
285     FSRef fsRef;
286     OSErr status;
287    
288     status = FSPathMakeRef((const uint8 *)path, &fsRef, NULL);
289     if ( status == noErr )
290     {
291     FSCatalogInfo cInfo;
292    
293     status = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &cInfo, NULL, NULL, NULL);
294     if ( status == noErr )
295     {
296 gbeauche 1.5 FSCatalogInfoBitmap whichInfo = kFSCatInfoNone;
297     if (finfo) {
298     whichInfo |= kFSCatInfoFinderInfo;
299 gbeauche 1.6 /*
300     FIXME: Some users reported that directories could
301     mysteriously disappear from a MacOS X 10.4 Finder
302     point of view.
303    
304     An alternative is to use the ".finfo/" technique
305     on MacOS X provided that attributes are first
306     initialised from an FSGetCatalogInfo() call.
307     */
308     uint8 oldFlags1, oldFlags2;
309     if (is_dir) {
310     oldFlags1 = cInfo.finderInfo[fdFlags];
311     oldFlags2 = cInfo.finderInfo[fdFlags + 1];
312     }
313 gbeauche 1.5 Mac2Host_memcpy(&cInfo.finderInfo, finfo, SIZEOF_FInfo);
314 gbeauche 1.6 if (is_dir) {
315     cInfo.finderInfo[fdFlags] = oldFlags1;
316     cInfo.finderInfo[fdFlags + 1] = oldFlags2;
317     }
318 gbeauche 1.5 }
319     if (fxinfo) {
320     whichInfo |= kFSCatInfoFinderXInfo;
321     Mac2Host_memcpy(&cInfo.extFinderInfo, fxinfo, SIZEOF_FXInfo);
322     }
323 asvitkine 1.7 // byte-swap them to system byte order from big endian (network order) if necessary
324     ((FileInfo *)&cInfo.finderInfo)->fileType = ntohl(((FileInfo *)&cInfo.finderInfo)->fileType);
325     ((FileInfo *)&cInfo.finderInfo)->fileCreator = ntohl(((FileInfo *)&cInfo.finderInfo)->fileCreator);
326     ((FileInfo *)&cInfo.finderInfo)->finderFlags = ntohs(((FileInfo *)&cInfo.finderInfo)->finderFlags);
327 gbeauche 1.5 FSSetCatalogInfo(&fsRef, whichInfo, &cInfo);
328 nigel 1.1 }
329     }
330     }
331    
332    
333     /*
334     * Resource fork emulation functions
335     */
336    
337     uint32 get_rfork_size(const char *path)
338     {
339     // Open resource file
340     int fd = open_rsrc(path, O_RDONLY);
341     if (fd < 0)
342     return 0;
343    
344     // Get size
345     off_t size = lseek(fd, 0, SEEK_END);
346    
347     // Close file and return size
348     close(fd);
349     return size < 0 ? 0 : size;
350     }
351    
352     int open_rfork(const char *path, int flag)
353     {
354     return open_rsrc(path, flag);
355     }
356    
357     void close_rfork(const char *path, int fd)
358     {
359     close(fd);
360     }
361    
362    
363     /*
364     * Read "length" bytes from file to "buffer",
365     * returns number of bytes read (or -1 on error)
366     */
367    
368     ssize_t extfs_read(int fd, void *buffer, size_t length)
369     {
370     return read(fd, buffer, length);
371     }
372    
373    
374     /*
375     * Write "length" bytes from "buffer" to file,
376     * returns number of bytes written (or -1 on error)
377     */
378    
379     ssize_t extfs_write(int fd, void *buffer, size_t length)
380     {
381     return write(fd, buffer, length);
382     }
383    
384    
385     /*
386     * Remove file/directory (and associated helper files),
387     * returns false on error (and sets errno)
388     */
389    
390     bool extfs_remove(const char *path)
391     {
392     // Remove helpers first, don't complain if this fails
393     char helper_path[MAX_PATH_LENGTH];
394     add_rsrc(path, helper_path);
395     remove(helper_path);
396    
397     // Now remove file or directory (and helper directories in the directory)
398     if (remove(path) < 0) {
399     if (errno == EISDIR || errno == ENOTEMPTY) {
400     return rmdir(path) == 0;
401     } else
402     return false;
403     }
404     return true;
405     }
406    
407    
408     /*
409     * Rename/move file/directory (and associated helper files),
410     * returns false on error (and sets errno)
411     */
412    
413     bool extfs_rename(const char *old_path, const char *new_path)
414     {
415     // Rename helpers first, don't complain if this fails
416     char old_helper_path[MAX_PATH_LENGTH], new_helper_path[MAX_PATH_LENGTH];
417     add_rsrc(old_path, old_helper_path);
418     add_rsrc(new_path, new_helper_path);
419     rename(old_helper_path, new_helper_path);
420    
421     // Now rename file
422     return rename(old_path, new_path) == 0;
423     }
424 asvitkine 1.8
425    
426     // Convert from the host OS filename encoding to MacRoman
427     const char *host_encoding_to_macroman(const char *filename)
428     {
429     static char filename_mr[64];
430     CFStringRef sref = CFStringCreateWithCString(0, filename, kCFStringEncodingUTF8);
431     if (sref) {
432     memset(filename_mr, 0, sizeof(filename_mr));
433     if (CFStringGetCString(sref, filename_mr, sizeof(filename_mr), kCFStringEncodingMacRoman)) {
434     return filename_mr;
435     }
436     CFRelease(sref);
437     }
438     return filename;
439     }
440    
441 asvitkine 1.9
442     // Convert from MacRoman to the host OS filename encoding
443     const char *macroman_to_host_encoding(const char *filename)
444     {
445     static char filename_mr[64];
446     CFStringRef sref = CFStringCreateWithCString(0, filename, kCFStringEncodingMacRoman);
447     if (sref) {
448     memset(filename_mr, 0, sizeof(filename_mr));
449     if (CFStringGetCString(sref, filename_mr, sizeof(filename_mr), kCFStringEncodingUTF8)) {
450     return filename_mr;
451     }
452     CFRelease(sref);
453     }
454     return filename;
455     }
456