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