First try for a netatalk vfs layer current schemes adouble=v1,v2 classic adouble format adouble=osx ._ OSX resource fork. adouble=ads NT like alternate data stream. Note for ads: * cf. patch.vfs for samba ADS vfs layer and patch.samba.xx for samba tree patch. * It's using Afp_AfpInfo name (MS SFM name) but it's not yet compatible with SFM. from cdrecord source code Afp_AfpInfo is the raw HFS data, we are storing an appledouble file. * Server side copy and Macintosh copy only deal with resource fork, other NT ADS are lost. unfixable for Macintosh copy but doable for server side. * It's ok for rename, delete, chown and chmod. * Copy from a NT box should work. * Last but not least : only on a new volume! TODO indirection for metadata, aka stored in EA, a different file, whatever. diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/Makefile.am ./etc/afpd/Makefile.am --- ../src.dev2/etc/afpd/Makefile.am Mon Feb 9 22:45:51 2004 +++ ./etc/afpd/Makefile.am Fri Jun 18 19:15:47 2004 @@ -8,14 +8,14 @@ file.c enumerate.c desktop.c filedir.c fork.c appl.c gettok.c \ mangle.c status.c afp_options.c afp_asp.c afp_dsi.c messages.c \ afp_config.c nfsquota.c quota.c uam.c afs.c uid.c afp_util.c \ - catsearch.c afprun.c + catsearch.c afprun.c vfs_adouble.c afpd_LDADD = $(top_builddir)/libatalk/cnid/libcnid.la $(top_builddir)/libatalk/libatalk.la afpd_LDFLAGS = -export-dynamic noinst_HEADERS = auth.h afp_config.h desktop.h directory.h file.h \ filedir.h fork.h globals.h icon.h mangle.h misc.h status.h switch.h \ - uam_auth.h uid.h unix.h volume.h + uam_auth.h uid.h unix.h volume.h afp_vfs.h LIBS = @LIBS@ @PAM_LIBS@ @QUOTA_LIBS@ @SLP_LIBS@ diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/afp_vfs.h ./etc/afpd/afp_vfs.h --- ../src.dev2/etc/afpd/afp_vfs.h Thu Jan 1 00:00:00 1970 +++ ./etc/afpd/afp_vfs.h Wed Jun 23 03:56:15 2004 @@ -0,0 +1,49 @@ +/* + Copyright (c) 2004 Didier Gautheron + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + vfs layer for afp +*/ + +#ifndef _AFP_VFS_H +#define _AFP_VFS_H + +#include +struct vol; + +struct vfs_ops { + /* low level adouble fn */ + char *(*ad_path)(const char *, int); + + /* */ + int (*validupath)(const struct vol *, const char *); + int (*rf_chown)(const struct vol *, const char *path, uid_t owner, gid_t group); + int (*rf_renamedir)(const struct vol *, const char *oldpath, const char *newpath); + int (*rf_deletecurdir)(const struct vol *); + int (*rf_setfilmode)(const struct vol *, const char * name, mode_t mode, struct stat *st); + int (*rf_setdirmode)(const struct vol *, const char * name, mode_t mode, struct stat *st); + int (*rf_setdirunixmode)(const struct vol *, const char * name, mode_t mode, struct stat *st); + + int (*rf_setdirowner)(const struct vol *, const char *path, uid_t owner, gid_t group); + + int (*rf_deletefile)(const struct vol *, const char * ); + int (*rf_renamefile)(const struct vol *, const char *oldpath, const char *newpath); + +}; + +void initvol_vfs(struct vol *vol); + +#endif diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/directory.c ./etc/afpd/directory.c --- ../src.dev2/etc/afpd/directory.c Mon Jul 12 08:46:03 2004 +++ ./etc/afpd/directory.c Sat Jun 19 14:07:14 2004 @@ -610,7 +610,7 @@ system rmdir with afp error code. ENOENT is not an error. */ -static int netatalk_rmdir(const char *name) +int netatalk_rmdir(const char *name) { if (rmdir(name) < 0) { switch ( errno ) { @@ -2075,15 +2075,11 @@ } } - if (vol->v_adouble == AD_VERSION2_OSX) { - /* We simply move the corresponding ad file as well */ - char tempbuf[258]="._"; - rename(vol->ad_path(src,0),strcat(tempbuf,dst)); - } + vol->vfs->rf_renamedir(vol, src, dst); len = strlen( newname ); /* rename() succeeded so we need to update our tree even if we can't open - * .Parent + * metadata */ ad_init(&ad, vol->v_adouble); @@ -2132,12 +2128,9 @@ return( AFP_OK ); } -#define DOT_APPLEDOUBLE_LEN 13 /* delete an empty directory */ -int deletecurdir( vol, path, pathlen ) +int deletecurdir( vol) const struct vol *vol; -char *path; -int pathlen; { struct dirent *de; struct stat st; @@ -2162,42 +2155,9 @@ return AFPERR_OLOCK; } } - - if (vol->v_adouble == AD_VERSION2_OSX) { - - if ((err = netatalk_unlink(vol->ad_path(".",0) )) ) { - return err; - } - } - else { - /* delete stray .AppleDouble files. this happens to get .Parent files - as well. */ - if ((dp = opendir(".AppleDouble"))) { - strcpy(path, ".AppleDouble/"); - while ((de = readdir(dp))) { - /* skip this and previous directory */ - if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) - continue; - - /* bail if the file exists in the current directory. - * note: this will not fail with dangling symlinks */ - if (stat(de->d_name, &st) == 0) { - closedir(dp); - return AFPERR_DIRNEMPT; - } - - strcpy(path + DOT_APPLEDOUBLE_LEN, de->d_name); - if ((err = netatalk_unlink(path))) { - closedir(dp); - return err; - } - } - closedir(dp); - } - - if ( (err = netatalk_rmdir( ".AppleDouble" )) ) { - return err; - } + err = vol->vfs->rf_deletecurdir(vol); + if (err) { + return err; } /* now get rid of dangling symlinks */ diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/directory.h ./etc/afpd/directory.h --- ../src.dev2/etc/afpd/directory.h Mon May 10 18:40:32 2004 +++ ./etc/afpd/directory.h Sat Jun 19 03:23:18 2004 @@ -196,7 +196,7 @@ extern struct dir *dirinsert __P((struct vol *, struct dir *)); extern int movecwd __P((const struct vol *, struct dir *)); -extern int deletecurdir __P((const struct vol *, char *, int)); +extern int deletecurdir __P((const struct vol *)); extern struct path *cname __P((const struct vol *, struct dir *, char **)); extern mode_t mtoumode __P((struct maccess *)); @@ -215,6 +215,7 @@ extern int check_access __P((char *name , int mode)); extern int file_access __P((struct path *path, int mode)); +extern int netatalk_rmdir __P((const char *name)); extern int netatalk_unlink __P((const char *name)); /* from enumerate.c */ diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/enumerate.c ./etc/afpd/enumerate.c --- ../src.dev2/etc/afpd/enumerate.c Mon Jul 12 08:46:03 2004 +++ ./etc/afpd/enumerate.c Thu Jun 24 04:26:35 2004 @@ -166,7 +166,7 @@ if (!strcmp(name, "..") || !strcmp(name, ".")) return NULL; - if (!vol->validupath(vol, name)) + if (!vol->vfs->validupath(vol, name)) return NULL; /* check for vetoed filenames */ diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/file.c ./etc/afpd/file.c --- ../src.dev2/etc/afpd/file.c Tue Jun 15 22:53:54 2004 +++ ./etc/afpd/file.c Mon Jun 21 00:21:24 2004 @@ -901,7 +901,7 @@ /* second try with adouble open */ - if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF, + if ( ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF, O_RDWR|O_CREAT, 0666, adp) < 0) { /* for some things, we don't need an adouble header */ if (f_bitmap & ~(1<ad_path( src, 0 )); - - if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) { - struct stat st; + if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) { int err; err = errno; - if (errno == ENOENT) { - struct adouble ad; - - if (stat(adsrc, &st)) /* source has no ressource fork, */ - return AFP_OK; - - /* We are here because : - * -there's no dest folder. - * -there's no .AppleDouble in the dest folder. - * if we use the struct adouble passed in parameter it will not - * create .AppleDouble if the file is already opened, so we - * use a diff one, it's not a pb,ie it's not the same file, yet. - */ - ad_init(&ad, vol->v_adouble); - if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) { - ad_close(&ad, ADFLAGS_HF); - if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) ) - err = 0; - else - err = errno; - } - else { /* it's something else, bail out */ - err = errno; - } - } /* try to undo the data fork rename, * we know we are on the same device */ @@ -1436,6 +1407,7 @@ if (ret_err) { deletefile(d_vol, dst, 0); } + /* ADS here */ /* set dest modification date to src date */ if (!stat(src, &st)) { @@ -1562,14 +1534,12 @@ if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) { err = AFPERR_BUSY; } - else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) && - !(err = netatalk_unlink( file )) ) { + else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) { cnid_t id; if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) { cnid_delete(vol->v_cdb, id); } - } if (adp) ad_close( &ad, adflags ); /* ad_close removes locks if any */ diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/filedir.c ./etc/afpd/filedir.c --- ../src.dev2/etc/afpd/filedir.c Mon May 10 18:40:32 2004 +++ ./etc/afpd/filedir.c Sat Jun 19 15:09:08 2004 @@ -73,7 +73,7 @@ return AFPERR_NOOBJ ; } - adpath = vol->ad_path( upath, ADFLAGS_HF ); + adpath = vol->vfs->ad_path( upath, ADFLAGS_HF ); /* FIXME dirsearch doesn't move cwd to did ! */ if (( dir = dirlookup( vol, did )) == NULL ) { LOG(log_error, logtype_afpd, "matchfile2dirperms: Unable to get directory info."); @@ -313,7 +313,7 @@ if ((vol->v_flags & AFPVOL_NOHEX) && strchr(name, '/')) return AFPERR_PARAM; - if (!vol->validupath(vol, name)) + if (!vol->vfs->validupath(vol, name)) return AFPERR_EXIST; /* check for vetoed filenames */ @@ -582,7 +582,7 @@ rc = AFPERR_ACCESS; } else { - rc = deletecurdir( vol, obj->oldtmp, AFPOBJ_TMPSIZ); + rc = deletecurdir( vol); } } else if (of_findname(s_path)) { rc = AFPERR_BUSY; @@ -764,7 +764,7 @@ int admode = ad_mode("", 0777); setfilmode(upath, admode, NULL); - setfilmode(vol->ad_path( upath, ADFLAGS_HF ), ad_hf_mode(admode), NULL); + vol->vfs->rf_setfilmode(vol, upath, admode, NULL); } setvoltime(obj, vol ); } diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/unix.c ./etc/afpd/unix.c --- ../src.dev2/etc/afpd/unix.c Tue Jun 15 22:53:55 2004 +++ ./etc/afpd/unix.c Wed Jun 23 04:04:01 2004 @@ -260,8 +260,8 @@ rwx-wx-wx or rwx-wx-- rwx----wx (is not asked by a Mac with OS >= 8.0 ?) */ -static int stickydirmode(name, mode, dropbox) -char * name; +int stickydirmode(name, mode, dropbox) +const char * name; const mode_t mode; const int dropbox; { @@ -405,12 +405,12 @@ if (setfilmode( path->u_name, mode, &path->st) < 0) return -1; /* we need to set write perm if read set for resource fork */ - return setfilmode(vol->ad_path( path->u_name, ADFLAGS_HF ), ad_hf_mode(mode), &path->st); + return vol->vfs->rf_setfilmode(vol, path->u_name, mode, &path->st); } /* --------------------- */ int setfilmode(name, mode, st) -char * name; +const char * name; mode_t mode; struct stat *st; { @@ -436,29 +436,18 @@ const char *name; const mode_t mode; { -char *adouble = vol->ad_path( name, ADFLAGS_DIR ); int dropbox = (vol->v_flags & AFPVOL_DROPBOX); if (dir_rx_set(mode)) { - /* extending right? dir first then .AppleDouble */ + /* extending right? dir first then .AppleDouble in rf_setdirmode */ if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 ) return -1; - if (vol->v_adouble != AD_VERSION2_OSX) { - if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) { - return -1 ; - } - } } - if (setfilmode(adouble, ad_hf_mode(mode), NULL) < 0 && !vol_noadouble(vol)) { + if (vol->vfs->rf_setdirunixmode(vol, name, mode, NULL) < 0 && !vol_noadouble(vol)) { return -1 ; } if (!dir_rx_set(mode)) { - if (vol->v_adouble != AD_VERSION2_OSX) { - if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) { - return -1 ; - } - } if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 ) return -1; } @@ -471,26 +460,17 @@ const char *name; const mode_t mode; { - char buf[ MAXPATHLEN + 1]; struct stat st; - char *m; struct dirent *dirp; DIR *dir; int osx = vol->v_adouble == AD_VERSION2_OSX; int hf_mode = ad_hf_mode(mode); int dropbox = (vol->v_flags & AFPVOL_DROPBOX); - char *adouble = vol->ad_path( name, ADFLAGS_DIR ); - char *adouble_p = ad_dir(adouble); if (dir_rx_set(mode)) { - /* extending right? dir first then .AppleDouble */ + /* extending right? dir first */ if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 ) return -1; - if (!osx) { - if (stickydirmode(adouble_p, DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) { - return -1 ; - } - } } if (( dir = opendir( name )) == NULL ) { @@ -516,61 +496,13 @@ return -1; } } -#if 0 - /* Don't change subdir perm */ - else if (S_ISDIR(st.st_mode)) { - if (stickydirmode(dirp->d_name, DIRBITS | mode, dropbox) < 0) - return (-1); - } else if (stickydirmode(dirp->d_name, mode, dropbox) < 0) - return (-1); - } -#endif } closedir( dir ); - if (osx) { - goto setdirmode_noadouble; - } - - /* change perm of .AppleDouble's files - */ - if (( dir = opendir( adouble_p )) == NULL ) { - if (vol_noadouble(vol)) - goto setdirmode_noadouble; - LOG(log_error, logtype_afpd, "setdirmode: opendir %s: %s", fullpathname(".AppleDouble"),strerror(errno) ); - return( -1 ); - } - strcpy( buf, adouble_p); - strcat( buf, "/" ); - m = strchr( buf, '\0' ); - for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) { - if ( strcmp( dirp->d_name, "." ) == 0 || - strcmp( dirp->d_name, ".." ) == 0 ) { - continue; - } - *m = '\0'; - strcat( buf, dirp->d_name ); - - if ( stat( buf, &st ) < 0 ) { - LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", buf, strerror(errno) ); - continue; - } - if (!S_ISDIR(st.st_mode)) { - if (setfilmode(buf, hf_mode , &st) < 0) { - /* FIXME what do we do then? */ - } - } - } /* end for */ - closedir( dir ); - - if (!dir_rx_set(mode)) { - /* XXX: need to preserve special modes */ - if (stickydirmode(adouble_p, DIRBITS | mode, dropbox) < 0 ) { - return -1 ; - } + if (vol->vfs->rf_setdirmode(vol, name, mode, NULL) < 0 && !vol_noadouble(vol)) { + return -1 ; } -setdirmode_noadouble: if (!dir_rx_set(mode)) { if ( stickydirmode(name, DIRBITS | mode, dropbox) < 0 ) return -1; @@ -578,6 +510,7 @@ return( 0 ); } +/* ----------------------------- */ int setdeskowner( uid, gid ) const uid_t uid; const gid_t gid; @@ -648,8 +581,6 @@ const gid_t gid; struct path* path; { - struct stat st; - char *ad_p; if (!path->st_valid) { of_stat(path); @@ -665,22 +596,15 @@ return -1; } - ad_p = vol->ad_path( path->u_name, ADFLAGS_HF ); - - if ( stat( ad_p, &st ) < 0 ) { - /* ignore */ - return 0; - } - if ( chown( ad_p, uid, gid ) < 0 && - errno != EPERM ) { - LOG(log_debug, logtype_afpd, "setfilowner: chown %d/%d %s: %s", - uid, gid, ad_p, strerror(errno) ); + if (vol->vfs->rf_chown(vol, path->u_name, uid, gid ) < 0 && errno != EPERM) { + LOG(log_debug, logtype_afpd, "setfilowner: rf_chown %d/%d %s: %s", + uid, gid, path->u_name, strerror(errno) ); return -1; } + return 0; } - /* --------------------------------- * uid/gid == 0 need to be handled as special cases. they really mean * that user/group should inherit from other, but that doesn't fit @@ -692,15 +616,10 @@ const uid_t uid; const gid_t gid; { - char buf[ MAXPATHLEN + 1]; struct stat st; - char *m; struct dirent *dirp; DIR *dir; int osx = vol->v_adouble == AD_VERSION2_OSX; - int noadouble = vol_noadouble(vol); - char *adouble; - char *adouble_p; if (( dir = opendir( name )) == NULL ) { return( -1 ); @@ -723,56 +642,15 @@ } } closedir( dir ); - - if (osx) { - goto setdirowner_noadouble; - } - adouble = vol->ad_path( name, ADFLAGS_DIR ); - adouble_p = ad_dir(adouble); - if (( dir = opendir( adouble_p )) == NULL ) { - if (noadouble) - goto setdirowner_noadouble; - return( -1 ); - } - strcpy( buf, adouble_p ); - strcat( buf, "/" ); - m = strchr( buf, '\0' ); - for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) { - if ( strcmp( dirp->d_name, "." ) == 0 || - strcmp( dirp->d_name, ".." ) == 0 ) { - continue; - } - *m = '\0'; - strcat( buf, dirp->d_name ); - if ( chown( buf, uid, gid ) < 0 && errno != EPERM ) { - LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", - uid, gid, fullpathname(buf), strerror(errno) ); - /* return ( -1 ); Sometimes this is okay */ - } - } - closedir( dir ); - - /* - * We cheat: we know that chown doesn't do anything. - */ - if ( stat( ".AppleDouble", &st ) < 0 ) { - LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) ); - return( -1 ); - } - if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && - errno != EPERM ) { - LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", - uid, gid,fullpathname(".AppleDouble"), strerror(errno) ); - /* return ( -1 ); Sometimes this is okay */ + if (vol->vfs->rf_setdirowner(vol, name, uid, gid) < 0) { + return -1; } - -setdirowner_noadouble: + if ( stat( ".", &st ) < 0 ) { return( -1 ); } - if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 && - errno != EPERM ) { + if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 && errno != EPERM ) { LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", uid, gid, fullpathname("."), strerror(errno) ); } diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/unix.h ./etc/afpd/unix.h --- ../src.dev2/etc/afpd/unix.h Mon May 10 18:40:33 2004 +++ ./etc/afpd/unix.h Wed Jun 23 03:43:28 2004 @@ -221,11 +221,12 @@ extern int setdirmode __P((const struct vol *, const char *, const mode_t)); extern int setdeskowner __P((const uid_t, const gid_t)); extern int setdirowner __P((const struct vol *, const char *, const uid_t, const gid_t)); -extern int setfilmode __P((char *, mode_t , struct stat *)); +extern int setfilmode __P((const char *, mode_t , struct stat *)); extern int setfilunixmode __P((const struct vol *, struct path*, const mode_t)); extern int setfilowner __P((const struct vol *, const uid_t, const gid_t, struct path*)); extern int unix_rename __P((const char *oldpath, const char *newpath)); extern int dir_rx_set __P((mode_t mode)); +extern int stickydirmode __P((const char * name, const mode_t mode, const int dropbox)); extern void accessmode __P((char *, struct maccess *, struct dir *, struct stat *)); extern char *fullpathname __P((const char *)); diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/vfs_adouble.c ./etc/afpd/vfs_adouble.c --- ../src.dev2/etc/afpd/vfs_adouble.c Thu Jan 1 00:00:00 1970 +++ ./etc/afpd/vfs_adouble.c Wed Jun 30 19:31:49 2004 @@ -0,0 +1,749 @@ +/* + Copyright (c) 2004 Didier Gautheron + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#ifdef STDC_HEADERS +#include +#endif + +#include + +#include +#include +#include + +#include "directory.h" +#include "volume.h" +#include "unix.h" + +struct perm { + uid_t uid; + gid_t gid; +}; + +typedef int (*rf_loop)(struct dirent *, char *, void *, int ); + +/* ----------------------------- */ +static int +for_each_adouble(const char *from, const char *name, rf_loop fn, void *data, int flag) +{ + char buf[ MAXPATHLEN + 1]; + char *m; + DIR *dp; + struct dirent *de; + int ret; + + + if (NULL == ( dp = opendir( name)) ) { + if (!flag) { + LOG(log_error, logtype_afpd, "%s: opendir %s: %s", from, fullpathname(name),strerror(errno) ); + return -1; + } + return 0; + } + strlcpy( buf, name, sizeof(buf)); + strlcat( buf, "/", sizeof(buf) ); + m = strchr( buf, '\0' ); + ret = 0; + while ((de = readdir(dp))) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { + continue; + } + + strlcat(buf, de->d_name, sizeof(buf)); + if (fn && (ret = fn(de, buf, data, flag))) { + closedir(dp); + return ret; + } + *m = 0; + } + closedir(dp); + return ret; +} + +/* ------------------------------ */ +static int ads_chown_loop(struct dirent *de, char *name, void *data, int flag) +{ + struct perm *owner = data; + + if (chown( name , owner->uid, owner->gid ) < 0) { + return -1; + } + return 0; +} + +static int RF_chown_ads(const struct vol *vol, const char *path, uid_t uid, gid_t gid) + +{ + struct stat st; + char *ad_p; + struct perm owner; + + owner.uid = uid; + owner.gid = gid; + + + ad_p = ad_dir(vol->vfs->ad_path(path, ADFLAGS_HF )); + + if ( stat( ad_p, &st ) < 0 ) { + /* ignore */ + return 0; + } + + if (chown( ad_p, uid, gid ) < 0) { + return -1; + } + return for_each_adouble("chown_ads", ad_p, ads_chown_loop, &owner, 1); +} + +/* --------------------------------- */ +static int deletecurdir_ads1_loop(struct dirent *de, char *name, void *data, int flag) +{ + return netatalk_unlink(name); +} + +static int ads_delete_rf(char *name) +{ + int err; + + if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1))) + return err; + return netatalk_rmdir(name); +} + +static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data, int flag) +{ + struct stat st; + + /* bail if the file exists in the current directory. + * note: this will not fail with dangling symlinks */ + + if (stat(de->d_name, &st) == 0) { + return AFPERR_DIRNEMPT; + } + return ads_delete_rf(name); +} + +static int RF_deletecurdir_ads(const struct vol *vol) +{ + int err; + + /* delete stray .AppleDouble files. this happens to get .Parent files as well. */ + if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_ads_loop, NULL, 1))) + return err; + return netatalk_rmdir( ".AppleDouble" ); +} + +/* ------------------- */ +struct set_mode { + mode_t mode; + struct stat *st; +}; + +static int ads_setfilmode_loop(struct dirent *de, char *name, void *data, int flag) +{ + struct set_mode *param = data; + + return setfilmode(name, param->mode, param->st); +} + +static int ads_setfilmode(const char * name, mode_t mode, struct stat *st) +{ + mode_t dir_mode = mode; + mode_t file_mode = ad_hf_mode(mode); + struct set_mode param; + + if ((dir_mode & (S_IRUSR | S_IWUSR ))) + dir_mode |= S_IXUSR; + if ((dir_mode & (S_IRGRP | S_IWGRP ))) + dir_mode |= S_IXGRP; + if ((dir_mode & (S_IROTH | S_IWOTH ))) + dir_mode |= S_IXOTH; + + /* change folder */ + dir_mode |= DIRBITS; + if (dir_rx_set(dir_mode)) { + if (chmod( name, dir_mode ) < 0) + return -1; + } + param.st = st; + param.mode = file_mode; + if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, ¶m, 0) < 0) + return -1; + + if (!dir_rx_set(dir_mode)) { + if (chmod( name, dir_mode ) < 0) + return -1; + } + + return 0; +} + +static int RF_setfilmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st) +{ + return ads_setfilmode(ad_dir(vol->vfs->ad_path( name, ADFLAGS_HF )), mode, st); +} + +/* ------------------- */ +static int RF_setdirunixmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st) +{ + char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR ); + char ad_p[ MAXPATHLEN + 1]; + int dropbox = (vol->v_flags & AFPVOL_DROPBOX); + + strlcpy(ad_p,ad_dir(adouble), MAXPATHLEN + 1); + + if (dir_rx_set(mode)) { + + /* .AppleDouble */ + if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) + return -1; + + /* .AppleDouble/.Parent */ + if (stickydirmode(ad_p, DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) + return -1; + } + + if (ads_setfilmode(ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR)), mode, st) < 0) + return -1; + + if (!dir_rx_set(mode)) { + if (stickydirmode(ad_p, DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) + return -1 ; + if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) + return -1; + } + return 0; +} + +/* ------------------- */ +struct dir_mode { + mode_t mode; + int dropbox; +}; + +static int setdirmode_ads_loop(struct dirent *de, char *name, void *data, int flag) +{ + + struct dir_mode *param = data; + int ret = 0; /* 0 ignore error, -1 */ + + if (dir_rx_set(param->mode)) { + if (stickydirmode(name, DIRBITS | param->mode, param->dropbox) < 0) { + if (flag) { + return 0; + } + return ret; + } + } + if (ads_setfilmode(name, param->mode, NULL) < 0) + return ret; + + if (!dir_rx_set(param->mode)) { + if (stickydirmode(name, DIRBITS | param->mode, param->dropbox) < 0) { + if (flag) { + return 0; + } + return ret; + } + } + return 0; +} + +static int RF_setdirmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st) +{ + char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR ); + char ad_p[ MAXPATHLEN + 1]; + struct dir_mode param; + + param.mode = mode; + param.dropbox = (vol->v_flags & AFPVOL_DROPBOX); + + strlcpy(ad_p,ad_dir(adouble), sizeof(ad_p)); + + if (dir_rx_set(mode)) { + /* .AppleDouble */ + if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox) < 0 && !vol_noadouble(vol)) + return -1; + } + + if (for_each_adouble("setdirmode_ads", ad_dir(ad_p), setdirmode_ads_loop, ¶m, vol_noadouble(vol))) + return -1; + + if (!dir_rx_set(mode)) { + if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox) < 0 && !vol_noadouble(vol)) + return -1; + } + return 0; +} + +/* ------------------- */ +static int setdirowner_ads1_loop(struct dirent *de, char *name, void *data, int flag) +{ + struct perm *owner = data; + + if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) { + LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", + owner->uid, owner->gid, fullpathname(name), strerror(errno) ); + /* return ( -1 ); Sometimes this is okay */ + } + return 0; +} + +static int setdirowner_ads_loop(struct dirent *de, char *name, void *data, int flag) +{ + struct perm *owner = data; + + if (for_each_adouble("setdirowner", name, setdirowner_ads1_loop, data, flag) < 0) + return -1; + + if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) { + LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", + owner->uid, owner->gid, fullpathname(name), strerror(errno) ); + /* return ( -1 ); Sometimes this is okay */ + } + return 0; +} + +static int RF_setdirowner_ads(const struct vol *vol, const char *name, uid_t uid, gid_t gid) +{ + int noadouble = vol_noadouble(vol); + char adouble_p[ MAXPATHLEN + 1]; + struct stat st; + struct perm owner; + + owner.uid = uid; + owner.gid = gid; + + strlcpy(adouble_p, ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR )), sizeof(adouble_p)); + + if (for_each_adouble("setdirowner", ad_dir(adouble_p), setdirowner_ads_loop, &owner, noadouble)) + return -1; + + /* + * We cheat: we know that chown doesn't do anything. + */ + if ( stat( ".AppleDouble", &st ) < 0) { + if (errno == ENOENT && noadouble) + return 0; + LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) ); + return -1; + } + if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) { + LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", + uid, gid,fullpathname(".AppleDouble"), strerror(errno) ); + /* return ( -1 ); Sometimes this is okay */ + } + return 0; +} + +/* ------------------- */ +static int RF_deletefile_ads(const struct vol *vol, const char *file ) +{ + char *ad_p = ad_dir(vol->vfs->ad_path(file, ADFLAGS_HF )); + + return ads_delete_rf(ad_p); +} + +/* --------------------------- */ +int RF_renamefile_ads(const struct vol *vol, const char *src, const char *dst) +{ + char adsrc[ MAXPATHLEN + 1]; + int err = 0; + + strcpy( adsrc, ad_dir(vol->vfs->ad_path( src, 0 ))); + if (unix_rename( adsrc, ad_dir(vol->vfs->ad_path( dst, 0 ))) < 0) { + struct stat st; + + err = errno; + if (errno == ENOENT) { + struct adouble ad; + + if (stat(adsrc, &st)) /* source has no ressource fork, */ + return AFP_OK; + + /* We are here because : + * -there's no dest folder. + * -there's no .AppleDouble in the dest folder. + * if we use the struct adouble passed in parameter it will not + * create .AppleDouble if the file is already opened, so we + * use a diff one, it's not a pb,ie it's not the same file, yet. + */ + ad_init(&ad, vol->v_adouble); + if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) { + ad_close(&ad, ADFLAGS_HF); + + /* We must delete it */ + RF_deletefile_ads(vol, dst ); + if (!unix_rename( adsrc, ad_dir(vol->vfs->ad_path( dst, 0 ))) ) + err = 0; + else + err = errno; + } + else { /* it's something else, bail out */ + err = errno; + } + } + } + if (err) { + errno = err; + return -1; + } + return 0; +} + +/* =================================================== + classic adouble format +*/ + +static int validupath_adouble(const struct vol *vol, const char *name) +{ + return (vol->v_flags & AFPVOL_USEDOTS) ? strncasecmp(name,".Apple", 6) && strcasecmp(name, ".Parent") + : name[0] != '.'; +} + +/* ----------------- */ +static int RF_chown_adouble(const struct vol *vol, const char *path, uid_t uid, gid_t gid) + +{ + struct stat st; + char *ad_p; + + ad_p = vol->vfs->ad_path(path, ADFLAGS_HF ); + + if ( stat( ad_p, &st ) < 0 ) + return 0; /* ignore */ + + return chown( ad_p, uid, gid ); +} + +/* ----------------- */ +int RF_renamedir_adouble(const struct vol *vol, const char *oldpath, const char *newpath) +{ + return 0; +} + +/* ----------------- */ +static int deletecurdir_adouble_loop(struct dirent *de, char *name, void *data, int flag) +{ + struct stat st; + int err; + + /* bail if the file exists in the current directory. + * note: this will not fail with dangling symlinks */ + + if (stat(de->d_name, &st) == 0) + return AFPERR_DIRNEMPT; + + if ((err = netatalk_unlink(name))) + return err; + + return 0; +} + +static int RF_deletecurdir_adouble(const struct vol *vol) +{ + int err; + + /* delete stray .AppleDouble files. this happens to get .Parent files + as well. */ + if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_adouble_loop, NULL, 1))) + return err; + return netatalk_rmdir( ".AppleDouble" ); +} + +/* ----------------- */ +static int adouble_setfilmode(const char * name, mode_t mode, struct stat *st) +{ + return setfilmode(name, ad_hf_mode(mode), st); +} + +static int RF_setfilmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st) +{ + return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_HF ), mode, st); +} + +/* ----------------- */ +static int RF_setdirunixmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st) +{ + char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR ); + int dropbox = (vol->v_flags & AFPVOL_DROPBOX); + + if (dir_rx_set(mode)) { + if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) + return -1; + } + + if (adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st) < 0) + return -1; + + if (!dir_rx_set(mode)) { + if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) + return -1 ; + } + return 0; +} + +/* ----------------- */ +static int setdirmode_adouble_loop(struct dirent *de, char *name, void *data, int flag) +{ + int hf_mode = *(int *)data; + struct stat st; + + if ( stat( name, &st ) < 0 ) { + if (flag) + return 0; + LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", name, strerror(errno) ); + } + else if (!S_ISDIR(st.st_mode)) { + if (setfilmode(name, hf_mode , &st) < 0) { + /* FIXME what do we do then? */ + } + } + return 0; +} + +static int RF_setdirmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st1) +{ + int dropbox = (vol->v_flags & AFPVOL_DROPBOX); + int hf_mode = ad_hf_mode(mode); + char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR ); + char *adouble_p = ad_dir(adouble); + + if (dir_rx_set(mode)) { + if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) + return -1; + } + + if (for_each_adouble("setdirmode", adouble_p, setdirmode_adouble_loop, &hf_mode, vol_noadouble(vol))) + return -1; + + if (!dir_rx_set(mode)) { + if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox) < 0 && !vol_noadouble(vol)) + return -1 ; + } + return 0; +} + +/* ----------------- */ +static int setdirowner_adouble_loop(struct dirent *de, char *name, void *data, int flag) +{ + struct perm *owner = data; + + if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) { + LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", + owner->uid, owner->gid, fullpathname(name), strerror(errno) ); + /* return ( -1 ); Sometimes this is okay */ + } + return 0; +} + +static int RF_setdirowner_adouble(const struct vol *vol, const char *name, uid_t uid, gid_t gid) + +{ + int noadouble = vol_noadouble(vol); + char *adouble_p; + struct stat st; + struct perm owner; + + owner.uid = uid; + owner.gid = gid; + + adouble_p = ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR )); + + if (for_each_adouble("setdirowner", adouble_p, setdirowner_adouble_loop, &owner, noadouble)) + return -1; + + /* + * We cheat: we know that chown doesn't do anything. + */ + if ( stat( ".AppleDouble", &st ) < 0) { + if (errno == ENOENT && noadouble) + return 0; + LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) ); + return -1; + } + if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) { + LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", + uid, gid,fullpathname(".AppleDouble"), strerror(errno) ); + /* return ( -1 ); Sometimes this is okay */ + } + return 0; +} + +/* ----------------- */ +static int RF_deletefile_adouble(const struct vol *vol, const char *file ) +{ + return netatalk_unlink(vol->vfs->ad_path( file, ADFLAGS_HF)); +} + +/* ----------------- */ +int RF_renamefile_adouble(const struct vol *vol, const char *src, const char *dst) +{ + char adsrc[ MAXPATHLEN + 1]; + int err = 0; + + strcpy( adsrc, vol->vfs->ad_path( src, 0 )); + if (unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) < 0) { + struct stat st; + + err = errno; + if (errno == ENOENT) { + struct adouble ad; + + if (stat(adsrc, &st)) /* source has no ressource fork, */ + return AFP_OK; + + /* We are here because : + * -there's no dest folder. + * -there's no .AppleDouble in the dest folder. + * if we use the struct adouble passed in parameter it will not + * create .AppleDouble if the file is already opened, so we + * use a diff one, it's not a pb,ie it's not the same file, yet. + */ + ad_init(&ad, vol->v_adouble); + if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) { + ad_close(&ad, ADFLAGS_HF); + if (!unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) ) + err = 0; + else + err = errno; + } + else { /* it's something else, bail out */ + err = errno; + } + } + } + if (err) { + errno = err; + return -1; + } + return 0; +} + +struct vfs_ops netatalk_adouble = { + /* ad_path: */ ad_path, + /* validupath: */ validupath_adouble, + /* rf_chown: */ RF_chown_adouble, + /* rf_renamedir: */ RF_renamedir_adouble, + /* rf_deletecurdir: */ RF_deletecurdir_adouble, + /* rf_setfilmode: */ RF_setfilmode_adouble, + /* rf_setdirmode: */ RF_setdirmode_adouble, + /* rf_setdirunixmode: */ RF_setdirunixmode_adouble, + /* rf_setdirowner: */ RF_setdirowner_adouble, + /* rf_deletefile: */ RF_deletefile_adouble, + /* rf_renamefile: */ RF_renamefile_adouble, +}; + +/* ======================================= + osx adouble format + */ +static int validupath_osx(const struct vol *vol, const char *name) +{ + return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2); +} + +/* ---------------- */ +int RF_renamedir_osx(const struct vol *vol, const char *oldpath, const char *newpath) +{ + /* We simply move the corresponding ad file as well */ + char tempbuf[258]="._"; + return rename(vol->vfs->ad_path(oldpath,0),strcat(tempbuf,newpath)); +} + +/* ---------------- */ +int RF_deletecurdir_osx(const struct vol *vol) +{ + return netatalk_unlink( vol->vfs->ad_path(".",0) ); +} + +/* ---------------- */ +static int RF_setdirunixmode_osx(const struct vol *vol, const char * name, mode_t mode, struct stat *st) +{ + return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st); +} + +/* ---------------- */ +static int RF_setdirmode_osx(const struct vol *vol, const char * name, mode_t mode, struct stat *st) +{ + return 0; +} + +/* ---------------- */ +static int RF_setdirowner_osx(const struct vol *vol, const char *path, uid_t uid, gid_t gid) +{ + return 0; +} + +/* ---------------- */ +int RF_renamefile_osx(const struct vol *vol, const char *src, const char *dst) +{ + char adsrc[ MAXPATHLEN + 1]; + + strcpy( adsrc, vol->vfs->ad_path( src, 0 )); + return unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )); +} + +struct vfs_ops netatalk_adouble_osx = { + /* ad_path: */ ad_path_osx, + /* validupath: */ validupath_osx, + /* rf_chown: */ RF_chown_adouble, + /* rf_renamedir: */ RF_renamedir_osx, + /* rf_deletecurdir: */ RF_deletecurdir_osx, + /* rf_setfilmode: */ RF_setfilmode_adouble, + /* rf_setdirmode: */ RF_setdirmode_osx, + /* rf_setdirunixmode:*/ RF_setdirunixmode_osx, + /* rf_setdirowner: */ RF_setdirowner_osx, + /* rf_deletefile: */ RF_deletefile_adouble, + /* rf_renamefile: */ RF_renamefile_osx, +}; + +/* ======================================= + samba ads format + */ +struct vfs_ops netatalk_adouble_ads = { + /* ad_path: */ ad_path_ads, + /* validupath: */ validupath_adouble, + /* rf_chown: */ RF_chown_ads, + /* rf_renamedir: */ RF_renamedir_adouble, + /* rf_deletecurdir: */ RF_deletecurdir_ads, + /* rf_setfilmode: */ RF_setfilmode_ads, + /* rf_setdirmode: */ RF_setdirmode_ads, + /* rf_setdirunixmode:*/ RF_setdirunixmode_ads, + /* rf_setdirowner: */ RF_setdirowner_ads, + /* rf_deletefile: */ RF_deletefile_ads, + /* rf_renamefile: */ RF_renamefile_ads, +}; + +/* ---------------- */ +void initvol_vfs(struct vol *vol) +{ + if (vol->v_adouble == AD_VERSION2_OSX) { + vol->vfs = &netatalk_adouble_osx; + } + else if (vol->v_adouble == AD_VERSION1_ADS) { + vol->vfs = &netatalk_adouble_ads; + } + else { + vol->vfs = &netatalk_adouble; + } +} + diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/volume.c ./etc/afpd/volume.c --- ../src.dev2/etc/afpd/volume.c Mon Jul 12 08:46:03 2004 +++ ./etc/afpd/volume.c Mon Jul 12 00:29:11 2004 @@ -427,6 +427,8 @@ options[VOLOPT_ADOUBLE].i_value = AD_VERSION2; else if (strcasecmp(val + 1, "osx") == 0) options[VOLOPT_ADOUBLE].i_value = AD_VERSION2_OSX; + else if (strcasecmp(val + 1, "ads") == 0) + options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_ADS; #endif } else if (optionok(tmp, "options:", val)) { char *p; @@ -523,34 +525,6 @@ } } -/* ----------------- - * FIXME should be define elsewhere -*/ -static int validupath_adouble(const struct vol *vol, const char *name) -{ - return (vol->v_flags & AFPVOL_USEDOTS) ? strncasecmp(name,".Apple", 6) && strcasecmp(name, ".Parent") - : name[0] != '.'; -} - -/* ----------------- */ -static int validupath_osx(const struct vol *vol, const char *name) -{ - return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2); -} - -/* ---------------- */ -static void initvoladouble(struct vol *vol) -{ - if (vol->v_adouble == AD_VERSION2_OSX) { - vol->validupath = validupath_osx; - vol->ad_path = ad_path_osx; - } - else { - vol->validupath = validupath_adouble; - vol->ad_path = ad_path; - } -} - /* ------------------------------- */ static int creatvol(AFPObj *obj, struct passwd *pwd, char *path, char *name, @@ -653,7 +627,8 @@ volume->v_adouble = options[VOLOPT_ADOUBLE].i_value; else volume->v_adouble = AD_VERSION; - initvoladouble(volume); + + initvol_vfs(volume); #ifdef FORCE_UIDGID if (options[VOLOPT_FORCEUID].c_value) { volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value); @@ -2231,6 +2206,9 @@ break; case AD_VERSION2_OSX: strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf)); + break; + case AD_VERSION1_ADS: + strlcat(buf, "ADOUBLE_VER:ads\n", sizeof(buf)); break; } diff -Nur -X .cvsignore -x CVS ../src.dev2/etc/afpd/volume.h ./etc/afpd/volume.h --- ../src.dev2/etc/afpd/volume.h Mon Jul 12 08:46:03 2004 +++ ./etc/afpd/volume.h Fri Jun 25 22:01:56 2004 @@ -14,6 +14,7 @@ #include "atalk/unicode.h" #include "globals.h" +#include "afp_vfs.h" #define AFPVOL_NAMELEN 27 @@ -75,6 +76,7 @@ int v_preexec_close; /* adouble indirection */ + struct vfs_ops *vfs; int (*validupath)(const struct vol *, const char *); char *(*ad_path)(const char *, int); }; diff -Nur -X .cvsignore -x CVS ../src.dev2/include/atalk/adouble.h ./include/atalk/adouble.h --- ../src.dev2/include/atalk/adouble.h Tue Jun 15 01:08:28 2004 +++ ./include/atalk/adouble.h Sun Jun 20 22:33:26 2004 @@ -82,6 +82,7 @@ #define AD_VERSION1 0x00010000 #define AD_VERSION2 0x00020000 #define AD_VERSION2_OSX 0x00020001 +#define AD_VERSION1_ADS 0x00010002 #define AD_VERSION AD_VERSION2 /* @@ -252,6 +253,7 @@ the header parameter size is too small. */ char *(*ad_path)(const char *, int); + int (*ad_mkrf)(char *); #ifdef USE_MMAPPED_HEADERS char *ad_data; @@ -364,6 +366,7 @@ extern char *ad_dir __P((const char *)); extern char *ad_path __P((const char *, int)); extern char *ad_path_osx __P((const char *, int)); +extern char *ad_path_ads __P((const char *, int)); extern int ad_mode __P((const char *, int)); extern int ad_mkdir __P((const char *, int)); diff -Nur -X .cvsignore -x CVS ../src.dev2/libatalk/adouble/ad_open.c ./libatalk/adouble/ad_open.c --- ../src.dev2/libatalk/adouble/ad_open.c Mon Jul 12 02:01:45 2004 +++ ./libatalk/adouble/ad_open.c Mon Jul 12 02:12:25 2004 @@ -697,6 +697,25 @@ return( pathbuf ); } +/* -------------------- */ +static int ad_mkrf(char *path) +{ + char *slash; + /* + * Probably .AppleDouble doesn't exist, try to mkdir it. + */ + if (NULL == ( slash = strrchr( path, '/' )) ) { + return -1; + } + *slash = '\0'; + errno = 0; + if ( ad_mkdir( path, 0777 ) < 0 ) { + return -1; + } + *slash = '/'; + return 0; +} + /* --------------------------------------- * Put the resource fork where it needs to be: * ._name @@ -729,8 +748,97 @@ strlcat( pathbuf, slash, MAXPATHLEN +1); return pathbuf; } +/* -------------------- */ +static int ad_mkrf_osx(char *path) +{ + return 0; +} -/* +/* --------------------------------------- + * Put the .AppleDouble where it needs to be: + * + * / a/.AppleDouble/b/Afp_AfpInfo + * a/b + * \ b/.AppleDouble/.Parent/Afp_AfpInfo + * + */ +char * +ad_path_ads( path, adflags ) + const char *path; + int adflags; +{ + static char pathbuf[ MAXPATHLEN + 1]; + char c, *slash, buf[MAXPATHLEN + 1]; + size_t l; + + l = strlcpy(buf, path, MAXPATHLEN +1); + if ( adflags & ADFLAGS_DIR ) { + strcpy( pathbuf, buf); + if ( *buf != '\0' && l < MAXPATHLEN) { + pathbuf[l++] = '/'; + pathbuf[l] = 0; + } + slash = ".Parent"; + } else { + if (NULL != ( slash = strrchr( buf, '/' )) ) { + c = *++slash; + *slash = '\0'; + strcpy( pathbuf, buf); + *slash = c; + } else { + pathbuf[ 0 ] = '\0'; + slash = buf; + } + } + strlcat( pathbuf, ".AppleDouble/", MAXPATHLEN +1); + strlcat( pathbuf, slash, MAXPATHLEN +1); + + strlcat( pathbuf, "/Afp_AfpInfo", MAXPATHLEN +1); + +#if 0 + if ((adflags & ADFLAGS_HF)) { + strlcat( pathbuf, "Afp_AfpInfo", MAXPATHLEN +1); + else { + strlcat( pathbuf, "Afp_Resource", MAXPATHLEN +1); + } +#endif + return( pathbuf ); +} + +/* -------------------- */ +static int ad_mkrf_ads(char *path) +{ + char *slash; + /* + * Probably .AppleDouble doesn't exist, try to mkdir it. + */ + if (NULL == ( slash = strrchr( path, '/' )) ) { + return -1; + } + *slash = 0; + errno = 0; + if ( ad_mkdir( path, 0777 ) < 0 ) { + if ( errno == ENOENT ) { + char *slash1; + + if (NULL == ( slash1 = strrchr( path, '/' )) ) + return -1; + errno = 0; + *slash1 = 0; + if ( ad_mkdir( path, 0777 ) < 0 ) + return -1; + *slash1 = '/'; + if ( ad_mkdir( path, 0777 ) < 0 ) + return -1; + } + else + return -1; + } + *slash = '/'; + return 0; +} + +/* ------------------------- * Support inherited protection modes for AppleDouble files. The supplied * mode is ANDed with the parent directory's mask value in lieu of "umask", * and that value is returned. @@ -914,10 +1022,16 @@ memset( ad, 0, sizeof( struct adouble ) ); ad->ad_flags = flags; if (flags == AD_VERSION2_OSX) { - ad->ad_path = ad_path_osx; + ad->ad_path = ad_path_osx; + ad->ad_mkrf = ad_mkrf_osx; + } + else if (flags == AD_VERSION1_ADS) { + ad->ad_path = ad_path_ads; + ad->ad_mkrf = ad_mkrf_ads; } else { - ad->ad_path = ad_path; + ad->ad_path = ad_path; + ad->ad_mkrf = ad_mkrf; } } @@ -931,7 +1045,7 @@ struct adouble *ad; { struct stat st; - char *slash, *ad_p; + char *ad_p; int hoflags, admode; int st_invalid; int open_df = 0; @@ -1031,19 +1145,9 @@ st_invalid = ad_mode_st(ad_p, &admode, &st); admode = ad_hf_mode(admode); if ( errno == ENOENT && !(adflags & ADFLAGS_NOADOUBLE) && ad->ad_flags != AD_VERSION2_OSX) { - /* - * Probably .AppleDouble doesn't exist, try to - * mkdir it. - */ - if (NULL == ( slash = strrchr( ad_p, '/' )) ) { - return ad_error(ad, adflags); - } - *slash = '\0'; - errno = 0; - if ( ad_mkdir( ad_p, 0777 ) < 0 ) { + if (ad->ad_mkrf( ad_p) < 0) { return ad_error(ad, adflags); - } - *slash = '/'; + } admode = mode; st_invalid = ad_mode_st(ad_p, &admode, &st); admode = ad_hf_mode(admode);