Index: source/smbd/nttrans.c
===================================================================
--- source/smbd/nttrans.c	(revision 1473)
+++ source/smbd/nttrans.c	(working copy)
@@ -661,11 +661,16 @@
 			 * Check to see if this is a mac fork of some kind.
 			 */
 
-			if( strchr_m(fname, ':')) {
-				END_PROFILE(SMBntcreateX);
-				return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
-			}
-
+                        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);
+                        }
 			/*
 			  we need to handle the case when we get a
 			  relative open relative to a file and the
@@ -673,26 +678,29 @@
 			  (hint from demyn plantenberg)
 			*/
 
-			END_PROFILE(SMBntcreateX);
-			return(ERROR_DOS(ERRDOS,ERRbadfid));
+			/*
+			 * 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.
+		 	 */
 
-		/*
-		 * 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 '\'.
+		 	 */
 
-		/*
-		 * Ensure it ends in a '\'.
-		 */
-
-		if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
-			pstrcat(fname, "/");
-			dir_name_len++;
-		}
-
+			if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
+				pstrcat(fname, "/");
+				dir_name_len++;
+			}
+                }
 		srvstr_get_path(inbuf, rel_fname, smb_buf(inbuf), sizeof(rel_fname), 0, STR_TERMINATE, &status,False);
 		if (!NT_STATUS_IS_OK(status)) {
 			END_PROFILE(SMBntcreateX);
@@ -709,7 +717,6 @@
 		/* 
 		 * Check to see if this is a mac fork of some kind.
 		 */
-
 		if( strchr_m(fname, ':')) {
 			
 #ifdef HAVE_SYS_QUOTAS
@@ -725,8 +732,11 @@
 				 */
 			} else {
 #endif
-				END_PROFILE(SMBntcreateX);
-				return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+				if (-1 == SMB_VFS_LISTADS(conn, NULL, NULL, 0)) {  
+					END_PROFILE(SMBntcreateX);
+					return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+				}
+
 #ifdef HAVE_SYS_QUOTAS
 			}
 #endif
@@ -1235,12 +1245,10 @@
 			}
 
 			/*
-			 * 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
 			 */
-
-			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);
 		}
 
@@ -1278,7 +1286,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);
 	}
 
Index: source/smbd/vfs.c
===================================================================
--- source/smbd/vfs.c	(revision 1473)
+++ source/smbd/vfs.c	(working copy)
@@ -142,7 +142,10 @@
 		vfswrap_fremovexattr,
 		vfswrap_setxattr,
 		vfswrap_lsetxattr,
-		vfswrap_fsetxattr
+		vfswrap_fsetxattr,
+
+		/* alternate streams operations. */
+		vfswrap_listads
 	}
 };
 
Index: source/smbd/vfs-wrap.c
===================================================================
--- source/smbd/vfs-wrap.c	(revision 1473)
+++ source/smbd/vfs-wrap.c	(working copy)
@@ -1029,3 +1029,14 @@
 {
 	return sys_fsetxattr(fd, name, value, size, flags);
 }
