+++ /dev/null
-First try for a netatalk vfs layer
-
-current schemes
-adouble=v1,v2 classic adouble format
-adouble=osx ._<filename> 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 <atalk/adouble.h>
-+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<<FILPBIT_MDATE)) {
-@@ -1020,7 +1020,6 @@
- char *src, *dst, *newname;
- struct adouble *adp;
- {
-- char adsrc[ MAXPATHLEN + 1];
- int rc;
-
- #ifdef DEBUG
-@@ -1055,38 +1054,10 @@
- }
- }
-
-- strcpy( adsrc, vol->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 <string.h>
-+#endif
-+
-+#include <stdio.h>
-+
-+#include <atalk/adouble.h>
-+#include <atalk/logger.h>
-+#include <atalk/util.h>
-+
-+#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);
+++ /dev/null
-diff -Nur vfs/Makefile vfs.new/Makefile
---- vfs/Makefile Thu Jan 1 00:00:00 1970
-+++ vfs.new/Makefile Mon Jul 12 10:48:56 2004
-@@ -0,0 +1,40 @@
-+##########################################################################
-+# Makefile for Samba VFS modules
-+###########################################################################
-+
-+CC=gcc -g
-+LIBTOOL=/usr/bin/libtool
-+# REPLACE with samba source
-+SMB=/u/redhat/paris/cvs/samba/smb3.0a20
-+
-+# REPLACE with samba build folder
-+BUILD=/mnt/hdd/build/smb.1.3
-+
-+CFLAGS=-Wall -I $(BUILD)/include \
-+-I$(SMB)/source -I$(SMB)/source/include -I$(SMB)/source/ubiqx -I$(SMB)/source/smbwrapper
-+
-+
-+LDFLAGS=-shared
-+
-+VFS_OBJS=vfs_ads.so
-+
-+SHELL=/bin/sh
-+
-+default: $(VFS_OBJS)
-+
-+# Pattern rules
-+
-+%.so: %.lo
-+ @echo Linking $<
-+ @$(LIBTOOL) --mode=link $(CC) -o $@ $< $(LDFLAGS)
-+
-+%.lo: %.c
-+ @echo Compiling $<
-+ @$(LIBTOOL) --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
-+
-+# Misc targets
-+
-+clean:
-+ rm -rf .libs */.libs
-+ rm -f core *~ *% *.bak *.o */*.o *.lo $(VFS_OBJS)
-+
-diff -Nur vfs/README vfs.new/README
---- vfs/README Thu Jan 1 00:00:00 1970
-+++ vfs.new/README Tue Jul 13 02:28:21 2004
-@@ -0,0 +1,34 @@
-+This a vfs for NT ADS
-+you must set SMB and BUILD variables in Makefile.
-+
-+old smb.conf
-+[test_ads]
-+ comment = test ADS Mac/PC directory
-+ path=/home/test_ads/
-+# /.AppleD* is mandatory
-+ veto files = /.AppleD*/Network Trash Folder/Icon\r/
-+ delete veto files = True
-+# full path to vfs_ads.so
-+ vfs object = /usr/src/samba/vfs/vfs_ads.so
-+ browseable = yes
-+ writable = yes
-+
-+new one (current svn tree)
-+copy vfs_ads.so as ads.so in <prefix>/lib/vfs/
-+eg
-+cp vfs_ads.so /opt/lib/vfs/ads.so
-+
-+smb.conf
-+[test_ads]
-+ comment = test ADS Mac/PC directory
-+ path=/home/test_ads/
-+
-+# /.AppleD* is mandatory
-+ veto files = /.AppleD*/Network Trash Folder/Icon\r/
-+ delete veto files = True
-+ vfs objects = ads
-+ browseable = yes
-+ writable = yes
-+
-+
-+Didier
-diff -Nur vfs/vfs_ads.c vfs.new/vfs_ads.c
---- vfs/vfs_ads.c Thu Jan 1 00:00:00 1970
-+++ vfs.new/vfs_ads.c Wed Jul 14 16:37:15 2004
-@@ -0,0 +1,1029 @@
-+/*
-+ * CAP VFS module for Samba 3.x Version 0.3
-+ *
-+ * Copyright (C) Tim Potter, 1999-2000
-+ * Copyright (C) Alexander Bokovoy, 2002-2003
-+ * Copyright (C) Stefan (metze) Metzmacher, 2003
-+ * Copyright (C) TAKAHASHI Motonobu (monyo), 2003
-+ *
-+ * 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.
-+ *
-+ * modified for alternate data stream
-+ * Copyright (C) Didier Gautheron 2004
-+ *
-+ * this module should compile with old 3.0 API and 2004-07 svn API
-+ */
-+
-+
-+#include "includes.h"
-+
-+#undef DBGC_CLASS
-+#define DBGC_CLASS DBGC_VFS
-+
-+#define ADS_FOLDER ".AppleDouble"
-+#define ADOUBLEMODE 0777
-+
-+/* FIXME found a better test */
-+#ifdef SMB_VFS_OP
-+#define ADS_NEW_MODULE
-+
-+/* for current svn tree */
-+#define ADS_TALLOC_INIT(a) talloc_init(a)
-+
-+#define HANDLE_PARAMETER vfs_handle_struct *handle,
-+#define HANDLE handle,
-+
-+/* ------------------- */
-+#else
-+
-+#define ADS_TALLOC_INIT(a) talloc_init()
-+
-+#define HANDLE_PARAMETER
-+#define HANDLE
-+
-+/* VFS operations */
-+static struct vfs_ops default_vfs_ops; /* For passthrough operation */
-+static struct smb_vfs_handle_struct *ads_handle;
-+
-+#define SMB_VFS_NEXT_DISK_FREE(a,b,c,d,e,f,g) default_vfs_ops.disk_free(b,c,d,e,f,g)
-+#define SMB_VFS_NEXT_OPENDIR(a,b,c) default_vfs_ops.opendir(b,c)
-+#define SMB_VFS_NEXT_READDIR(a,b,c) default_vfs_ops.readdir(b,c)
-+#define SMB_VFS_NEXT_MKDIR(a,b,c,d) default_vfs_ops.mkdir(b,c,d)
-+#define SMB_VFS_NEXT_RMDIR(a,b,c) default_vfs_ops.rmdir(b,c)
-+#define SMB_VFS_NEXT_OPEN(a,b,c,d,e) default_vfs_ops.open(b,c,d,e)
-+#define SMB_VFS_NEXT_RENAME(a,b,c,d) default_vfs_ops.rename(b,c,d)
-+#define SMB_VFS_NEXT_STAT(a,b,c,d) default_vfs_ops.stat(b,c,d)
-+#define SMB_VFS_NEXT_LSTAT(a,b,c,d) default_vfs_ops.lstat(b,c,d)
-+#define SMB_VFS_NEXT_UNLINK(a,b,c) default_vfs_ops.unlink(b,c)
-+#define SMB_VFS_NEXT_CHMOD(a,b,c,d) default_vfs_ops.chmod(b,c,d)
-+#define SMB_VFS_NEXT_CHOWN(a,b,c,d,e) default_vfs_ops.chown(b,c,d,e)
-+#define SMB_VFS_NEXT_CHDIR(a,b,c) default_vfs_ops.chdir(b,c)
-+#define SMB_VFS_NEXT_UTIME(a,b,c,d) default_vfs_ops.utime(b,c,d)
-+#define SMB_VFS_NEXT_SYMLINK(a,b,c,d) default_vfs_ops.symlink(b,c,d)
-+#define SMB_VFS_NEXT_READLINK(a,b,c,d,e) default_vfs_ops.readlink(b,c,d,e)
-+#define SMB_VFS_NEXT_LINK(a,b,c,d) default_vfs_ops.link(b,c,d)
-+#define SMB_VFS_NEXT_MKNOD(a,b,c,d,e) default_vfs_ops.mknod(b,c,d,e)
-+#define SMB_VFS_NEXT_REALPATH(a,b,c,d) default_vfs_ops.realpath(b,c,d)
-+#define SMB_VFS_NEXT_SET_NT_ACL(a,b,c,d,e) default_vfs_ops.set_nt_acl(b,c,d,e)
-+#define SMB_VFS_NEXT_CHMOD_ACL(a,b,c,d) default_vfs_ops.chmod_acl(b,c,d)
-+#define SMB_VFS_NEXT_SYS_ACL_GET_FILE(a,b,c,d) default_vfs_ops.sys_acl_get_file(b,c,d)
-+#define SMB_VFS_NEXT_SYS_ACL_SET_FILE(a,b,c,d,e) default_vfs_ops.sys_acl_set_file(b,c,d,e)
-+#define SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(a,b,c) default_vfs_ops.sys_acl_delete_def_file(b,c)
-+/* ads functions */
-+
-+#endif
-+
-+/* -------------------------
-+ * format
-+ * .AppleDouble/filename/stream name
-+ *
-+ * return the *LAST* '/' in path
-+ */
-+static int ads_get_path_ptr(char *path)
-+{
-+ int i = 0;
-+ int ptr = 0;
-+
-+ for (i = 0; path[i]; i ++) {
-+ if (path[i] == '/')
-+ ptr = i;
-+ }
-+
-+ return ptr;
-+}
-+
-+/* ------------------------------
-+ * return the *FIRST* ':' in path
-+*/
-+static int ads_get_stream_ptr(const char *path)
-+{
-+ int i = 0;
-+ int ptr = 0;
-+
-+ for (i = 0; path[i]; i ++) {
-+ if (path[i] == ':') {
-+ ptr = i;
-+ break;
-+ }
-+ }
-+ return ptr;
-+}
-+
-+/* ----------------
-+ * fname is only a filename
-+*/
-+
-+static char *ads_canonical_dir(TALLOC_CTX *ctx, const char *path, const char *fname, int isdir)
-+{
-+ if (isdir) {
-+ return talloc_asprintf(ctx, "%s/%s/%s/.Parent", path, fname, ADS_FOLDER);
-+ }
-+ return talloc_asprintf(ctx, "%s/%s/%s", path, ADS_FOLDER, fname);
-+
-+}
-+
-+/* ----------------
-+ * return directory pathname for an alternate data stream
-+ * fname is *NOT* an altername name (ie foo:bar)
-+*/
-+static char *ads_dir(TALLOC_CTX *ctx, const char *path, const char *fname, int isdir)
-+{
-+ int ptr0 = 0;
-+ int ptr1 = 0;
-+ char *temp;
-+
-+#if 0
-+ if (fname[0] == '.') ptr0 ++;
-+ if (fname[1] == '/') ptr0 ++;
-+#endif
-+ temp = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]);
-+ ptr1 = ads_get_path_ptr(temp);
-+ temp[ptr1] = '\0';
-+ return ads_canonical_dir(ctx, temp, &temp[ptr1 + 1], isdir);
-+}
-+
-+/* ----------------------------------
-+ * build the pathname for stream, create folder if (mode & O_CREAT)
-+ * return -1 on error
-+ * 0 it's not a stream
-+ * 1 it's a stream
-+ *
-+ * main_path : file fullpathname with :$DATA removed
-+ * ads_path: unix pathname
-+ * if it's not an ADS then main_path == ads_path
-+ *
-+ */
-+static int ads_build_paths(TALLOC_CTX *ctx, const char *path, const char *fname,
-+ char **ads_path, char **main_path, SMB_STRUCT_STAT **main_info, int flag)
-+{
-+ int ret = 0;
-+ int ptr0 = 0;
-+ int ptr1 = 0;
-+ int ptr2 = 0;
-+ int ptr3 = 0;
-+ char *dname = 0;
-+ char *name = 0;
-+ SMB_STRUCT_STAT ads_info;
-+
-+ if (!ctx || !path || !fname || !ads_path || !main_path || !main_info || !*main_info)
-+ return -1;
-+#if 1
-+ DEBUG(3, ("ADS: PATH: %s[%s]\n", path, fname));
-+#endif
-+ if (strstr(path, ADS_FOLDER) || strstr(fname, ADS_FOLDER)) {
-+ DEBUG(1, ("ADS: path %s[%s] already contains %s\n", path, fname, ADS_FOLDER));
-+ return -1;
-+ }
-+
-+#if 0
-+ if (fname[0] == '.') ptr0 ++;
-+ if (fname[1] == '/') ptr0 ++;
-+#endif
-+
-+ *main_path = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]);
-+ *ads_path = NULL;
-+
-+ /* get pointer to last '/' */
-+ ptr1 = ads_get_path_ptr(*main_path);
-+ ptr2 = ads_get_stream_ptr(*main_path +ptr1 +1);
-+ /* FIXME
-+ * what about ::$DATA or :name:$DATA
-+ */
-+
-+ if (ptr2) {
-+ /* it's an alternate stream */
-+ ptr2 += ptr1 +1;
-+ (*main_path)[ptr2] = 0;
-+ ptr3 = ads_get_stream_ptr(*main_path +ptr2 +1);
-+ if (ptr3) {
-+ ptr3 += ptr2 +1;
-+ /* check it's $DATA */
-+ if (!strcmp("$DATA", &(*main_path)[ptr3+1])) {
-+ (*main_path)[ptr3] = 0;
-+ }
-+ }
-+
-+ DEBUG(3, ("ADS: MAIN DATA %s\n", *main_path));
-+
-+ if (sys_lstat(*main_path, *main_info) < 0) {
-+ /* if we can't get the main file give up */
-+ return -1;
-+ }
-+ (*main_path)[ptr2] = ':';
-+ dname = talloc_strdup(ctx, *main_path);
-+ dname[ptr1] = '\0';
-+ name = *main_path;
-+ name[ptr2] = '\0';
-+ if (S_ISDIR((*main_info)->st_mode)) {
-+ *ads_path = talloc_asprintf(ctx, "%s/%s/%s/.Parent/%s", dname, &name[ptr1 + 1], ADS_FOLDER, &name[ptr2 + 1]);
-+ }
-+ else {
-+ *ads_path = talloc_asprintf(ctx, "%s/%s/%s/%s", dname, ADS_FOLDER, &name[ptr1 + 1], &name[ptr2 + 1]);
-+ }
-+ /* XXX are we always the right user ?*/
-+ if (sys_lstat(*ads_path, &ads_info) < 0) {
-+ int st_ret;
-+ /* */
-+ if (errno == ENOENT && (flag & O_CREAT)) {
-+ char *ads_base = ads_canonical_dir(ctx, dname, &name[ptr1 + 1], S_ISDIR((*main_info)->st_mode));
-+ mode_t mode;
-+
-+ st_ret = mkdir(ads_base, 0777);
-+ if (st_ret < 0) {
-+ if (errno == ENOENT) {
-+ char *ads_double;
-+ if (S_ISDIR((*main_info)->st_mode)) {
-+ ads_double = talloc_asprintf(ctx, "%s/%s/%s", dname, &name[ptr1 + 1], ADS_FOLDER);
-+ }
-+ else {
-+ ads_double = talloc_asprintf(ctx, "%s/%s", dname, ADS_FOLDER);
-+ }
-+ if (mkdir(ads_double, 0777) < 0)
-+ return -1;
-+ if ((st_ret = mkdir(ads_base, 0777)) < 0)
-+ return -1;
-+
-+ /* we just created .AppleDouble/file/ update mode with dir search
-+ * XXX what about acl?
-+ */
-+ mode = (*main_info)->st_mode;
-+ if ((mode & (S_IRUSR | S_IWUSR )))
-+ mode |= S_IXUSR;
-+ if ((mode & (S_IRGRP | S_IWGRP )))
-+ mode |= S_IXGRP;
-+ if ((mode & (S_IROTH | S_IWOTH )))
-+ mode |= S_IXOTH;
-+ chmod(ads_base, mode);
-+ }
-+ else
-+ errno = ENOENT;
-+ }
-+ }
-+ else
-+ return -1;
-+ }
-+ ret = 1;
-+ }
-+ else {
-+ *ads_path = *main_path;
-+ if (sys_lstat(*main_path, *main_info) < 0) {
-+ *main_info = NULL;
-+ }
-+ }
-+#if 1
-+ DEBUG(3, ("ADS: DEBUG:[%s] [%s]\n", *main_path, *ads_path));
-+#endif
-+ return ret;
-+}
-+
-+/* ------------------------ */
-+static SMB_BIG_UINT ads_disk_free(HANDLE_PARAMETER connection_struct *conn, const char *path,
-+ BOOL small_query, SMB_BIG_UINT *bsize,
-+ SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
-+{
-+ return SMB_VFS_NEXT_DISK_FREE(handle, conn, path, small_query, bsize, dfree, dsize);
-+}
-+
-+static DIR *ads_opendir(HANDLE_PARAMETER connection_struct *conn, const char *fname)
-+{
-+ return SMB_VFS_NEXT_OPENDIR(handle, conn, fname);
-+}
-+
-+static struct dirent *ads_readdir(HANDLE_PARAMETER connection_struct *conn, DIR *dirp)
-+{
-+ struct dirent *result;
-+ DEBUG(3,("ads: ads_readdir\n"));
-+ result = SMB_VFS_NEXT_READDIR(handle, conn, dirp);
-+ if (result) {
-+ DEBUG(3,("ads: ads_readdir: %s\n", result->d_name));
-+ }
-+ return result;
-+}
-+
-+/* ------------------------- */
-+static int ads_mkdir(HANDLE_PARAMETER connection_struct *conn, const char *path, mode_t mode)
-+{
-+ return SMB_VFS_NEXT_MKDIR(handle, conn, path, mode);
-+}
-+
-+/* ------------------------- */
-+static int unlink_file(const char *path)
-+{
-+int ret = 0;
-+
-+ become_root();
-+ ret = unlink(path);
-+ unbecome_root();
-+ return ret;
-+}
-+
-+/* ------------------------- */
-+static int unlink_folder(const char *path)
-+{
-+int ret = 0;
-+
-+ become_root();
-+ ret = rmdir(path);
-+ unbecome_root();
-+ return ret;
-+}
-+
-+/* -------------------------
-+ remove all files in an AppleDouble folder
-+*/
-+static void rrmdir(TALLOC_CTX *ctx, char *path)
-+{
-+ int n;
-+ char *dpath;
-+ struct dirent **namelist;
-+
-+ if (!path) return;
-+
-+ n = scandir(path, &namelist, 0, alphasort);
-+ if (n < 0) {
-+ return;
-+ }
-+ while (n --) {
-+ if (strcmp(namelist[n]->d_name, ".") == 0 || strcmp(namelist[n]->d_name, "..") == 0) {
-+ free(namelist[n]);
-+ continue;
-+ }
-+ if ((dpath = talloc_asprintf(ctx, "%s/%s",path, namelist[n]->d_name))) {
-+ unlink_file(dpath);
-+ }
-+ free(namelist[n]);
-+ }
-+ free(namelist);
-+ unlink_folder(path);
-+}
-+
-+/* --------------------------- */
-+static void rrm_adsdir(TALLOC_CTX *ctx, char *path)
-+{
-+ int n;
-+ char *dpath;
-+ struct dirent **namelist;
-+
-+ if (!path) return;
-+
-+ n = scandir(path, &namelist, 0, alphasort);
-+ if (n < 0) {
-+ return;
-+ }
-+ while (n --) {
-+ if (strcmp(namelist[n]->d_name, ".") == 0 || strcmp(namelist[n]->d_name, "..") == 0) {
-+ free(namelist[n]);
-+ continue;
-+ }
-+ if ((dpath = talloc_asprintf(ctx, "%s/%s",path, namelist[n]->d_name))) {
-+ rrmdir(ctx, dpath);
-+ }
-+ free(namelist[n]);
-+ }
-+ free(namelist);
-+ unlink_folder(path);
-+}
-+
-+/* -------------------------
-+ * XXX
-+ * if in smb.conf there's :
-+ * delete veto files = True
-+ * veto files = /.AppleD* /
-+*/
-+static int ads_rmdir( HANDLE_PARAMETER connection_struct *conn, const char *path)
-+{
-+ BOOL add = False;
-+ TALLOC_CTX *ctx = 0;
-+ char *dpath;
-+ int ret = 0;
-+
-+ if (!conn || !conn->origpath || !path) goto exit_rmdir;
-+
-+ /* .AppleD* */
-+ strstr(path, ADS_FOLDER) ? (add = False) : (add = True);
-+
-+ if (!(ctx = ADS_TALLOC_INIT("ads_rmdir")))
-+ goto exit_rmdir;
-+
-+ if (!(dpath = talloc_asprintf(ctx, "%s/%s%s",conn->origpath, path, add ? "/"ADS_FOLDER : "")))
-+ goto exit_rmdir;
-+
-+ /* remove folder .AppleDouble */
-+ rrm_adsdir(ctx, dpath);
-+
-+exit_rmdir:
-+ ret = SMB_VFS_NEXT_RMDIR(handle, conn, path);
-+ talloc_destroy(ctx);
-+
-+ return ret;
-+}
-+
-+/* ------------------------- */
-+static int ads_open(HANDLE_PARAMETER connection_struct *conn, const char *fname, int flags, mode_t mode)
-+{
-+ int ret = 0;
-+ char *ads_path = 0;
-+ char *main_path = 0;
-+ TALLOC_CTX *ctx;
-+ SMB_STRUCT_STAT st;
-+ SMB_STRUCT_STAT *main_info = &st;
-+
-+ DEBUG(3,("ads: ads_open for %s %x\n", fname, flags));
-+ if (!(ctx = ADS_TALLOC_INIT("ads_open")))
-+ return -1;
-+ /* convert to */
-+ if (ads_build_paths(ctx, conn->origpath, fname, &ads_path, &main_path, &main_info, flags) < 0) {
-+ talloc_destroy(ctx);
-+ return -1;
-+ }
-+
-+ ret = SMB_VFS_NEXT_OPEN(handle, conn, ads_path, flags, mode);
-+ talloc_destroy(ctx);
-+ return ret;
-+
-+}
-+
-+static int isDir(SMB_STRUCT_STAT *st)
-+{
-+ if (st == NULL) {
-+ return 0;
-+ }
-+ return S_ISDIR(st->st_mode);
-+}
-+
-+/* ------------------------- */
-+static int ads_rename(HANDLE_PARAMETER connection_struct *conn, const char *old, const char *new)
-+{
-+ int ret = 0;
-+ TALLOC_CTX *ctx;
-+ char *ads_path = 0;
-+ char *main_path = 0;
-+ SMB_STRUCT_STAT st;
-+ SMB_STRUCT_STAT *main_info = &st;
-+
-+ DEBUG(3,("ads: ads_rename %s --> %sx\n", old, new));
-+
-+ if (!(ctx = ADS_TALLOC_INIT("ads_rename")))
-+ return -1;
-+
-+ if (ads_build_paths(ctx, conn->origpath, old, &ads_path, &main_path, &main_info, 0) < 0) {
-+ talloc_destroy(ctx);
-+ return -1;
-+ }
-+
-+ if (ads_path != main_path) {
-+ /* you can't rename an ads ! */
-+ talloc_destroy(ctx);
-+ errno = EINVAL;
-+ return -1;
-+ }
-+
-+ ret = SMB_VFS_NEXT_RENAME(handle, conn, old, new);
-+ if (!ret && !isDir(main_info)) {
-+ int ptr1;
-+ int ptr2;
-+
-+ char *ads_old = ads_dir(ctx, conn->origpath, old, 0);
-+ char *ads_new = ads_dir(ctx, conn->origpath, new, 0);
-+
-+ /* is dest folder .Adouble there ? */
-+ ptr1 = ads_get_path_ptr(ads_new);
-+ ptr2 = ads_get_path_ptr(ads_old);
-+
-+ ads_new[ptr1] = '\0';
-+ ads_old[ptr2] = '\0';
-+ if (strcmp(ads_new, ads_old)) {
-+ mkdir(ads_new, 0777);
-+ }
-+
-+ ads_new[ptr1] = '/';
-+ ads_old[ptr2] = '/';
-+
-+ SMB_VFS_NEXT_RENAME(handle, conn, ads_old, ads_new);
-+ }
-+
-+ talloc_destroy(ctx);
-+ return ret;
-+}
-+
-+/* -------------------------
-+ * For an ADS what do we need to return , ADS ? main DATA?
-+*/
-+static int ads_stat(HANDLE_PARAMETER connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf)
-+{
-+ int ret = 0;
-+ char *ads_path = 0;
-+ char *main_path = 0;
-+ TALLOC_CTX *ctx;
-+ SMB_STRUCT_STAT st;
-+ SMB_STRUCT_STAT *main_info = &st;
-+
-+ DEBUG(3,("ads: ads_stat for %s\n", fname));
-+
-+ if (!(ctx = ADS_TALLOC_INIT("ads_stat")))
-+ return -1;
-+ /* which inode ?
-+ */
-+ if (ads_build_paths(ctx, conn->origpath, fname, &ads_path, &main_path, &main_info, 0) < 0) {
-+ talloc_destroy(ctx);
-+ return -1;
-+ }
-+
-+ ret = SMB_VFS_NEXT_STAT(handle, conn, ads_path, sbuf);
-+ talloc_destroy(ctx);
-+ return ret;
-+}
-+
-+/* ------------------------- */
-+static int ads_lstat(HANDLE_PARAMETER connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
-+{
-+ int ret = 0;
-+ char *ads_path = 0;
-+ char *main_path = 0;
-+ TALLOC_CTX *ctx;
-+ SMB_STRUCT_STAT st;
-+ SMB_STRUCT_STAT *main_info = &st;
-+
-+ if (!(ctx = ADS_TALLOC_INIT("ads_lstat")))
-+ return -1;
-+ /* which inode ?
-+ */
-+ if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) {
-+ talloc_destroy(ctx);
-+ return -1;
-+ }
-+
-+ return SMB_VFS_NEXT_LSTAT(handle, conn, ads_path, sbuf);
-+ talloc_destroy(ctx);
-+ return ret;
-+}
-+
-+/* ------------------------- */
-+static int ads_unlink(HANDLE_PARAMETER connection_struct *conn, const char *path)
-+{
-+ int ret = 0;
-+
-+ char *ads_path = 0;
-+ char *main_path = 0;
-+ TALLOC_CTX *ctx;
-+ SMB_STRUCT_STAT st;
-+ SMB_STRUCT_STAT *main_info = &st;
-+
-+ DEBUG(3,("ads: ads_unlink %s\n", path));
-+ if (!(ctx = ADS_TALLOC_INIT("ads_unlink")))
-+ return -1;
-+
-+ if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) {
-+ talloc_destroy(ctx);
-+ return -1;
-+ }
-+
-+ ret = SMB_VFS_NEXT_UNLINK(handle, conn, ads_path);
-+ /*
-+ if data stream
-+ for each stream
-+ unlink
-+ */
-+ if (!ret && ads_path == main_path) {
-+ char *ads_base = ads_dir(ctx, conn->origpath, path, isDir(main_info));
-+ struct dirent *dent = 0;
-+ DIR *dir = opendir(ads_base);
-+
-+ if (dir) {
-+ char *dpath;
-+
-+ while (NULL != (dent = readdir(dir))) {
-+ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
-+ continue;
-+ if (!(dpath = talloc_asprintf(ctx, "%s/%s", ads_base, dent->d_name)))
-+ continue;
-+ /* XXX need to be root ? */
-+ SMB_VFS_NEXT_UNLINK(handle, conn, dpath);
-+ }
-+ closedir(dir);
-+ rmdir(ads_base);
-+ }
-+ }
-+
-+ talloc_destroy(ctx);
-+ return ret;
-+}
-+
-+/* ------------------------- */
-+static int ads_chmod(HANDLE_PARAMETER connection_struct *conn, const char *path, mode_t mode)
-+{
-+ int ret = 0;
-+ char *ads_path = 0;
-+ char *main_path = 0;
-+ TALLOC_CTX *ctx;
-+ SMB_STRUCT_STAT st;
-+ SMB_STRUCT_STAT *main_info = &st;
-+
-+ DEBUG(3,("ads: ads_chmod %s\n", path));
-+ /* if stream
-+ error ?, change only the stream
-+ */
-+ if (!(ctx = ADS_TALLOC_INIT("ads_chmod")))
-+ return -1;
-+
-+ if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) {
-+ talloc_destroy(ctx);
-+ return -1;
-+ }
-+
-+ ret = SMB_VFS_NEXT_CHMOD(handle, conn, ads_path, mode);
-+ /*
-+ if data stream
-+ for each stream
-+ chmod
-+ */
-+ if (!ret && ads_path == main_path) {
-+ char *ads_base = ads_dir(ctx, conn->origpath, path, isDir(main_info));
-+ struct dirent *dent = 0;
-+ DIR *dir = opendir(ads_base);
-+
-+ if (dir) {
-+ char *dpath;
-+
-+ while (NULL != (dent = readdir(dir))) {
-+ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
-+ continue;
-+ if (!(dpath = talloc_asprintf(ctx, "%s/%s", ads_base, dent->d_name)))
-+ continue;
-+ /* XXX need to be root ? */
-+ SMB_VFS_NEXT_CHMOD(handle, conn, dpath, mode);
-+ }
-+ closedir(dir);
-+ /* XXX need to change ads_base too*/
-+ }
-+ }
-+
-+ talloc_destroy(ctx);
-+ return ret;
-+}
-+
-+/* ------------------------- */
-+static int ads_chown(HANDLE_PARAMETER connection_struct *conn, const char *path, uid_t uid, gid_t gid)
-+{
-+ int ret = 0;
-+ char *ads_path = 0;
-+ char *main_path = 0;
-+ TALLOC_CTX *ctx;
-+ SMB_STRUCT_STAT st;
-+ SMB_STRUCT_STAT *main_info = &st;
-+
-+ DEBUG(3,("ads: ads_chown %s\n", path));
-+ /* if stream
-+ error ?, change only the stream
-+ */
-+ if (!(ctx = ADS_TALLOC_INIT("ads_chown")))
-+ return -1;
-+
-+ if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) {
-+ talloc_destroy(ctx);
-+ return -1;
-+ }
-+
-+ ret = SMB_VFS_NEXT_CHOWN(handle, conn, ads_path, uid, gid);
-+ /* if data stream
-+ for each stream
-+ chmod
-+ */
-+ if (!ret && ads_path == main_path) {
-+ char *ads_base = ads_dir(ctx, conn->origpath, path, isDir(main_info));
-+ struct dirent *dent = 0;
-+ DIR *dir = opendir(ads_base);
-+
-+ if (dir) {
-+ char *dpath;
-+
-+ while (NULL != (dent = readdir(dir))) {
-+ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
-+ continue;
-+ if (!(dpath = talloc_asprintf(ctx, "%s/%s", ads_base, dent->d_name)))
-+ continue;
-+ /* XXX need to be root ?, what do we do in case of error? */
-+ SMB_VFS_NEXT_CHOWN(handle, conn, dpath, uid, gid);
-+ }
-+ closedir(dir);
-+ SMB_VFS_NEXT_CHOWN(handle, conn, ads_path, uid, gid);
-+ }
-+ }
-+
-+ talloc_destroy(ctx);
-+ return ret;
-+}
-+
-+/* ------------------------- */
-+static int ads_chdir(HANDLE_PARAMETER connection_struct *conn, const char *path)
-+{
-+ DEBUG(3,("ads: ads_chdir for %s\n", path));
-+ return SMB_VFS_NEXT_CHDIR(handle, conn, path);
-+}
-+
-+static int ads_utime(HANDLE_PARAMETER connection_struct *conn, const char *path, struct utimbuf *times)
-+{
-+ return SMB_VFS_NEXT_UTIME(handle, conn, path, times);
-+}
-+
-+
-+static BOOL ads_symlink(HANDLE_PARAMETER connection_struct *conn, const char *oldpath, const char *newpath)
-+{
-+ return SMB_VFS_NEXT_SYMLINK(handle, conn, oldpath, newpath);
-+}
-+
-+static BOOL ads_readlink(HANDLE_PARAMETER connection_struct *conn, const char *path, char *buf, size_t bufsiz)
-+{
-+ return SMB_VFS_NEXT_READLINK(handle, conn, path, buf, bufsiz);
-+}
-+
-+static int ads_link( HANDLE_PARAMETER connection_struct *conn, const char *oldpath, const char *newpath)
-+{
-+ return SMB_VFS_NEXT_LINK(handle, conn, oldpath, newpath);
-+}
-+
-+static int ads_mknod(HANDLE_PARAMETER connection_struct *conn, const char *path, mode_t mode, SMB_DEV_T dev)
-+{
-+ return SMB_VFS_NEXT_MKNOD(handle, conn, path, mode, dev);
-+}
-+
-+static char *ads_realpath(HANDLE_PARAMETER connection_struct *conn, const char *path, char *resolved_path)
-+{
-+ return SMB_VFS_NEXT_REALPATH(handle, conn, path, resolved_path);
-+}
-+
-+static BOOL ads_set_nt_acl(HANDLE_PARAMETER files_struct *fsp, const char *name, uint32 security_info_sent, struct security_descriptor_info *psd)
-+{
-+ return SMB_VFS_NEXT_SET_NT_ACL(handle, fsp, name, security_info_sent, psd);
-+}
-+
-+static int ads_chmod_acl(HANDLE_PARAMETER connection_struct *conn, const char *name, mode_t mode)
-+{
-+ /* If the underlying VFS doesn't have ACL support... */
-+#ifdef ADS_NEW_MODULE
-+ if (!handle->vfs_next.ops.chmod_acl) {
-+#else
-+ if (!default_vfs_ops.chmod_acl) {
-+#endif
-+ errno = ENOSYS;
-+ return -1;
-+ }
-+ return SMB_VFS_NEXT_CHMOD_ACL(handle, conn, name, mode);
-+}
-+
-+static SMB_ACL_T ads_sys_acl_get_file(HANDLE_PARAMETER connection_struct *conn, const char *path_p, SMB_ACL_TYPE_T type)
-+{
-+ return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, conn, path_p, type);
-+}
-+
-+static int ads_sys_acl_set_file(HANDLE_PARAMETER connection_struct *conn, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
-+{
-+ return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, conn, name, acltype, theacl);
-+}
-+
-+static int ads_sys_acl_delete_def_file(HANDLE_PARAMETER connection_struct *conn, const char *path)
-+{
-+ return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, conn, path);
-+}
-+
-+#ifdef ADS_NEW_MODULE
-+static ssize_t ads_getxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, void *value, size_t size)
-+{
-+ return SMB_VFS_NEXT_GETXATTR(handle, conn, path, name, value, size);
-+}
-+
-+static ssize_t ads_lgetxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, void *value, size_t
-+size)
-+{
-+ return SMB_VFS_NEXT_LGETXATTR(handle, conn, path, name, value, size);
-+}
-+
-+static ssize_t ads_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, void *value, size_t size)
-+{
-+ return SMB_VFS_NEXT_FGETXATTR(handle, fsp, fd, name, value, size);
-+}
-+
-+static ssize_t ads_listxattr(vfs_handle_struct *handle, connection_struct *conn,const char *path, char *list, size_t size)
-+{
-+ return SMB_VFS_NEXT_LISTXATTR(handle, conn, path, list, size);
-+}
-+
-+static ssize_t ads_llistxattr(vfs_handle_struct *handle,struct connection_struct *conn,const char *path, char *list, size_t size)
-+{
-+ return SMB_VFS_NEXT_LLISTXATTR(handle, conn, path, list, size);
-+}
-+
-+static int ads_removexattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name)
-+{
-+ return SMB_VFS_NEXT_REMOVEXATTR(handle, conn, path, name);
-+}
-+
-+static int ads_lremovexattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name)
-+{
-+ return SMB_VFS_NEXT_LREMOVEXATTR(handle, conn, path, name);
-+}
-+
-+static int ads_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name)
-+{
-+ return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, fd, name);
-+}
-+
-+static int ads_setxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags)
-+{
-+ return SMB_VFS_NEXT_SETXATTR(handle, conn, path, name, value, size, flags);
-+}
-+
-+static int ads_lsetxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags)
-+{
-+ return SMB_VFS_NEXT_LSETXATTR(handle, conn, path, name, value, size, flags);
-+}
-+
-+static int ads_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, const void *value, size_t size, int flags)
-+{
-+ return SMB_VFS_NEXT_FSETXATTR(handle, fsp, fd, name, value, size, flags);
-+}
-+
-+#endif
-+
-+/* ----------------------------------
-+ * enumerate
-+*/
-+static ssize_t ads_listads(HANDLE_PARAMETER struct connection_struct *conn,const char *path, char *list, size_t size)
-+{
-+ char *ads_path = 0;
-+ char *main_path = 0;
-+ TALLOC_CTX *ctx;
-+ size_t len, total = 0;
-+ SMB_STRUCT_STAT st;
-+ SMB_STRUCT_STAT *main_info = &st;
-+
-+
-+ if (!list || !path) {
-+ /* aka we have ads functionnality */
-+ return 0;
-+ }
-+
-+ DEBUG(3,("ads: ads_listads %s\n", path));
-+
-+ if (!(ctx = ADS_TALLOC_INIT("ads_listads")))
-+ return -1;
-+
-+ if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) {
-+ talloc_destroy(ctx);
-+ return -1;
-+ }
-+
-+ /*
-+ if data stream
-+ for each stream
-+ */
-+ if (ads_path == main_path) {
-+ char *ads_base = ads_dir(ctx, conn->origpath, path, isDir(main_info));
-+ struct dirent *dent = 0;
-+ DIR *dir = opendir(ads_base);
-+
-+ /* XXX need to be root ? */
-+ if (dir) {
-+
-+ while (NULL != (dent = readdir(dir))) {
-+ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
-+ continue;
-+ len = strlen(dent->d_name) +8 ;
-+ total += len;
-+ if (total >= size) {
-+ talloc_destroy(ctx);
-+ errno = ERANGE;
-+ return -1;
-+ }
-+ snprintf (list, len, ":%s:$DATA", dent->d_name);
-+ list += len;
-+ }
-+ closedir(dir);
-+ }
-+ }
-+
-+ talloc_destroy(ctx);
-+ return total;
-+}
-+
-+/* ------------------------------------
-+ * VFS operations structure */
-+
-+#ifndef SMB_VFS_OP
-+#define SMB_VFS_OP(x) ((void *) x)
-+#endif
-+
-+static vfs_op_tuple ads_op_tuples[] = {
-+
-+ /* Disk operations */
-+
-+ {SMB_VFS_OP(ads_disk_free), SMB_VFS_OP_DISK_FREE, SMB_VFS_LAYER_TRANSPARENT},
-+
-+ /* Directory operations */
-+
-+ {SMB_VFS_OP(ads_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_readdir), SMB_VFS_OP_READDIR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
-+
-+ /* File operations */
-+
-+ {SMB_VFS_OP(ads_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_stat), SMB_VFS_OP_STAT, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_lstat), SMB_VFS_OP_LSTAT, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_chown), SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_chdir), SMB_VFS_OP_CHDIR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_utime), SMB_VFS_OP_UTIME, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_readlink), SMB_VFS_OP_READLINK, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_mknod), SMB_VFS_OP_MKNOD, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_realpath), SMB_VFS_OP_REALPATH, SMB_VFS_LAYER_TRANSPARENT},
-+
-+ /* NT File ACL operations */
-+
-+ {SMB_VFS_OP(ads_set_nt_acl), SMB_VFS_OP_SET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
-+
-+ /* POSIX ACL operations */
-+
-+ {SMB_VFS_OP(ads_chmod_acl), SMB_VFS_OP_CHMOD_ACL, SMB_VFS_LAYER_TRANSPARENT},
-+
-+ {SMB_VFS_OP(ads_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_sys_acl_delete_def_file), SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, SMB_VFS_LAYER_TRANSPARENT},
-+#ifdef ADS_NEW_MODULE
-+ /* EA operations. */
-+ {SMB_VFS_OP(ads_getxattr), SMB_VFS_OP_GETXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_lgetxattr), SMB_VFS_OP_LGETXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_fgetxattr), SMB_VFS_OP_FGETXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_listxattr), SMB_VFS_OP_LISTXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_llistxattr), SMB_VFS_OP_LLISTXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_removexattr), SMB_VFS_OP_REMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_lremovexattr), SMB_VFS_OP_LREMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_fremovexattr), SMB_VFS_OP_FREMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_setxattr), SMB_VFS_OP_SETXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_lsetxattr), SMB_VFS_OP_LSETXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+ {SMB_VFS_OP(ads_fsetxattr), SMB_VFS_OP_FSETXATTR, SMB_VFS_LAYER_TRANSPARENT},
-+#endif
-+ /* ADS operations */
-+ {SMB_VFS_OP(ads_listads), SMB_VFS_OP_LISTADS, SMB_VFS_LAYER_TRANSPARENT},
-+
-+ {NULL, SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
-+};
-+
-+#ifdef ADS_NEW_MODULE
-+
-+#if 0
-+NTSTATUS vfs_ads_init(void)
-+{
-+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "ads", ads_op_tuples);
-+}
-+#endif
-+
-+NTSTATUS vfs_ads_init(void)
-+{
-+ DEBUG(3, ("ADS: vfs_ads_init\n"));
-+ return NT_STATUS_OK;
-+}
-+
-+
-+NTSTATUS init_module(void)
-+{
-+ DEBUG(3, ("ADS: init_module\n" ));
-+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "ads", ads_op_tuples);
-+}
-+
-+#else
-+/* VFS initialisation function. Return vfs_op_tuple array back to SAMBA. */
-+vfs_op_tuple *vfs_init(int *vfs_version, struct vfs_ops *def_vfs_ops,struct smb_vfs_handle_struct *vfs_handle)
-+{
-+ *vfs_version = SMB_VFS_INTERFACE_VERSION;
-+ memcpy(&default_vfs_ops, def_vfs_ops, sizeof(struct vfs_ops));
-+
-+ ads_handle = vfs_handle;
-+ DEBUG(3, ("ADS: vfs module loaded\n"));
-+ return ads_op_tuples;
-+}
-+
-+/* VFS finalization function. */
-+void vfs_done(connection_struct *conn)
-+{
-+ DEBUG(3, ("ADS: vfs module unloaded\n"));
-+}
-+
-+#endif