]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/vfs_adouble.c
remove a spurious error msg if noadouble option is set
[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;
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) 
225             return -1;
226
227         /* .AppleDouble/.Parent */
228         if (stickydirmode(ad_p, DIRBITS | mode, dropbox) < 0) 
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) 
237             return  -1 ;
238         if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox) < 0) 
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;
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) 
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 ) 
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) ?
427          strcasecmp(name,".AppleDB") &&
428          strcasecmp(name,".AppleDouble") &&
429          strcasecmp(name,".AppleDesktop") &&
430          strcasecmp(name,".Parent")
431                                            : name[0] != '.';
432 }
433
434 /* ----------------- */
435 static int RF_chown_adouble(const struct vol *vol, const char *path, uid_t uid, gid_t gid)
436
437 {
438     struct stat st;
439     char        *ad_p;
440
441     ad_p = vol->vfs->ad_path(path, ADFLAGS_HF );
442
443     if ( stat( ad_p, &st ) < 0 )
444         return 0; /* ignore */
445
446     return chown( ad_p, uid, gid );
447 }
448
449 /* ----------------- */
450 int RF_renamedir_adouble(const struct vol *vol _U_, const char *oldpath _U_, const char *newpath _U_)
451 {
452     return 0;
453 }
454
455 /* ----------------- */
456 static int deletecurdir_adouble_loop(struct dirent *de, char *name, void *data _U_, int flag _U_)
457 {
458     struct stat st;
459     int         err;
460     
461     /* bail if the file exists in the current directory.
462      * note: this will not fail with dangling symlinks */
463     
464     if (stat(de->d_name, &st) == 0)
465         return AFPERR_DIRNEMPT;
466
467     if ((err = netatalk_unlink(name)))
468         return err;
469
470     return 0;
471 }
472
473 static int RF_deletecurdir_adouble(const struct vol *vol _U_)
474 {
475     int err;
476
477     /* delete stray .AppleDouble files. this happens to get .Parent files
478        as well. */
479     if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_adouble_loop, NULL, 1))) 
480         return err;
481     return netatalk_rmdir( ".AppleDouble" );
482 }
483
484 /* ----------------- */
485 static int adouble_setfilmode(const char * name, mode_t mode, struct stat *st)
486 {
487     return setfilmode(name, ad_hf_mode(mode), st);
488 }
489
490 static int RF_setfilmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
491 {
492     return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_HF ), mode, st);
493 }
494
495 /* ----------------- */
496 static int RF_setdirunixmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
497 {
498     char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
499     int  dropbox = vol->v_flags;
500
501     if (dir_rx_set(mode)) {
502         if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 ) 
503             return -1;
504     }
505
506     if (adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st) < 0) 
507         return -1;
508
509     if (!dir_rx_set(mode)) {
510         if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 ) 
511             return  -1 ;
512     }
513     return 0;
514 }
515
516 /* ----------------- */
517 static int setdirmode_adouble_loop(struct dirent *de _U_, char *name, void *data, int flag)
518 {
519     mode_t hf_mode = *(mode_t *)data;
520     struct stat st;
521
522     if ( stat( name, &st ) < 0 ) {
523         if (flag)
524             return 0;
525         LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", name, strerror(errno) );
526     }
527     else if (!S_ISDIR(st.st_mode)) {
528         if (setfilmode(name, hf_mode , &st) < 0) {
529                /* FIXME what do we do then? */
530         }
531     }
532     return 0;
533 }
534
535 static int RF_setdirmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st _U_)
536 {
537     int   dropbox = vol->v_flags;
538     mode_t hf_mode = ad_hf_mode(mode);
539     char  *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
540     char  *adouble_p = ad_dir(adouble);
541
542     if (dir_rx_set(mode)) {
543         if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0) 
544             return -1;
545     }
546
547     if (for_each_adouble("setdirmode", adouble_p, setdirmode_adouble_loop, &hf_mode, vol_noadouble(vol)))
548         return -1;
549
550     if (!dir_rx_set(mode)) {
551         if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0) 
552             return  -1 ;
553     }
554     return 0;
555 }
556
557 /* ----------------- */
558 static int setdirowner_adouble_loop(struct dirent *de _U_, char *name, void *data, int flag _U_)
559 {
560     struct perm   *owner  = data;
561
562     if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
563          LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
564                 owner->uid, owner->gid, fullpathname(name), strerror(errno) );
565          /* return ( -1 ); Sometimes this is okay */
566     }
567     return 0;
568 }
569
570 static int RF_setdirowner_adouble(const struct vol *vol, const char *name, uid_t uid, gid_t gid)
571
572 {
573     int           noadouble = vol_noadouble(vol);
574     char          *adouble_p;
575     struct stat   st;
576     struct perm   owner;
577     
578     owner.uid = uid;
579     owner.gid = gid;
580
581     adouble_p = ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR ));
582
583     if (for_each_adouble("setdirowner", adouble_p, setdirowner_adouble_loop, &owner, noadouble)) 
584         return -1;
585
586     /*
587      * We cheat: we know that chown doesn't do anything.
588      */
589     if ( stat( ".AppleDouble", &st ) < 0) {
590         if (errno == ENOENT && noadouble)
591             return 0;
592         LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
593         return -1;
594     }
595     if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) {
596         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
597             uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
598         /* return ( -1 ); Sometimes this is okay */
599     }
600     return 0;
601 }
602
603 /* ----------------- */
604 static int RF_deletefile_adouble(const struct vol *vol, const char *file )
605 {
606         return netatalk_unlink(vol->vfs->ad_path( file, ADFLAGS_HF));
607 }
608
609 /* ----------------- */
610 int RF_renamefile_adouble(const struct vol *vol, const char *src, const char *dst)
611 {
612     char  adsrc[ MAXPATHLEN + 1];
613     int   err = 0;
614
615     strcpy( adsrc, vol->vfs->ad_path( src, 0 ));
616     if (unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) < 0) {
617         struct stat st;
618
619         err = errno;
620         if (errno == ENOENT) {
621                 struct adouble    ad;
622
623             if (stat(adsrc, &st)) /* source has no ressource fork, */
624                 return AFP_OK;
625             
626             /* We are here  because :
627              * -there's no dest folder. 
628              * -there's no .AppleDouble in the dest folder.
629              * if we use the struct adouble passed in parameter it will not
630              * create .AppleDouble if the file is already opened, so we
631              * use a diff one, it's not a pb,ie it's not the same file, yet.
632              */
633             ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
634             if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
635                 ad_close(&ad, ADFLAGS_HF);
636                 if (!unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) ) 
637                    err = 0;
638                 else 
639                    err = errno;
640             }
641             else { /* it's something else, bail out */
642                     err = errno;
643                 }
644             }
645         }
646         if (err) {
647                 errno = err;
648                 return -1;
649         }
650         return 0;
651 }
652
653 struct vfs_ops netatalk_adouble = {
654     /* ad_path:           */ ad_path,
655     /* validupath:        */ validupath_adouble,
656     /* rf_chown:          */ RF_chown_adouble,
657     /* rf_renamedir:      */ RF_renamedir_adouble,
658     /* rf_deletecurdir:   */ RF_deletecurdir_adouble,
659     /* rf_setfilmode:     */ RF_setfilmode_adouble,
660     /* rf_setdirmode:     */ RF_setdirmode_adouble,
661     /* rf_setdirunixmode: */ RF_setdirunixmode_adouble,
662     /* rf_setdirowner:    */ RF_setdirowner_adouble,
663     /* rf_deletefile:     */ RF_deletefile_adouble,
664     /* rf_renamefile:     */ RF_renamefile_adouble,
665 };
666
667 /* =======================================
668  osx adouble format 
669  */
670 static int validupath_osx(const struct vol *vol _U_, const char *name) 
671 {
672     return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2);
673 }
674
675 /* ---------------- */
676 int RF_renamedir_osx(const struct vol *vol, const char *oldpath, const char *newpath)
677 {
678     /* We simply move the corresponding ad file as well */
679     char   tempbuf[258]="._";
680     return rename(vol->vfs->ad_path(oldpath,0),strcat(tempbuf,newpath));
681 }
682
683 /* ---------------- */
684 int RF_deletecurdir_osx(const struct vol *vol)
685 {
686     return netatalk_unlink( vol->vfs->ad_path(".",0) );
687 }
688
689 /* ---------------- */
690 static int RF_setdirunixmode_osx(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
691 {
692     return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st);
693 }
694
695 /* ---------------- */
696 static int 
697 RF_setdirmode_osx(const struct vol *vol _U_, const char *name _U_, mode_t mode _U_, struct stat *st _U_)
698 {
699     return 0;
700 }
701
702 /* ---------------- */
703 static int 
704 RF_setdirowner_osx(const struct vol *vol _U_, const char *path _U_, uid_t uid _U_, gid_t gid _U_)
705 {
706         return 0;
707 }
708
709 /* ---------------- */
710 int RF_renamefile_osx(const struct vol *vol, const char *src, const char *dst)
711 {
712     char  adsrc[ MAXPATHLEN + 1];
713
714     strcpy( adsrc, vol->vfs->ad_path( src, 0 ));
715     return unix_rename( adsrc, vol->vfs->ad_path( dst, 0 ));
716 }
717
718 struct vfs_ops netatalk_adouble_osx = {
719     /* ad_path:          */ ad_path_osx,
720     /* validupath:       */ validupath_osx,
721     /* rf_chown:         */ RF_chown_adouble,
722     /* rf_renamedir:     */ RF_renamedir_osx,
723     /* rf_deletecurdir:  */ RF_deletecurdir_osx,
724     /* rf_setfilmode:    */ RF_setfilmode_adouble,
725     /* rf_setdirmode:    */ RF_setdirmode_osx,
726     /* rf_setdirunixmode:*/ RF_setdirunixmode_osx,
727     /* rf_setdirowner:   */ RF_setdirowner_osx,
728     /* rf_deletefile:    */ RF_deletefile_adouble,
729     /* rf_renamefile:    */ RF_renamefile_osx,
730 };
731
732 /* =======================================
733    samba ads format 
734  */
735 struct vfs_ops netatalk_adouble_ads = {
736     /* ad_path:          */ ad_path_ads,
737     /* validupath:       */ validupath_adouble,
738     /* rf_chown:         */ RF_chown_ads,
739     /* rf_renamedir:     */ RF_renamedir_adouble,
740     /* rf_deletecurdir:  */ RF_deletecurdir_ads,
741     /* rf_setfilmode:    */ RF_setfilmode_ads,
742     /* rf_setdirmode:    */ RF_setdirmode_ads,
743     /* rf_setdirunixmode:*/ RF_setdirunixmode_ads,
744     /* rf_setdirowner:   */ RF_setdirowner_ads,
745     /* rf_deletefile:    */ RF_deletefile_ads,
746     /* rf_renamefile:    */ RF_renamefile_ads,
747 };
748
749 /* =======================================
750    samba sfm format
751    ad_path shouldn't be set here
752  */
753 struct vfs_ops netatalk_adouble_sfm = {
754     /* ad_path:          */ ad_path_sfm,
755     /* validupath:       */ validupath_adouble,
756     /* rf_chown:         */ RF_chown_ads,
757     /* rf_renamedir:     */ RF_renamedir_adouble,
758     /* rf_deletecurdir:  */ RF_deletecurdir_ads,
759     /* rf_setfilmode:    */ RF_setfilmode_ads,
760     /* rf_setdirmode:    */ RF_setdirmode_ads,
761     /* rf_setdirunixmode:*/ RF_setdirunixmode_ads,
762     /* rf_setdirowner:   */ RF_setdirowner_ads,
763     /* rf_deletefile:    */ RF_deletefile_ads,
764     /* rf_renamefile:    */ RF_renamefile_ads,
765 };
766
767 /* ---------------- */
768 void initvol_vfs(struct vol *vol)
769 {
770     if (vol->v_adouble == AD_VERSION2_OSX) {
771         vol->vfs = &netatalk_adouble_osx;
772     }
773     else if (vol->v_adouble == AD_VERSION1_ADS) {
774         vol->vfs = &netatalk_adouble_ads;
775     }
776     else if (vol->v_adouble == AD_VERSION1_SFM) {
777         vol->vfs = &netatalk_adouble_sfm;
778     }
779     else {
780         vol->vfs = &netatalk_adouble;
781     }
782 }
783