diff -ur ../smb3.0a20.orig/source/include/smb.h ./source/include/smb.h
--- ../smb3.0a20.orig/source/include/smb.h	Mon Jan  6 18:04:22 2003
+++ ./source/include/smb.h	Fri Jun  4 05:34:14 2004
@@ -1652,4 +1652,10 @@
 
 extern struct poptOption popt_common_debug[];
 
+struct ads_struct {
+	SMB_BIG_UINT size;
+	SMB_BIG_UINT allocation_size;
+	char *name;
+};
+
 #endif /* _SMB_H */
diff -ur ../smb3.0a20.orig/source/include/smb_macros.h ./source/include/smb_macros.h
--- ../smb3.0a20.orig/source/include/smb_macros.h	Mon Jan  6 18:04:22 2003
+++ ./source/include/smb_macros.h	Fri Jun  4 18:24:20 2004
@@ -291,4 +291,8 @@
 
 #define vfs_chdir(conn,fname) ((conn)->vfs_ops.chdir((conn),fname))
 
+/*******************************************************************
+ A wrapper for vfs_listads().
+********************************************************************/
+#define vfs_listads(conn,path,list,size)  ((conn)->vfs_ops.listads((conn),(path),(list),(size))) 
 #endif /* _SMB_MACROS_H */
diff -ur ../smb3.0a20.orig/source/include/vfs.h ./source/include/vfs.h
--- ../smb3.0a20.orig/source/include/vfs.h	Mon Jan  6 18:04:23 2003
+++ ./source/include/vfs.h	Fri Jun  4 16:30:14 2004
@@ -45,7 +45,8 @@
 /* Changed to version 3 for POSIX acl extensions. JRA. */
 /* Changed to version 4 for cascaded VFS interface. Alexander Bokovoy. */
 /* Changed to version 5 for sendfile addition. JRA. */
-#define SMB_VFS_INTERFACE_VERSION 5
+/* Changed to version 11 to include alternate data streams. */
+#define SMB_VFS_INTERFACE_VERSION 11
 
 
 /* Version of supported cascaded interface backward copmatibility.
@@ -173,6 +174,9 @@
 	int (*sys_acl_free_text)(struct connection_struct *conn, char *text);
 	int (*sys_acl_free_acl)(struct connection_struct *conn, SMB_ACL_T posix_acl);
 	int (*sys_acl_free_qualifier)(struct connection_struct *conn, void *qualifier, SMB_ACL_TAG_T tagtype);
+
+	/* alternate stream operations. */
+	ssize_t (*listads)(/* struct vfs_handle_struct *handle, */ struct connection_struct *conn,const char *path, char *list, size_t size);
 };
 
 struct vfs_options {
@@ -269,6 +273,9 @@
 	SMB_VFS_OP_SYS_ACL_FREE_ACL,
 	SMB_VFS_OP_SYS_ACL_FREE_QUALIFIER,
 	
+	/* alternate stream */
+	SMB_VFS_OP_LISTADS,
+
 	/* This should always be last enum value */
 	
 	SMB_VFS_OP_LAST
diff -ur ../smb3.0a20.orig/source/smbd/nttrans.c ./source/smbd/nttrans.c
--- ../smb3.0a20.orig/source/smbd/nttrans.c	Mon Jan  6 18:05:44 2003
+++ ./source/smbd/nttrans.c	Fri Jul  2 07:38:38 2004
@@ -52,6 +52,8 @@
 	FILE_GENERIC_ALL
 };
 
+#define SMB_VFS_LISTADS vfs_listads
+
 /****************************************************************************
  Send the required number of replies back.
  We assume all fields other than the data fields are
@@ -625,30 +627,40 @@
 			 * Check to see if this is a mac fork of some kind.
 			 */
 
