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