ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/extfs_macosx.cpp
Revision: 1.4
Committed: 2008-06-20T00:47:25Z (16 years, 5 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +1 -1 lines
Log Message:
[patch from Kelvin Delbarre] Typo fix.

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * extfs_macosx.cpp - MacOS file system for access native file system access, MacOS X specific stuff
3     *
4 gbeauche 1.3 * Basilisk II (C) 1997-2008 Christian Bauer
5 gbeauche 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include <sys/types.h>
22     #include <sys/stat.h>
23     #include <sys/attr.h>
24     #include <sys/syscall.h>
25     #include <stdio.h>
26     #include <stdlib.h>
27     #include <unistd.h>
28     #include <dirent.h>
29     #include <errno.h>
30    
31     #include "sysdeps.h"
32     #include "prefs.h"
33     #include "extfs.h"
34     #include "extfs_defs.h"
35    
36 gbeauche 1.2 // XXX: don't clobber with native definitions
37     #define noErr native_noErr
38     #define Point native_Point
39     #define Rect native_Rect
40     #define ProcPtr native_ProcPtr
41     # include <CoreFoundation/CFString.h>
42     #undef ProcPtr
43     #undef Rect
44     #undef Point
45 gbeauche 1.1 #undef noErr
46    
47     #define DEBUG 0
48     #include "debug.h"
49    
50    
51     // Default Finder flags
52     const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited;
53    
54    
55     /*
56     * Extended attributes (Tiger+)
57     */
58    
59     #define USE_XATTRS g_use_xattrs
60     static bool g_use_xattrs = false;
61    
62     #define XATTR_TEST "org.BasiliskII.TestAttr"
63     #define XATTR_FINFO "org.BasiliskII.FinderInfo"
64     #define XATTR_FXINFO "org.BasiliskII.ExtendedFinderInfo"
65    
66     static bool get_xattr(const char *path, const char *name, void *value, uint32 size)
67     {
68     return syscall(SYS_getxattr, path, name, value, size, 0, 0) == size;
69     }
70    
71     static bool set_xattr(const char *path, const char *name, const void *value, uint32 size)
72     {
73     return syscall(SYS_setxattr, path, name, value, size, 0, 0) == 0;
74     }
75    
76     static bool remove_xattr(const char *path, const char *name)
77     {
78     return syscall(SYS_removexattr, path, name, 0) == 0;
79     }
80    
81     static bool check_xattr(void)
82     {
83     const char *path = PrefsFindString("extfs");
84     if (path == NULL)
85     return false;
86     const uint32 sentinel = 0xdeadbeef;
87     if (!set_xattr(path, XATTR_TEST, &sentinel, sizeof(sentinel)))
88     return false;
89     uint32 v;
90     if (!get_xattr(path, XATTR_TEST, &v, sizeof(v)))
91     return false;
92     if (!remove_xattr(path, XATTR_TEST))
93     return false;
94     return v == sentinel;
95     }
96    
97    
98     /*
99     * Initialization
100     */
101    
102     void extfs_init(void)
103     {
104     g_use_xattrs = check_xattr();
105     }
106    
107    
108     /*
109     * Deinitialization
110     */
111    
112     void extfs_exit(void)
113     {
114     }
115    
116    
117     /*
118     * Add component to path name
119     */
120    
121     void add_path_component(char *path, const char *component)
122     {
123     int l = strlen(path);
124     if (l < MAX_PATH_LENGTH-1 && path[l-1] != '/') {
125     path[l] = '/';
126     path[l+1] = 0;
127     }
128     strncat(path, component, MAX_PATH_LENGTH-1);
129     }
130    
131    
132     /*
133     * Finder info manipulation helpers
134     */
135    
136     typedef uint8 FinderInfo[SIZEOF_FInfo];
137    
138     struct FinderInfoAttrBuf {
139     uint32 length;
140     FinderInfo finderInfo;
141     FinderInfo extendedFinderInfo;
142     };
143    
144     static const FinderInfo kNativeFInfoMask = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00};
145     static const FinderInfo kNativeFXInfoMask = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00};
146     static const FinderInfo kNativeDInfoMask = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00};
147     static const FinderInfo kNativeDXInfoMask = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00}; /* XXX: keep frScroll? */
148    
149     static void finfo_merge(FinderInfo dst, const FinderInfo emu, const FinderInfo nat, const FinderInfo mask)
150     {
151     for (int i = 0; i < SIZEOF_FInfo; i++)
152     dst[i] = (emu[i] & ~mask[i]) | (nat[i] & mask[i]);
153     }
154    
155     static void finfo_split(FinderInfo dst, const FinderInfo emu, const FinderInfo mask)
156     {
157     for (int i = 0; i < SIZEOF_FInfo; i++)
158     dst[i] = emu[i] & mask[i];
159     }
160    
161    
162     /*
163     * Finder info are kept in helper files (on anything below Tiger)
164     *
165     * Finder info:
166     * /path/.finf/file
167     *
168     * The .finf files store a FInfo/DInfo, followed by a FXInfo/DXInfo
169     * (16+16 bytes)
170     */
171    
172     static void make_finf_path(const char *src, char *dest, bool only_dir = false)
173     {
174     dest[0] = 0;
175    
176     // Get pointer to last component of path
177     const char *last_part = strrchr(src, '/');
178     if (last_part)
179     last_part++;
180     else
181     last_part = src;
182    
183     // Copy everything before
184     strncpy(dest, src, last_part-src);
185     dest[last_part-src] = 0;
186    
187     // Add additional component
188     strncat(dest, ".finf/", MAX_PATH_LENGTH-1);
189    
190     // Add last component
191     if (!only_dir)
192     strncat(dest, last_part, MAX_PATH_LENGTH-1);
193     }
194    
195     static int create_finf_dir(const char *path)
196     {
197     char finf_dir[MAX_PATH_LENGTH];
198     make_finf_path(path, finf_dir, true);
199     if (finf_dir[strlen(finf_dir) - 1] == '/') // Remove trailing "/"
200     finf_dir[strlen(finf_dir) - 1] = 0;
201     return mkdir(finf_dir, 0777);
202     }
203    
204     static int open_finf(const char *path, int flag)
205     {
206     char finf_path[MAX_PATH_LENGTH];
207     make_finf_path(path, finf_path);
208    
209     if ((flag & O_ACCMODE) == O_RDWR || (flag & O_ACCMODE) == O_WRONLY)
210     flag |= O_CREAT;
211     int fd = open(finf_path, flag, 0666);
212     if (fd < 0) {
213     if (errno == ENOENT && (flag & O_CREAT)) {
214     // One path component was missing, probably the finf
215     // directory. Try to create it and re-open the file.
216     int ret = create_finf_dir(path);
217     if (ret < 0)
218     return ret;
219     fd = open(finf_path, flag, 0666);
220     }
221     }
222     return fd;
223     }
224    
225    
226     /*
227     * Resource forks are kept into their native location
228     *
229     * Resource fork:
230     * /path/file/..namedfork/rsrc
231     */
232    
233     static void make_rsrc_path(const char *src, char *dest)
234     {
235     int l = strlen(src);
236     if (l + 1 + 16 + 1 <= MAX_PATH_LENGTH)
237     memcpy(dest, src, l + 1);
238     else {
239     // The rsrc component is copied as is, if there is not enough
240     // space to add it. In that case, open() will fail gracefully
241     // and this is what we want.
242 asvitkine 1.4 dest[0] = '.';
243 gbeauche 1.1 dest[1] = '\0';
244     }
245    
246     add_path_component(dest, "..namedfork/rsrc");
247     }
248    
249     static int open_rsrc(const char *path, int flag)
250     {
251     char rsrc_path[MAX_PATH_LENGTH];
252     make_rsrc_path(path, rsrc_path);
253    
254     return open(rsrc_path, flag);
255     }
256    
257    
258     /*
259     * Get/set finder info for file/directory specified by full path
260     */
261    
262     struct ext2type {
263     const char *ext;
264     uint32 type;
265     uint32 creator;
266     };
267    
268     static const ext2type e2t_translation[] = {
269     {".Z", FOURCC('Z','I','V','M'), FOURCC('L','Z','I','V')},
270     {".gz", FOURCC('G','z','i','p'), FOURCC('G','z','i','p')},
271     {".hqx", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
272     {".bin", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
273     {".pdf", FOURCC('P','D','F',' '), FOURCC('C','A','R','O')},
274     {".ps", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')},
275     {".sit", FOURCC('S','I','T','!'), FOURCC('S','I','T','x')},
276     {".tar", FOURCC('T','A','R','F'), FOURCC('T','A','R',' ')},
277     {".uu", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
278     {".uue", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
279     {".zip", FOURCC('Z','I','P',' '), FOURCC('Z','I','P',' ')},
280     {".8svx", FOURCC('8','S','V','X'), FOURCC('S','N','D','M')},
281     {".aifc", FOURCC('A','I','F','C'), FOURCC('T','V','O','D')},
282     {".aiff", FOURCC('A','I','F','F'), FOURCC('T','V','O','D')},
283     {".au", FOURCC('U','L','A','W'), FOURCC('T','V','O','D')},
284     {".mid", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')},
285     {".midi", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')},
286     {".mp2", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')},
287     {".mp3", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')},
288     {".wav", FOURCC('W','A','V','E'), FOURCC('T','V','O','D')},
289     {".bmp", FOURCC('B','M','P','f'), FOURCC('o','g','l','e')},
290     {".gif", FOURCC('G','I','F','f'), FOURCC('o','g','l','e')},
291     {".lbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')},
292     {".ilbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')},
293     {".jpg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')},
294     {".jpeg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')},
295     {".pict", FOURCC('P','I','C','T'), FOURCC('o','g','l','e')},
296     {".png", FOURCC('P','N','G','f'), FOURCC('o','g','l','e')},
297     {".sgi", FOURCC('.','S','G','I'), FOURCC('o','g','l','e')},
298     {".tga", FOURCC('T','P','I','C'), FOURCC('o','g','l','e')},
299     {".tif", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')},
300     {".tiff", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')},
301     {".htm", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')},
302     {".html", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')},
303     {".txt", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')},
304     {".rtf", FOURCC('T','E','X','T'), FOURCC('M','S','W','D')},
305     {".c", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
306     {".C", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
307     {".cc", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
308     {".cpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
309     {".cxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
310     {".h", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
311     {".hh", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
312     {".hpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
313     {".hxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
314     {".s", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
315     {".S", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
316     {".i", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
317     {".mpg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')},
318     {".mpeg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')},
319     {".mov", FOURCC('M','o','o','V'), FOURCC('T','V','O','D')},
320     {".fli", FOURCC('F','L','I',' '), FOURCC('T','V','O','D')},
321     {".avi", FOURCC('V','f','W',' '), FOURCC('T','V','O','D')},
322     {".qxd", FOURCC('X','D','O','C'), FOURCC('X','P','R','3')},
323     {".hfv", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')},
324     {".dsk", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')},
325     {".img", FOURCC('r','o','h','d'), FOURCC('d','d','s','k')},
326     {NULL, 0, 0} // End marker
327     };
328    
329     // Get emulated Finder info from metadata (Tiger+)
330     static bool get_finfo_from_xattr(const char *path, uint8 *finfo, uint8 *fxinfo)
331     {
332     if (!get_xattr(path, XATTR_FINFO, finfo, SIZEOF_FInfo))
333     return false;
334     if (fxinfo && !get_xattr(path, XATTR_FXINFO, fxinfo, SIZEOF_FXInfo))
335     return false;
336     return true;
337     }
338    
339     // Get emulated Finder info from helper file
340     static bool get_finfo_from_helper(const char *path, uint8 *finfo, uint8 *fxinfo)
341     {
342     int fd = open_finf(path, O_RDONLY);
343     if (fd < 0)
344     return false;
345    
346     ssize_t actual = read(fd, finfo, SIZEOF_FInfo);
347     if (fxinfo)
348     actual += read(fd, fxinfo, SIZEOF_FXInfo);
349     close(fd);
350     return actual == (SIZEOF_FInfo + (fxinfo ? SIZEOF_FXInfo : 0));
351     }
352    
353     // Get native Finder info
354     static bool get_finfo_from_native(const char *path, uint8 *finfo, uint8 *fxinfo)
355     {
356     struct attrlist attrList;
357     memset(&attrList, 0, sizeof(attrList));
358     attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
359     attrList.commonattr = ATTR_CMN_FNDRINFO;
360    
361     FinderInfoAttrBuf attrBuf;
362     if (getattrlist(path, &attrList, &attrBuf, sizeof(attrBuf), 0) < 0)
363     return false;
364    
365     memcpy(finfo, attrBuf.finderInfo, SIZEOF_FInfo);
366     if (fxinfo)
367     memcpy(fxinfo, attrBuf.extendedFinderInfo, SIZEOF_FXInfo);
368     return true;
369     }
370    
371     static bool do_get_finfo(const char *path, bool has_fxinfo,
372     FinderInfo emu_finfo, FinderInfo emu_fxinfo,
373     FinderInfo nat_finfo, FinderInfo nat_fxinfo)
374     {
375     memset(emu_finfo, 0, SIZEOF_FInfo);
376     if (has_fxinfo)
377     memset(emu_fxinfo, 0, SIZEOF_FXInfo);
378     *((uint16 *)(emu_finfo + fdFlags)) = htonl(DEFAULT_FINDER_FLAGS);
379     *((uint32 *)(emu_finfo + fdLocation)) = htonl((uint32)-1);
380    
381     if (USE_XATTRS)
382     get_finfo_from_xattr(path, emu_finfo, has_fxinfo ? emu_fxinfo : NULL);
383     else
384     get_finfo_from_helper(path, emu_finfo, has_fxinfo ? emu_fxinfo : NULL);
385    
386     if (!get_finfo_from_native(path, nat_finfo, has_fxinfo ? nat_fxinfo : NULL))
387     return false;
388     return true;
389     }
390    
391     void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir)
392     {
393     // Set default finder info
394     Mac_memset(finfo, 0, SIZEOF_FInfo);
395     if (fxinfo)
396     Mac_memset(fxinfo, 0, SIZEOF_FXInfo);
397     WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS);
398     WriteMacInt32(finfo + fdLocation, (uint32)-1);
399    
400     // Merge emulated and native Finder info
401     FinderInfo emu_finfo, emu_fxinfo;
402     FinderInfo nat_finfo, nat_fxinfo;
403     if (do_get_finfo(path, fxinfo, emu_finfo, emu_fxinfo, nat_finfo, nat_fxinfo)) {
404     if (!is_dir) {
405     finfo_merge(Mac2HostAddr(finfo), emu_finfo, nat_finfo, kNativeFInfoMask);
406     if (fxinfo)
407     finfo_merge(Mac2HostAddr(fxinfo), emu_fxinfo, nat_fxinfo, kNativeFXInfoMask);
408     if (ReadMacInt32(finfo + fdType) != 0 && ReadMacInt32(finfo + fdCreator) != 0)
409     return;
410     }
411     else {
412     finfo_merge(Mac2HostAddr(finfo), emu_finfo, nat_finfo, kNativeDInfoMask);
413     if (fxinfo)
414     finfo_merge(Mac2HostAddr(fxinfo), emu_fxinfo, nat_fxinfo, kNativeDXInfoMask);
415     return;
416     }
417     }
418    
419     // No native Finder info, translate file name extension to MacOS type/creator
420     if (!is_dir) {
421     int path_len = strlen(path);
422     for (int i=0; e2t_translation[i].ext; i++) {
423     int ext_len = strlen(e2t_translation[i].ext);
424     if (path_len < ext_len)
425     continue;
426     if (!strcmp(path + path_len - ext_len, e2t_translation[i].ext)) {
427     WriteMacInt32(finfo + fdType, e2t_translation[i].type);
428     WriteMacInt32(finfo + fdCreator, e2t_translation[i].creator);
429     break;
430     }
431     }
432     }
433     }
434    
435     // Set emulated Finder info into metada (Tiger+)
436     static bool set_finfo_to_xattr(const char *path, const uint8 *finfo, const uint8 *fxinfo)
437     {
438     if (!set_xattr(path, XATTR_FINFO, finfo, SIZEOF_FInfo))
439     return false;
440     if (fxinfo && !set_xattr(path, XATTR_FXINFO, fxinfo, SIZEOF_FXInfo))
441     return false;
442     return true;
443     }
444    
445     // Set emulated Finder info into helper file
446     static bool set_finfo_to_helper(const char *path, const uint8 *finfo, const uint8 *fxinfo)
447     {
448     int fd = open_finf(path, O_RDWR);
449     if (fd < 0)
450     return false;
451    
452     ssize_t actual = write(fd, finfo, SIZEOF_FInfo);
453     if (fxinfo)
454     actual += write(fd, fxinfo, SIZEOF_FXInfo);
455     close(fd);
456     return actual == (SIZEOF_FInfo + (fxinfo ? SIZEOF_FXInfo : 0));
457     }
458    
459     // Set native Finder info
460     static bool set_finfo_to_native(const char *path, const uint8 *finfo, const uint8 *fxinfo, bool is_dir)
461     {
462     struct attrlist attrList;
463     memset(&attrList, 0, sizeof(attrList));
464     attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
465     attrList.commonattr = ATTR_CMN_FNDRINFO;
466    
467     FinderInfoAttrBuf attrBuf;
468     if (getattrlist(path, &attrList, &attrBuf, sizeof(attrBuf), 0) < 0)
469     return false;
470    
471     finfo_merge(attrBuf.finderInfo, attrBuf.finderInfo, finfo, is_dir ? kNativeDInfoMask : kNativeFInfoMask);
472     if (fxinfo)
473     finfo_merge(attrBuf.extendedFinderInfo, attrBuf.extendedFinderInfo, fxinfo, is_dir ? kNativeDXInfoMask : kNativeFXInfoMask);
474    
475     attrList.commonattr = ATTR_CMN_FNDRINFO;
476     if (setattrlist(path, &attrList, attrBuf.finderInfo, 2 * SIZEOF_FInfo, 0) < 0)
477     return false;
478     return true;
479     }
480    
481     void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir)
482     {
483     // Extract native Finder info flags
484     FinderInfo nat_finfo, nat_fxinfo;
485     const uint8 *emu_finfo = Mac2HostAddr(finfo);
486     const uint8 *emu_fxinfo = fxinfo ? Mac2HostAddr(fxinfo) : NULL;
487     finfo_split(nat_finfo, emu_finfo, is_dir ? kNativeDInfoMask : kNativeFInfoMask);
488     if (fxinfo)
489     finfo_split(nat_fxinfo, emu_fxinfo, is_dir ? kNativeDXInfoMask : kNativeFXInfoMask);
490    
491     // Update Finder info file (all flags)
492     if (USE_XATTRS)
493     set_finfo_to_xattr(path, emu_finfo, emu_fxinfo);
494     else
495     set_finfo_to_helper(path, emu_finfo, emu_fxinfo);
496    
497     // Update native Finder info flags
498     set_finfo_to_native(path, nat_finfo, nat_fxinfo, is_dir);
499     }
500    
501    
502     /*
503     * Resource fork emulation functions
504     */
505    
506     uint32 get_rfork_size(const char *path)
507     {
508     // Open resource file
509     int fd = open_rsrc(path, O_RDONLY);
510     if (fd < 0)
511     return 0;
512    
513     // Get size
514     off_t size = lseek(fd, 0, SEEK_END);
515    
516     // Close file and return size
517     close(fd);
518     return size < 0 ? 0 : size;
519     }
520    
521     int open_rfork(const char *path, int flag)
522     {
523     return open_rsrc(path, flag);
524     }
525    
526     void close_rfork(const char *path, int fd)
527     {
528     close(fd);
529     }
530    
531    
532     /*
533     * Read "length" bytes from file to "buffer",
534     * returns number of bytes read (or -1 on error)
535     */
536    
537     ssize_t extfs_read(int fd, void *buffer, size_t length)
538     {
539     return read(fd, buffer, length);
540     }
541    
542    
543     /*
544     * Write "length" bytes from "buffer" to file,
545     * returns number of bytes written (or -1 on error)
546     */
547    
548     ssize_t extfs_write(int fd, void *buffer, size_t length)
549     {
550     return write(fd, buffer, length);
551     }
552    
553    
554     /*
555     * Remove file/directory (and associated helper files),
556     * returns false on error (and sets errno)
557     */
558    
559     bool extfs_remove(const char *path)
560     {
561     // Remove helpers first, don't complain if this fails
562     char helper_path[MAX_PATH_LENGTH];
563     make_finf_path(path, helper_path, false);
564     remove(helper_path);
565     make_rsrc_path(path, helper_path);
566     remove(helper_path);
567    
568     // Now remove file or directory (and helper directories in the directory)
569     if (remove(path) < 0) {
570     if (errno == EISDIR || errno == ENOTEMPTY) {
571     helper_path[0] = 0;
572     strncpy(helper_path, path, MAX_PATH_LENGTH-1);
573     add_path_component(helper_path, ".finf");
574     rmdir(helper_path);
575     return rmdir(path) == 0;
576     } else
577     return false;
578     }
579     return true;
580     }
581    
582    
583     /*
584     * Rename/move file/directory (and associated helper files),
585     * returns false on error (and sets errno)
586     */
587    
588     bool extfs_rename(const char *old_path, const char *new_path)
589     {
590     // Rename helpers first, don't complain if this fails
591     char old_helper_path[MAX_PATH_LENGTH], new_helper_path[MAX_PATH_LENGTH];
592     make_finf_path(old_path, old_helper_path, false);
593     make_finf_path(new_path, new_helper_path, false);
594     create_finf_dir(new_path);
595     rename(old_helper_path, new_helper_path);
596     make_rsrc_path(old_path, old_helper_path);
597     make_rsrc_path(new_path, new_helper_path);
598     rename(old_helper_path, new_helper_path);
599    
600     // Now rename file
601     return rename(old_path, new_path) == 0;
602     }
603    
604    
605     /*
606     * Strings (filenames) conversion
607     */
608    
609     // Convert string in the specified source and target encodings
610     const char *convert_string(const char *str, CFStringEncoding from, CFStringEncoding to)
611     {
612     const char *ostr = str;
613     CFStringRef cfstr = CFStringCreateWithCString(NULL, str, from);
614     if (cfstr) {
615     static char buffer[MAX_PATH_LENGTH];
616     memset(buffer, 0, sizeof(buffer));
617     if (CFStringGetCString(cfstr, buffer, sizeof(buffer), to))
618     ostr = buffer;
619     CFRelease(cfstr);
620     }
621     return ostr;
622     }
623    
624     // Convert from the host OS filename encoding to MacRoman
625     const char *host_encoding_to_macroman(const char *filename)
626     {
627     return convert_string(filename, kCFStringEncodingUTF8, kCFStringEncodingMacRoman);
628     }
629    
630     // Convert from MacRoman to host OS filename encoding
631     const char *macroman_to_host_encoding(const char *filename)
632     {
633     return convert_string(filename, kCFStringEncodingMacRoman, kCFStringEncodingUTF8);
634     }