-			if( strchr_m(fname, ':')) {
+			if( !strchr_m(fname, ':')) {
+		    		/* it's not an alternate stream */
+		    		END_PROFILE(SMBntcreateX);
+		    		return(ERROR_DOS(ERRDOS,ERRbadfid));
+			}
+			else if (-1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0)) {
+			        /* fs have no support for alternate streams */
 				END_PROFILE(SMBntcreateX);
 				return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
 			}
-			END_PROFILE(SMBntcreateX);
-			return(ERROR_DOS(ERRDOS,ERRbadfid));
-		}
 
-		/*
-		 * Copy in the base directory name.
-		 */
+			/*
+		 	* Copy in the base name.
+		 	*/
+			pstrcpy( fname, dir_fsp->fsp_name );
+			dir_name_len = strlen(fname);
+		}
+		else { /* it's a dir */
+			/*
+	 		 * Copy in the base directory name.
+	 		 */
 
-		pstrcpy( fname, dir_fsp->fsp_name );
-		dir_name_len = strlen(fname);
+			pstrcpy( fname, dir_fsp->fsp_name );
+			dir_name_len = strlen(fname);
 
-		/*
-		 * Ensure it ends in a '\'.
-		 */
-
-		if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
-			pstrcat(fname, "\\");
-			dir_name_len++;
-		}
+			/*
+	 		 * Ensure it ends in a '\'.
+			 */
 
+			if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
+				pstrcat(fname, "\\");
+				dir_name_len++;
+			}
+                }
 		srvstr_pull_buf(inbuf, &fname[dir_name_len], smb_buf(inbuf), sizeof(fname)-dir_name_len, STR_TERMINATE);
 	} else {
 		srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE);
@@ -656,8 +668,7 @@
 		/* 
 		 * Check to see if this is a mac fork of some kind.
 		 */
-
-		if( strchr_m(fname, ':')) {
+		if( strchr_m(fname, ':') && -1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0)) {
 			END_PROFILE(SMBntcreateX);
 			return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
 		}
@@ -1138,12 +1149,10 @@
 			srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE);
 
 			/*
-			 * Check to see if this is a mac fork of some kind.
+			 * Check to see if this is a mac fork of some kind. FIXME ADS
 			 */
-
-			if( strchr_m(fname, ':'))
+			if( strchr_m(fname, ':') && -1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0))
 				return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
-
 			return ERROR_DOS(ERRDOS,ERRbadfid);
 		}
 
@@ -1172,7 +1181,7 @@
 		 * Check to see if this is a mac fork of some kind.
 		 */
 
-		if( strchr_m(fname, ':'))
+		if( strchr_m(fname, ':')  && -1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0))
 			return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
 	}
 
diff -ur ../smb3.0a20.orig/source/smbd/trans2.c ./source/smbd/trans2.c
--- ../smb3.0a20.orig/source/smbd/trans2.c	Mon Jan  6 18:05:48 2003
+++ ./source/smbd/trans2.c	Thu Jul  1 03:06:42 2004
@@ -50,6 +50,162 @@
 	return ret;
 }
 
