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

# Content
1 /*
2 * $Id: extfs_macosx.mm,v 1.9 2007/01/24 02:37:06 asvitkine Exp $
3 *
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 * Basilisk II (C) 1997-2005 Christian Bauer
10 *
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 * 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 */
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 * filesystem layer presents the resource fork using the above pseudo path
107 */
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
118 /*
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 uint32 AllFinderInfo = kFSCatInfoFinderInfo;
236
237 if (fxinfo)
238 AllFinderInfo |= kFSCatInfoFinderXInfo;
239
240 status = FSGetCatalogInfo(&fsRef, AllFinderInfo, &cInfo, NULL, NULL, NULL);
241 if ( status == noErr )
242 {
243 // 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 D(printf("get_finfo(%s,...) - Got info of '%16.16s'\n", path, cInfo.finderInfo));
248 Host2Mac_memcpy(finfo, &cInfo.finderInfo, SIZEOF_FInfo);
249 if (fxinfo)
250 Host2Mac_memcpy(fxinfo, &cInfo.extFinderInfo, SIZEOF_FXInfo);
251 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 FSCatalogInfoBitmap whichInfo = kFSCatInfoNone;
297 if (finfo) {
298 whichInfo |= kFSCatInfoFinderInfo;
299 /*
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 Mac2Host_memcpy(&cInfo.finderInfo, finfo, SIZEOF_FInfo);
314 if (is_dir) {
315 cInfo.finderInfo[fdFlags] = oldFlags1;
316 cInfo.finderInfo[fdFlags + 1] = oldFlags2;
317 }
318 }
319 if (fxinfo) {
320 whichInfo |= kFSCatInfoFinderXInfo;
321 Mac2Host_memcpy(&cInfo.extFinderInfo, fxinfo, SIZEOF_FXInfo);
322 }
323 // 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 FSSetCatalogInfo(&fsRef, whichInfo, &cInfo);
328 }
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
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
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