+
+/****************************************************************
+ 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;
+}
+
Index: source/smbd/trans2.c
===================================================================
--- source/smbd/trans2.c	(revision 1473)
+++ source/smbd/trans2.c	(working copy)
@@ -406,6 +406,159 @@
 }
 
 /****************************************************************************
+ ****************************************************************************
+ 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
   set correctly for the type of call.
@@ -2653,7 +2806,7 @@
 			data_size = 4;
 			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).
@@ -2663,16 +2816,24 @@
 #endif
 		case SMB_FILE_STREAM_INFORMATION:
 			DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STREAM_INFORMATION\n"));
-			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;
 
Index: source/include/vfs_macros.h
===================================================================
--- source/include/vfs_macros.h	(revision 1473)
+++ source/include/vfs_macros.h	(working copy)
@@ -119,6 +119,9 @@
 #define SMB_VFS_LSETXATTR(conn,path,name,value,size,flags) ((conn)->vfs.ops.lsetxattr((conn)->vfs.handles.lsetxattr,(conn),(path),(name),(value),(size),(flags)))
 #define SMB_VFS_FSETXATTR(fsp,fd,name,value,size,flags) ((fsp)->conn->vfs.ops.fsetxattr((fsp)->conn->vfs.handles.fsetxattr,(fsp),(fd),(name),(value),(size),(flags)))
 
+/* ADS operations. */
+#define SMB_VFS_LISTADS(conn,path,list,size) ((conn)->vfs.ops.listads((conn)->vfs.handles.listads,(conn),(path),(list),(size)))
+
 /*******************************************************************
  Don't access conn->vfs_opaque.ops directly!!!
  Use this macros!
@@ -217,6 +220,9 @@
 #define SMB_VFS_OPAQUE_LSETXATTR(conn,path,name,value,size,flags) ((conn)->vfs_opaque.ops.lsetxattr((conn)->vfs_opaque.handles.lsetxattr,(conn),(path),(name),(value),(size),(flags)))
 #define SMB_VFS_OPAQUE_FSETXATTR(fsp,fd,name,value,size,flags) ((fsp)->conn->vfs_opaque.ops.fsetxattr((fsp)->conn->vfs_opaque.handles.fsetxattr,(fsp),(fd),(name),(value),(size),(flags)))
 
+/* ADS operations. */
+#define SMB_VFS_OPAQUE_LISTADS(conn,path,list,size) ((conn)->vfs_opaque.ops.listads((conn)->vfs_opaque.handles.listads,(conn),(path),(list),(size)))
+
 /*******************************************************************
  Don't access handle->vfs_next.ops.* directly!!!
  Use this macros!
@@ -315,4 +321,7 @@
 #define SMB_VFS_NEXT_LSETXATTR(handle,conn,path,name,value,size,flags) ((handle)->vfs_next.ops.lsetxattr((handle)->vfs_next.handles.lsetxattr,(conn),(path),(name),(value),(size),(flags)))
 #define SMB_VFS_NEXT_FSETXATTR(handle,fsp,fd,name,value,size,flags) ((handle)->vfs_next.ops.fsetxattr((handle)->vfs_next.handles.fsetxattr,(fsp),(fd),(name),(value),(size),(flags)))
 
+/* ADS operations. */
+#define SMB_VFS_NEXT_LISTADS(handle,conn,path,list,size) ((handle)->vfs_next.ops.listads((handle)->vfs_next.handles.listads,(conn),(path),(list),(size)))
+
 #endif /* _VFS_MACROS_H */
Index: source/include/vfs.h
===================================================================
--- source/include/vfs.h	(revision 1473)
+++ source/include/vfs.h	(working copy)
@@ -55,7 +55,8 @@
 /* Changed to version 8 includes EA calls. JRA. */
 /* Changed to version 9 to include the get_shadow_data call. --metze */
 /* Changed to version 10 to include pread/pwrite calls. */
-#define SMB_VFS_INTERFACE_VERSION 10
+/* Changed to version 11 to include alternate data streams. */
+#define SMB_VFS_INTERFACE_VERSION 11
 
 
 /* to bug old modules witch are trying to compile with the old functions */
@@ -185,6 +186,9 @@
 	SMB_VFS_OP_SETXATTR,
 	SMB_VFS_OP_LSETXATTR,
 	SMB_VFS_OP_FSETXATTR,
+	
+	/* alternate stream */
+	SMB_VFS_OP_LISTADS,
 
 	/* This should always be last enum value */
 	
@@ -294,6 +298,9 @@
 		int (*lsetxattr)(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags);
 		int (*fsetxattr)(struct vfs_handle_struct *handle, struct files_struct *fsp,int filedes, const char *name, const void *value, size_t size, int flags);
 
+		/* alternate stream operations. */
+		ssize_t (*listads)(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, char *list, size_t size);
+
 	} ops;
 
 	struct vfs_handles_pointers {
@@ -394,6 +401,8 @@
 		struct vfs_handle_struct *lsetxattr;
 		struct vfs_handle_struct *fsetxattr;
 
+		/* alternate stream operations. */
+		struct vfs_handle_struct *listads;
 	} handles;
 };
 
Index: source/include/smb.h
===================================================================
--- source/include/smb.h	(revision 1473)
+++ source/include/smb.h	(working copy)
@@ -1703,6 +1703,12 @@
 	DATA_BLOB value;
 };
 
+struct ads_struct {
+	SMB_BIG_UINT size;
+	SMB_BIG_UINT allocation_size;
+	char *name;
+};
+
 /* EA names used internally in Samba. KEEP UP TO DATE with prohibited_ea_names in trans2.c !. */
 #define SAMBA_POSIX_INHERITANCE_EA_NAME "user.SAMBA_PAI"
 /* EA to use for DOS attributes */