+#define SMB_VFS_STAT vfs_stat
+#define SMB_VFS_LISTADS vfs_listads
+
+/****************************************************************************
+ ****************************************************************************
+ Return a linked list of the alternate streams Plus the total size
+****************************************************************************/
+struct ads_list {
+	struct ads_list *next, *prev;
+	struct ads_struct ads;
+};
+
+static struct ads_list *get_ads_list(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp, const char *fname, size_t *pads_total_len)
+{
+	/* Get a list of all ads with size, lax namesize is 64k. */
+	size_t ads_namelist_size = 4096;
+	char *ads_namelist;
+	char *p;
+	ssize_t sizeret;
+	int i;
+	struct ads_list *ads_list_head = NULL;
+
+	*pads_total_len = 0;
+
+	DEBUG(10,("get_ads_list\n" ));
+	
+	for (i = 0, ads_namelist = talloc(mem_ctx, ads_namelist_size); i < 6;
+			ads_namelist = talloc_realloc(mem_ctx, ads_namelist, ads_namelist_size), i++) {
+
+		sizeret = SMB_VFS_LISTADS(conn, fname, ads_namelist, ads_namelist_size);
+		if (sizeret == -1 && errno == ERANGE) {
+			ads_namelist_size *= 2;
+		} else {
+			break;
+		}
+	}
+
+	if (sizeret == -1)
+		return NULL;
+
+	DEBUG(10,("get_ads_list: ads_namelist size = %d\n", sizeret ));
+
+	if (sizeret) { 
+		for (p = ads_namelist; p - ads_namelist < sizeret; p += strlen(p) +1) {
+			struct ads_list *listp, *tmp;
+			SMB_STRUCT_STAT sbuf;
+			char *t;
+			
+			listp = talloc(mem_ctx, sizeof(struct ads_list));
+			if (!listp)
+				return NULL;
+
+			listp->ads.name = talloc_strdup(mem_ctx, p);
+			if (!listp->ads.name)
+				return NULL;
+			
+			listp->ads.size = 0;
+			listp->ads.allocation_size = 0;
+
+			t = talloc_asprintf(mem_ctx, "%s%s", fname, p);
+			if (!t)
+				return NULL;
+			if (!SMB_VFS_STAT(conn, t ,&sbuf)) {
+				listp->ads.size = get_file_size(sbuf);
+				listp->ads.allocation_size = get_allocation_size(NULL,&sbuf);
+			}
+			/* FIXME get ride of this */
+			{
+			fstring dos_ads_name;
+				
+				push_ascii_fstring(dos_ads_name, listp->ads.name);
+				*pads_total_len += strlen(dos_ads_name) + 1 + 24;
+				DEBUG(10,("get_ads_list: total_len = %u, %s, size = %llu\n",
+						*pads_total_len, dos_ads_name, listp->ads.size ));
+			}
+			DLIST_ADD_END(ads_list_head, listp, tmp);
+		}
+	}
+
+	DEBUG(10,("get_ads_list: total_len = %u\n", *pads_total_len));
+	return ads_list_head;
+}
+
+/****************************************************************************
+ Fill a qfilepathinfo buffer with alternate streams. 
+ Returns the length of the buffer that was filled.
+****************************************************************************/
+
+static unsigned int fill_ads_buffer(char *pdata, unsigned int total_data_size,
+	connection_struct *conn, files_struct *fsp, const char *fname)
+{
+	unsigned int ret_data_size = 0;
+	char *p = pdata;
+	size_t total_ads_len;
+	TALLOC_CTX *mem_ctx;
+	struct ads_list *ads_list;
+
+	SMB_ASSERT(total_data_size >= 24);
+
+	mem_ctx = talloc_init(/*"fill_ads_buffer"*/);
+	if (!mem_ctx) {
+		return 0;
+	}
+
+	ads_list = get_ads_list(mem_ctx, conn, fsp, fname, &total_ads_len);
+	if (!ads_list) {
+		talloc_destroy(mem_ctx);
+		return 0;
+	}
+
+	if (total_ads_len > total_data_size) {
+		talloc_destroy(mem_ctx);
+		return 0;
+	}
+
+	for (p = pdata; ads_list; ads_list = ads_list->next) {
+#if 0
+		size_t dos_namelen;
+		fstring dos_ads_name;
+
+		push_ascii_fstring(dos_ads_name, ads_list->ads.name);
+		dos_namelen = strlen(dos_ads_name);
+		if (dos_namelen > 255 || dos_namelen == 0) {
+			break;
+		}
+		if (dos_namelen + 24 > total_data_size) {
+			break;
+		}
+#endif
+		/* We know we have room. */
+		size_t byte_len = dos_PutUniCode(p +24, ads_list->ads.name, -1, False);
+		size_t off = SMB_ROUNDUP(24 +byte_len, 8); 
+		
+		SIVAL(p,0,0); /* from ethereal next entry offset */
+		SIVAL(p,4, byte_len); /* Byte length of unicode string :filename:$DATA */
+		SOFF_T(p,8, ads_list->ads.size);
+		SOFF_T(p,16, ads_list->ads.allocation_size);
+		if (ads_list->next) {
+		    SIVAL(p,0, off);
+		}
+		else {
+		    /* don't pad the last one */
+		    off = 24 +byte_len;
+		}
+
+		total_data_size -= off;
+		p += off;
+	}
+
+	ret_data_size = PTR_DIFF(p, pdata);
+	DEBUG(10,("fill_ads_buffer: data_size = %u, total_ads_len = %u\n",
+			ret_data_size, total_ads_len ));
+	talloc_destroy(mem_ctx);
+	return ret_data_size;
+}
+
 /****************************************************************************
   Send the required number of replies back.
   We assume all fields other than the data fields are
@@ -1934,7 +2090,7 @@
 				break;
 			}
 		
-#if 0
+#if 1
 		/*
 		 * NT4 server just returns "invalid query" to this - if we try to answer
 		 * it then NTws gets a BSOD! (tridge).
@@ -1943,16 +2099,24 @@
 		case SMB_QUERY_FILE_STREAM_INFO:
 #endif
 		case SMB_FILE_STREAM_INFORMATION:
-			if (mode & aDIR) {
-				data_size = 0;
-			} else {
-				size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False);
-				SIVAL(pdata,0,0); /* ??? */
-				SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
-				SOFF_T(pdata,8,file_size);
-				SIVAL(pdata,16,allocation_size);
-				SIVAL(pdata,20,0); /* ??? */
-				data_size = 24 + byte_len;
+			{
+				size_t off;
+
+				if (mode & aDIR) {
+					off = 0;
+				} else {
+					size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False);
+				
+					off = SMB_ROUNDUP(24 +byte_len, 8); /* FIXME or 8 ? */
+					SIVAL(pdata,0,0); /* from ethereal next entry offset */
+					SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
+					SOFF_T(pdata,8,file_size);
+					SOFF_T(pdata,16,allocation_size);
+				}
+				if ((data_size = fill_ads_buffer(pdata +off, data_size, conn, fsp, fname))) {
+					SIVAL(pdata,0,off);
+				}
+				data_size += off;
 			}
 			break;
 
