]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/vfs_adouble.c
add a SFM compatible format for adouble
[netatalk.git] / etc / afpd / vfs_adouble.c
1 /*
2     Copyright (c) 2004 Didier Gautheron
3  
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8  
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13  
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  
18 */
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif /* HAVE_CONFIG_H */
22
23 #ifdef STDC_HEADERS
24 #include <string.h>
25 #endif
26
27 #include <stdio.h>
28     
29 #include <atalk/adouble.h>
30 #include <atalk/logger.h>
31 #include <atalk/util.h>
32
33 #include "directory.h"
34 #include "volume.h"
35 #include "unix.h"
36
37 struct perm {
38     uid_t uid;
39     gid_t gid;
40 };
41
42 typedef int (*rf_loop)(struct dirent *, char *, void *, int );
43
44 /* ----------------------------- */
45 static int 
46 for_each_adouble(const char *from, const char *name, rf_loop fn, void *data, int flag)
47 {
48     char            buf[ MAXPATHLEN + 1];
49     char            *m;
50     DIR             *dp;
51     struct dirent   *de;
52     int             ret;
53     
54
55     if (NULL == ( dp = opendir( name)) ) {
56         if (!flag) {
57             LOG(log_error, logtype_afpd, "%s: opendir %s: %s", from, fullpathname(name),strerror(errno) );
58             return -1;
59         }
60         return 0;
61     }
62     strlcpy( buf, name, sizeof(buf));
63     strlcat( buf, "/", sizeof(buf) );
64     m = strchr( buf, '\0' );
65     ret = 0;
66     while ((de = readdir(dp))) {
67         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
68                 continue;
69         }
70         
71         strlcat(buf, de->d_name, sizeof(buf));
72         if (fn && (ret = fn(de, buf, data, flag))) {
73            closedir(dp);
74            return ret;
75         }
76         *m = 0;
77     }
78     closedir(dp);
79     return ret;
80 }
81
82 /* ------------------------------ */
83 static int ads_chown_loop(struct dirent *de _U_, char *name, void *data, int flag _U_)
84 {
85     struct perm   *owner  = data;
86     
87     if (chown( name , owner->uid, owner->gid ) < 0) {
88         return -1;
89     }
90     return 0;
91 }
92
93 static int RF_chown_ads(const struct vol *vol, const char *path, uid_t uid, gid_t gid)
94
95 {
96     struct        stat st;
97     char          *ad_p;
98     struct perm   owner;
99     
100     owner.uid = uid;
101     owner.gid = gid;
102
103
104     ad_p = ad_dir(vol->vfs->ad_path(path, ADFLAGS_HF ));
105
106     if ( stat( ad_p, &st ) < 0 ) {
107         /* ignore */
108         return 0;
109     }
110     
111     if (chown( ad_p, uid, gid ) < 0) {
112         return -1;
113     }
114     return for_each_adouble("chown_ads", ad_p, ads_chown_loop, &owner, 1);
115 }
116
117 /* --------------------------------- */
118 static int deletecurdir_ads1_loop(struct dirent *de _U_, char *name, void *data _U_, int flag _U_)
119 {
120     return netatalk_unlink(name);
121 }
122
123 static int ads_delete_rf(char *name) 
124 {
125     int err;
126
127     if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1))) 
128         return err;
129     /* FIXME 
130      * it's a problem for a nfs mounted folder, there's .nfsxxx around
131      * for linux the following line solve it.
132      * but it could fail if rm .nfsxxx  create a new .nfsyyy :(
133     */
134     if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1))) 
135         return err;
136     return netatalk_rmdir(name);
137 }
138
139 static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data _U_, int flag _U_)
140 {
141     struct stat st;
142     
143     /* bail if the file exists in the current directory.
144      * note: this will not fail with dangling symlinks */
145     
146     if (stat(de->d_name, &st) == 0) {
147         return AFPERR_DIRNEMPT;
148     }
149     return ads_delete_rf(name);
150 }
151
152 static int RF_deletecurdir_ads(const struct vol *vol _U_)
153 {
154     int err;
155     
156     /* delete stray .AppleDouble files. this happens to get .Parent files as well. */
157     if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_ads_loop, NULL, 1))) 
158         return err;
159     return netatalk_rmdir( ".AppleDouble" );
160 }
161
162 /* ------------------- */
163 struct set_mode {
164     mode_t mode;
165     struct stat *st;
166 };
167
168 static int ads_setfilmode_loop(struct dirent *de _U_, char *name, void *data, int flag _U_)
169 {
170     struct set_mode *param = data;
171
172     return setfilmode(name, param->mode, param->st);
173 }
174
175 static int ads_setfilmode(const char * name, mode_t mode, struct stat *st)
176 {
177     mode_t file_mode = ad_hf_mode(mode);
178     mode_t dir_mode = file_mode;
179     struct set_mode param;
180
181     if ((dir_mode & (S_IRUSR | S_IWUSR )))
182         dir_mode |= S_IXUSR;
183     if ((dir_mode & (S_IRGRP | S_IWGRP )))
184         dir_mode |= S_IXGRP;
185     if ((dir_mode & (S_IROTH | S_IWOTH )))
186         dir_mode |= S_IXOTH;    
187     
188         /* change folder */
189         dir_mode |= DIRBITS;
190     if (dir_rx_set(dir_mode)) {
191         if (chmod( name,  dir_mode ) < 0)
192             return -1;
193     }
194     param.st = st;
195     param.mode = file_mode;
196     if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, &param, 0) < 0)
197         return -1;
198
199     if (!dir_rx_set(dir_mode)) {
200         if (chmod( name,  dir_mode ) < 0)
201             return -1;
202     }
203
204     return 0;
205 }
206
207 static int RF_setfilmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
208 {
209     return ads_setfilmode(ad_dir(vol->vfs->ad_path( name, ADFLAGS_HF )), mode, st);
210 }
211
212 /* ------------------- */
213 static int RF_setdirunixmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
214 {
215     char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
216     char   ad_p[ MAXPATHLEN + 1];
217     int dropbox = (vol->v_flags & AFPVOL_DROPBOX);
218
219     strlcpy(ad_p,ad_dir(adouble), MAXPATHLEN + 1);
220
221     if (dir_rx_set(mode)) {
222
223         /* .AppleDouble */
224         if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
225             return -1;
226
227         /* .AppleDouble/.Parent */
228         if (stickydirmode(ad_p, DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
229             return -1;
230     }
231
232     if (ads_setfilmode(ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR)), mode, st) < 0)
233         return -1;
234
235     if (!dir_rx_set(mode)) {
236         if (stickydirmode(ad_p, DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
237             return  -1 ;
238         if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
239             return -1;
240     }
241     return 0;
242 }
243
244 /* ------------------- */
245 struct dir_mode {
246     mode_t mode;
247     int    dropbox;
248 };
249
250 static int setdirmode_ads_loop(struct dirent *de _U_, char *name, void *data, int flag)
251 {
252
253     struct dir_mode *param = data;
254     int    ret = 0; /* 0 ignore error, -1 */
255
256     if (dir_rx_set(param->mode)) {
257         if (stickydirmode(name, DIRBITS | param->mode, param->dropbox) < 0) {
258             if (flag) {
259                 return 0;
260             }
261             return ret;
262         }
263     }
264     if (ads_setfilmode(name, param->mode, NULL) < 0)
265         return ret;
266
267     if (!dir_rx_set(param->mode)) {
268         if (stickydirmode(name, DIRBITS | param->mode, param->dropbox) < 0) {
269             if (flag) {
270                 return 0;
271             }
272             return ret;
273         }
274     }
275     return 0;
276 }
277
278 static int RF_setdirmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st _U_)
279 {
280     char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
281     char   ad_p[ MAXPATHLEN + 1];
282     struct dir_mode param;
283
284     param.mode = mode;
285     param.dropbox = (vol->v_flags & AFPVOL_DROPBOX);
286
287     strlcpy(ad_p,ad_dir(adouble), sizeof(ad_p));
288
289     if (dir_rx_set(mode)) {
290         /* .AppleDouble */
291         if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox) < 0 && !vol_noadouble(vol)) 
292             return -1;
293     }
294
295     if (for_each_adouble("setdirmode_ads", ad_dir(ad_p), setdirmode_ads_loop, &param, vol_noadouble(vol)))
296         return -1;
297
298     if (!dir_rx_set(mode)) {
299         if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox) < 0 && !vol_noadouble(vol)) 
300             return -1;
301     }
302     return 0;
303 }
304
305 /* ------------------- */
306 static int setdirowner_ads1_loop(struct dirent *de _U_, char *name, void *data, int flag _U_)
307 {
308     struct perm   *owner  = data;
309
310     if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
311          LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
312                 owner->uid, owner->gid, fullpathname(name), strerror(errno) );
313          /* return ( -1 ); Sometimes this is okay */
314     }
315     return 0;
316 }
317
318 static int setdirowner_ads_loop(struct dirent *de _U_, char *name, void *data, int flag)
319 {
320     struct perm   *owner  = data;
321
322     if (for_each_adouble("setdirowner", name, setdirowner_ads1_loop, data, flag) < 0)
323         return -1;
324
325     if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
326          LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
327                 owner->uid, owner->gid, fullpathname(name), strerror(errno) );
328          /* return ( -1 ); Sometimes this is okay */
329     }
330     return 0;
331 }
332
333 static int RF_setdirowner_ads(const struct vol *vol, const char *name, uid_t uid, gid_t gid)
334 {
335     int           noadouble = vol_noadouble(vol);
336     char          adouble_p[ MAXPATHLEN + 1];
337     struct stat   st;
338     struct perm   owner;
339     
340     owner.uid = uid;
341     owner.gid = gid;
342
343     strlcpy(adouble_p, ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR )), sizeof(adouble_p));
344
345     if (for_each_adouble("setdirowner", ad_dir(adouble_p), setdirowner_ads_loop, &owner, noadouble)) 
346         return -1;
347
348     /*
349      * We cheat: we know that chown doesn't do anything.
350      */
351     if ( stat( ".AppleDouble", &st ) < 0) {
352         if (errno == ENOENT && noadouble)
353             return 0;
354         LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
355         return -1;
356     }
357     if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) {
358         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
359             uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
360         /* return ( -1 ); Sometimes this is okay */
361     }
362     return 0;
363 }
364
365 /* ------------------- */
366 static int RF_deletefile_ads(const struct vol *vol, const char *file )
367 {
368     char *ad_p = ad_dir(vol->vfs->ad_path(file, ADFLAGS_HF ));
369
370     return ads_delete_rf(ad_p);
371 }
372
373 /* --------------------------- */
374 int RF_renamefile_ads(const struct vol *vol, const char *src, const char *dst)
375 {
376     char  adsrc[ MAXPATHLEN + 1];
377     int   err = 0;
378
379     strcpy( adsrc, ad_dir(vol->vfs->ad_path( src, 0 )));
380     if (unix_rename( adsrc, ad_dir(vol->vfs->ad_path( dst, 0 ))) < 0) {
381         struct stat st;
382
383         err = errno;
384         if (errno == ENOENT) {
385                 struct adouble    ad;
386
387             if (stat(adsrc, &st)) /* source has no ressource fork, */
388                 return AFP_OK;
389             
390             /* We are here  because :
391              * -there's no dest folder. 
392              * -there's no .AppleDouble in the dest folder.
393              * if we use the struct adouble passed in parameter it will not
394              * create .AppleDouble if the file is already opened, so we
395              * use a diff one, it's not a pb,ie it's not the same file, yet.
396              */
397             ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
398             if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
399                 ad_close(&ad, ADFLAGS_HF);
400
401                 /* We must delete it */
402                 RF_deletefile_ads(vol, dst );
403                 if (!unix_rename( adsrc, ad_dir(vol->vfs->ad_path( dst, 0 ))) ) 
404                    err = 0;
405                 else 
406                    err = errno;
407             }
408             else { /* it's something else, bail out */
409                     err = errno;
410                 }
411             }
412         }
413         if (err) {
414                 errno = err;
415                 return -1;
416         }
417         return 0;
418 }
419
420 /* ===================================================
421  classic adouble format 
422 */
423
424 static int validupath_adouble(const struct vol *vol, const char *name) 
425 {
426     return (vol->v_flags & AFPVOL_USEDOTS) ? strncasecmp(name,".Apple", 6) && strcasecmp(name, ".Parent")
427                                            : name[0] != '.';
428 }
429
430 /* ----------------- */
431 static int RF_chown_adouble(const struct vol *vol, const char *path, uid_t uid, gid_t gid)
432
433 {
434     struct stat st;
435     char        *ad_p;
436
437     ad_p = vol->vfs->ad_path(path, ADFLAGS_HF );
438
439     if ( stat( ad_p, &st ) < 0 )
440         return 0; /* ignore */
441
442     return chown( ad_p, uid, gid );
443 }
444
445 /* ----------------- */
446 int RF_renamedir_adouble(const struct vol *vol _U_, const char *oldpath _U_, const char *newpath _U_)
447 {
448     return 0;
449 }
450
451 /* ----------------- */
452 static int deletecurdir_adouble_loop(struct dirent *de, char *name, void *data _U_, int flag _U_)
453 {
454     struct stat st;
455     int         err;
456     
457     /* bail if the file exists in the current directory.
458      * note: this will not fail with dangling symlinks */
459     
460     if (stat(de->d_name, &st) == 0)
461         return AFPERR_DIRNEMPT;
462
463     if ((err = netatalk_unlink(name)))
464         return err;
465
466     return 0;
467 }
468
469 static int RF_deletecurdir_adouble(const struct vol *vol _U_)
470 {
471     int err;
472
473     /* delete stray .AppleDouble files. this happens to get .Parent files
474        as well. */
475     if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_adouble_loop, NULL, 1))) 
476         return err;
477     return netatalk_rmdir( ".AppleDouble" );
478 }
479
480 /* ----------------- */
481 static int adouble_setfilmode(const char * name, mode_t mode, struct stat *st)
482 {
483     return setfilmode(name, ad_hf_mode(mode), st);
484 }
485
486 static int RF_setfilmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
487 {
488     return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_HF ), mode, st);
489 }
490
491 /* ----------------- */
492 static int RF_setdirunixmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
493 {
494     char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
495     int  dropbox = (vol->v_flags & AFPVOL_DROPBOX);
496
497     if (dir_rx_set(mode)) {
498         if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
499             return -1;
500     }
501
502     if (adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st) < 0) 
503         return -1;
504
505     if (!dir_rx_set(mode)) {
506         if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
507             return  -1 ;
508     }
509     return 0;
510 }
511
512 /* ----------------- */
513 static int setdirmode_adouble_loop(struct dirent *de _U_, char *name, void *data, int flag)
514 {
515     mode_t hf_mode = *(mode_t *)data;
516     struct stat st;
517
518     if ( stat( name, &st ) < 0 ) {
519         if (flag)
520             return 0;
521         LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", name, strerror(errno) );
522     }
523     else if (!S_ISDIR(st.st_mode)) {
524         if (setfilmode(name, hf_mode , &st) < 0) {
525                /* FIXME what do we do then? */
526         }
527     }
528     return 0;
529 }
530
531 static int RF_setdirmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st _U_)
532 {
533     int   dropbox = (vol->v_flags & AFPVOL_DROPBOX);
534     mode_t hf_mode = ad_hf_mode(mode);
535     char  *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
536     char  *adouble_p = ad_dir(adouble);
537
538     if (dir_rx_set(mode)) {
539         if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
540             return -1;
541     }
542
543     if (for_each_adouble("setdirmode", adouble_p, setdirmode_adouble_loop, &hf_mode, vol_noadouble(vol)))
544         return -1;
545
546     if (!dir_rx_set(mode)) {
547         if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) 
548             return  -1 ;
549     }
550     return 0;
551 }
552
553 /* ----------------- */
554 static int setdirowner_adouble_loop(struct dirent *de _U_, char *name, void *data, int flag _U_)
555 {
556     struct perm   *owner  = data;
557
558     if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
559          LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
560                 owner->uid, owner->gid, fullpathname(name), strerror(errno) );
561          /* return ( -1 ); Sometimes this is okay */
562     }
563     return 0;
564 }
565
566 static int RF_setdirowner_adouble(const struct vol *vol, const char *name, uid_t uid, gid_t gid)
567
568 {
569     int           noadouble = vol_noadouble(vol);
570     char          *adouble_p;
571     struct stat   st;
572     struct perm   owner;
573     
574     owner.uid = uid;
575     owner.gid = gid;
576
577     adouble_p = ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR ));
578
579     if (for_each_adouble("setdirowner", adouble_p, setdirowner_adouble_loop, &owner, noadouble)) 
580         return -1;
581
582     /*
583      * We cheat: we know that chown doesn't do anything.
584      */
585     if ( stat( ".AppleDouble", &st ) < 0) {
586         if (errno == ENOENT && noadouble)
587             return 0;
588         LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
589         return -1;
590     }
591     if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) {
592         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
593             uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
594         /* return ( -1 ); Sometimes this is okay */
595     }
596     return 0;
597 }
598
599 /* ----------------- */
600 static int RF_deletefile_adouble(const struct vol *vol, const char *file )
601 {
602         return netatalk_unlink(vol->vfs->ad_path( file, ADFLAGS_HF));
603 }
604
605 /* ----------------- */
606 int RF_renamefile_adouble(const struct vol *vol, const char *src, const char *dst)
607 {
608     char  adsrc[ MAXPATHLEN + 1];
609     int   err = 0;
610
611     strcpy( adsrc, vol->vfs->ad_path( src, 0 ));
612     if (unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) < 0) {
613         struct stat st;
614
615         err = errno;
616         if (errno == ENOENT) {
617                 struct adouble    ad;
618
619             if (stat(adsrc, &st)) /* source has no ressource fork, */
620                 return AFP_OK;
621             
622             /* We are here  because :
623              * -there's no dest folder. 
624              * -there's no .AppleDouble in the dest folder.
625              * if we use the struct adouble passed in parameter it will not
626              * create .AppleDouble if the file is already opened, so we
627              * use a diff one, it's not a pb,ie it's not the same file, yet.
628              */
629             ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
630             if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
631                 ad_close(&ad, ADFLAGS_HF);
632                 if (!unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) ) 
633                    err = 0;
634                 else 
635                    err = errno;
636             }
637             else { /* it's something else, bail out */
638                     err = errno;
639                 }
640             }
641         }
642         if (err) {
643                 errno = err;
644                 return -1;
645         }
646         return 0;
647 }
648
649 struct vfs_ops netatalk_adouble = {
650     /* ad_path:           */ ad_path,
651     /* validupath:        */ validupath_adouble,
652     /* rf_chown:          */ RF_chown_adouble,
653     /* rf_renamedir:      */ RF_renamedir_adouble,
654     /* rf_deletecurdir:   */ RF_deletecurdir_adouble,
655     /* rf_setfilmode:     */ RF_setfilmode_adouble,
656     /* rf_setdirmode:     */ RF_setdirmode_adouble,
657     /* rf_setdirunixmode: */ RF_setdirunixmode_adouble,
658     /* rf_setdirowner:    */ RF_setdirowner_adouble,
659     /* rf_deletefile:     */ RF_deletefile_adouble,
660     /* rf_renamefile:     */ RF_renamefile_adouble,
661 };
662
663 /* =======================================
664  osx adouble format 
665  */
666 static int validupath_osx(const struct vol *vol _U_, const char *name) 
667 {
668     return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2);
669 }
670
671 /* ---------------- */
672 int RF_renamedir_osx(const struct vol *vol, const char *oldpath, const char *newpath)
673 {
674     /* We simply move the corresponding ad file as well */
675     char   tempbuf[258]="._";
676     return rename(vol->vfs->ad_path(oldpath,0),strcat(tempbuf,newpath));
677 }
678
679 /* ---------------- */
680 int RF_deletecurdir_osx(const struct vol *vol)
681 {
682     return netatalk_unlink( vol->vfs->ad_path(".",0) );
683 }
684
685 /* ---------------- */
686 static int RF_setdirunixmode_osx(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
687 {
688     return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st);
689 }
690
691 /* ---------------- */
692 static int 
693 RF_setdirmode_osx(const struct vol *vol _U_, const char *name _U_, mode_t mode _U_, struct stat *st _U_)
694 {
695     return 0;
696 }
697
698 /* ---------------- */
699 static int 
700 RF_setdirowner_osx(const struct vol *vol _U_, const char *path _U_, uid_t uid _U_, gid_t gid _U_)
701 {
702         return 0;
703 }
704
705 /* ---------------- */
706 int RF_renamefile_osx(const struct vol *vol, const char *src, const char *dst)
707 {
708     char  adsrc[ MAXPATHLEN + 1];
709
710     strcpy( adsrc, vol->vfs->ad_path( src, 0 ));
711     return unix_rename( adsrc, vol->vfs->ad_path( dst, 0 ));
712 }
713
714 struct vfs_ops netatalk_adouble_osx = {
715     /* ad_path:          */ ad_path_osx,
716     /* validupath:       */ validupath_osx,
717     /* rf_chown:         */ RF_chown_adouble,
718     /* rf_renamedir:     */ RF_renamedir_osx,
719     /* rf_deletecurdir:  */ RF_deletecurdir_osx,
720     /* rf_setfilmode:    */ RF_setfilmode_adouble,
721     /* rf_setdirmode:    */ RF_setdirmode_osx,
722     /* rf_setdirunixmode:*/ RF_setdirunixmode_osx,
723     /* rf_setdirowner:   */ RF_setdirowner_osx,
724     /* rf_deletefile:    */ RF_deletefile_adouble,
725     /* rf_renamefile:    */ RF_renamefile_osx,
726 };
727
728 /* =======================================
729    samba ads format 
730  */
731 struct vfs_ops netatalk_adouble_ads = {
732     /* ad_path:          */ ad_path_ads,
733     /* validupath:       */ validupath_adouble,
734     /* rf_chown:         */ RF_chown_ads,
735     /* rf_renamedir:     */ RF_renamedir_adouble,
736     /* rf_deletecurdir:  */ RF_deletecurdir_ads,
737     /* rf_setfilmode:    */ RF_setfilmode_ads,
738     /* rf_setdirmode:    */ RF_setdirmode_ads,
739     /* rf_setdirunixmode:*/ RF_setdirunixmode_ads,
740     /* rf_setdirowner:   */ RF_setdirowner_ads,
741     /* rf_deletefile:    */ RF_deletefile_ads,
742     /* rf_renamefile:    */ RF_renamefile_ads,
743 };
744
745 /* =======================================
746    samba sfm format
747    ad_path shouldn't be set here
748  */
749 struct vfs_ops netatalk_adouble_sfm = {
750     /* ad_path:          */ ad_path_sfm,
751     /* validupath:       */ validupath_adouble,
752     /* rf_chown:         */ RF_chown_ads,
753     /* rf_renamedir:     */ RF_renamedir_adouble,
754     /* rf_deletecurdir:  */ RF_deletecurdir_ads,
755     /* rf_setfilmode:    */ RF_setfilmode_ads,
756     /* rf_setdirmode:    */ RF_setdirmode_ads,
757     /* rf_setdirunixmode:*/ RF_setdirunixmode_ads,
758     /* rf_setdirowner:   */ RF_setdirowner_ads,
759     /* rf_deletefile:    */ RF_deletefile_ads,
760     /* rf_renamefile:    */ RF_renamefile_ads,
761 };
762
763 /* ---------------- */
764 void initvol_vfs(struct vol *vol)
765 {
766     if (vol->v_adouble == AD_VERSION2_OSX) {
767         vol->vfs = &netatalk_adouble_osx;
768     }
769     else if (vol->v_adouble == AD_VERSION1_ADS) {
770         vol->vfs = &netatalk_adouble_ads;
771     }
772     else if (vol->v_adouble == AD_VERSION1_SFM) {
773         vol->vfs = &netatalk_adouble_sfm;
774     }
775     else {
776         vol->vfs = &netatalk_adouble;
777     }
778 }
779