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 */