diff -ur ../smb3.0a20.orig/source/smbd/vfs-wrap.c ./source/smbd/vfs-wrap.c
--- ../smb3.0a20.orig/source/smbd/vfs-wrap.c	Mon Jan  6 18:05:49 2003
+++ ./source/smbd/vfs-wrap.c	Fri Jun  4 16:33:16 2004
@@ -739,3 +739,14 @@
 {
 	return sys_acl_free_qualifier(qualifier, tagtype);
 }
+
+/****************************************************************
+ Alternate stream operations.
+*****************************************************************/
+
+ssize_t vfswrap_listads(/* struct vfs_handle_struct *handle, */ struct connection_struct *conn,const char *path, char *list, size_t size)
+{
+        errno = ENOSYS;
+        return -1;
+}
+
Only in ./source/smbd: vfs-wrap.c.orig
diff -ur ../smb3.0a20.orig/source/smbd/vfs.c ./source/smbd/vfs.c
--- ../smb3.0a20.orig/source/smbd/vfs.c	Mon Jan  6 18:05:48 2003
+++ ./source/smbd/vfs.c	Fri Jun  4 05:40:09 2004
@@ -124,7 +124,10 @@
 	vfswrap_sys_acl_get_perm,
 	vfswrap_sys_acl_free_text,
 	vfswrap_sys_acl_free_acl,
-	vfswrap_sys_acl_free_qualifier
+	vfswrap_sys_acl_free_qualifier,
+
+	/* alternate streams operations. */
+	vfswrap_listads
 };
 
 /****************************************************************************
