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
