[patch]: optimization for findfirst when in case-sensitive mode
Matt Mitchell
mmitchell at virtualproperties.com
Sun Dec 12 22:59:16 GMT 2004
Jeremy Allison wrote:
> On Fri, Dec 10, 2004 at 05:41:08PM -0600, Matt Mitchell wrote:
>
>>Jeremy (and all),
>>
>>Here is a first crack at a patch implementing an optimization where,
>>given that
>>
>>Any comments or slams appreciated. Yes, it is a hack.
>
>
> No patch attached I'm afraid.... :-).
That's what I get for trying to wrap things up right before the holiday
party. :)
Here are the patches. For real this time.
-m
-------------- next part --------------
--- samba3-orig/source/smbd/trans2.c 2004-12-10 17:26:44.000000000 -0600
+++ samba3/source/smbd/trans2.c 2004-12-10 17:11:19.000000000 -0600
@@ -33,6 +33,12 @@
#define get_file_size(sbuf) ((sbuf).st_size)
#define DIR_ENTRY_SAFETY_MARGIN 4096
+static BOOL populate_lanman2_dir_entry(connection_struct *conn,
+ void *outbuf, char** ppdata, char** pp,
+ pstring fname, pstring pathreal,
+ int dirtype, int info_level,
+ int requires_resume_key,
+ SMB_STRUCT_STAT sbuf, char* base_data, int* last_name_off);
/********************************************************************
Roundup a value to the nearest SMB_ROUNDUP_ALLOCATION_SIZE boundary.
Only do this for Windows clients.
@@ -835,17 +841,11 @@
pstring mask;
pstring pathreal;
pstring fname;
- char *p, *q, *pdata = *ppdata;
+ char *p, *pdata = *ppdata;
uint32 reskey=0;
int prev_dirpos=0;
int mode=0;
- SMB_OFF_T file_size = 0;
- SMB_BIG_UINT allocation_size = 0;
- uint32 len;
- time_t mdate=0, adate=0, cdate=0;
char *nameptr;
- BOOL was_8_3;
- int nt_extmode; /* Used for NT connections instead of mode */
BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
*fname = 0;
@@ -944,35 +944,14 @@
}
}
- mode = dos_mode(conn,pathreal,&sbuf);
+ DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
+ mode = dos_mode(conn,pathreal,&sbuf);
+
if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
- continue;
- }
-
- file_size = get_file_size(sbuf);
- allocation_size = get_allocation_size(NULL,&sbuf);
- mdate = sbuf.st_mtime;
- adate = sbuf.st_atime;
- cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
-
- if (lp_dos_filetime_resolution(SNUM(conn))) {
- cdate &= ~1;
- mdate &= ~1;
- adate &= ~1;
- }
-
- if(mode & aDIR) {
- /* This is necessary, as otherwise the
- * desktop.ini file in this folder is
- * ignored */
- mode |= (lp_profile_acls(SNUM(conn)) ? aRONLY : 0);
- file_size = 0;
+ return False;
}
-
- DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
-
found = True;
}
}
@@ -982,411 +961,103 @@
p = pdata;
nameptr = p;
- nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
+ if(!populate_lanman2_dir_entry(conn,
+ outbuf, ppdata, &p,
+ fname, pathreal,
+ dirtype, info_level,
+ requires_resume_key,
+ sbuf, base_data, last_name_off)) {
+ /* Some problem we should probably do a better job of handling... */
+ DEBUG(3,("populate_lanman2_dir_entry failed!"));
+ return False;
+ }
+
+
+ if (PTR_DIFF(p,pdata) > space_remaining) {
+ /* Move the dirptr back to prev_dirpos */
+ SeekDir(conn->dirptr, prev_dirpos);
+ *out_of_space = True;
+ DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
+ return False; /* Not finished - just out of space */
+ }
- switch (info_level) {
- case SMB_INFO_STANDARD:
- DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_STANDARD\n"));
- if(requires_resume_key) {
- SIVAL(p,0,reskey);
- p += 4;
- }
- put_dos_date2(p,l1_fdateCreation,cdate);
- put_dos_date2(p,l1_fdateLastAccess,adate);
- put_dos_date2(p,l1_fdateLastWrite,mdate);
- SIVAL(p,l1_cbFile,(uint32)file_size);
- SIVAL(p,l1_cbFileAlloc,(uint32)allocation_size);
- SSVAL(p,l1_attrFile,mode);
- p += l1_achName;
- nameptr = p;
- p += align_string(outbuf, p, 0);
- len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
- if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
- if (len > 2) {
- SCVAL(nameptr, -1, len - 2);
- } else {
- SCVAL(nameptr, -1, 0);
- }
- } else {
- if (len > 1) {
- SCVAL(nameptr, -1, len - 1);
- } else {
- SCVAL(nameptr, -1, 0);
- }
- }
- p += len;
- break;
+ /* Setup the last_filename pointer, as an offset from base_data */
+ /* *last_name_off = PTR_DIFF(nameptr,base_data); */
+ /* Advance the data pointer to the next slot */
+ *ppdata = p;
- case SMB_INFO_QUERY_EA_SIZE:
- DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_QUERY_EA_SIZE\n"));
- if(requires_resume_key) {
- SIVAL(p,0,reskey);
- p += 4;
- }
- put_dos_date2(p,l2_fdateCreation,cdate);
- put_dos_date2(p,l2_fdateLastAccess,adate);
- put_dos_date2(p,l2_fdateLastWrite,mdate);
- SIVAL(p,l2_cbFile,(uint32)file_size);
- SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size);
- SSVAL(p,l2_attrFile,mode);
- {
- unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
- SIVAL(p,l2_cbList,ea_size); /* Extended attributes */
- }
- p += l2_achName;
- nameptr = p - 1;
- len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE | STR_NOALIGN);
- if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
- if (len > 2) {
- len -= 2;
- } else {
- len = 0;
- }
- } else {
- if (len > 1) {
- len -= 1;
- } else {
- len = 0;
- }
- }
- SCVAL(nameptr,0,len);
- p += len;
- SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
- break;
+ return(found);
+}
- case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
- was_8_3 = mangle_is_8_3(fname, True);
- p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SOFF_T(p,0,file_size); p += 8;
- SOFF_T(p,0,allocation_size); p += 8;
- SIVAL(p,0,nt_extmode); p += 4;
- q = p; p += 4; /* q is placeholder for name length. */
- {
- unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
- SIVAL(p,0,ea_size); /* Extended attributes */
- p += 4;
- }
- /* Clear the short name buffer. This is
- * IMPORTANT as not doing so will trigger
- * a Win2k client bug. JRA.
- */
- memset(p,'\0',26);
- if (!was_8_3 && lp_manglednames(SNUM(conn))) {
- pstring mangled_name;
- pstrcpy(mangled_name, fname);
- mangle_map(mangled_name,True,True,SNUM(conn));
- mangled_name[12] = 0;
- len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
- SSVAL(p, 0, len);
- } else {
- SSVAL(p,0,0);
- *(p+2) = 0;
- }
- p += 2 + 24;
- len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
- SIVAL(q,0,len);
- p += len;
- len = PTR_DIFF(p, pdata);
- len = (len + 3) & ~3;
- SIVAL(pdata,0,len);
- p = pdata + len;
- break;
+/****************************************************************************
+ Reply to a TRANS2_FINDFIRST.
+****************************************************************************/
- case SMB_FIND_FILE_DIRECTORY_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
- p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SOFF_T(p,0,file_size); p += 8;
- SOFF_T(p,0,allocation_size); p += 8;
- SIVAL(p,0,nt_extmode); p += 4;
- len = srvstr_push(outbuf, p + 4, fname, -1, STR_TERMINATE_ASCII);
- SIVAL(p,0,len);
- p += 4 + len;
- len = PTR_DIFF(p, pdata);
- len = (len + 3) & ~3;
- SIVAL(pdata,0,len);
- p = pdata + len;
- break;
-
- case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
- p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SOFF_T(p,0,file_size); p += 8;
- SOFF_T(p,0,allocation_size); p += 8;
- SIVAL(p,0,nt_extmode); p += 4;
- q = p; p += 4; /* q is placeholder for name length. */
- {
- unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
- SIVAL(p,0,ea_size); /* Extended attributes */
- p +=4;
- }
- len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
- SIVAL(q, 0, len);
- p += len;
+static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
+{
+ /* We must be careful here that we don't return more than the
+ allowed number of data bytes. If this means returning fewer than
+ maxentries then so be it. We assume that the redirector has
+ enough room for the fixed number of parameter bytes it has
+ requested. */
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ int dirtype = SVAL(params,0);
+ int maxentries = SVAL(params,2);
+ uint16 findfirst_flags = SVAL(params,4);
+ BOOL close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
+ BOOL close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
+ BOOL requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
+ int info_level = SVAL(params,6);
+ pstring directory;
+ pstring mask;
+ char *p, *wcard;
+ int last_name_off=0;
+ int dptr_num = -1;
+ int numentries = 0;
+ int i;
+ BOOL finished = False;
+ BOOL dont_descend = False;
+ BOOL out_of_space = False;
+ int space_remaining;
+ BOOL bad_path = False;
+ SMB_STRUCT_STAT sbuf;
+ NTSTATUS ntstatus = NT_STATUS_OK;
- len = PTR_DIFF(p, pdata);
- len = (len + 3) & ~3;
- SIVAL(pdata,0,len);
- p = pdata + len;
- break;
+ if (total_params < 12)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ *directory = *mask = 0;
+
+ DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, \
+close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
+ dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
+ info_level, max_data_bytes));
+ if (!maxentries) {
+ /* W2K3 seems to treat zero as 1. */
+ maxentries = 1;
+ }
+
+ switch (info_level) {
+ case SMB_INFO_STANDARD:
+ case SMB_INFO_QUERY_EA_SIZE:
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
case SMB_FIND_FILE_NAMES_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
- p += 4;
- SIVAL(p,0,reskey); p += 4;
- p += 4;
- /* this must *not* be null terminated or w2k gets in a loop trying to set an
- acl on a dir (tridge) */
- len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
- SIVAL(p, -4, len);
- p += len;
- len = PTR_DIFF(p, pdata);
- len = (len + 3) & ~3;
- SIVAL(pdata,0,len);
- p = pdata + len;
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ case SMB_FIND_ID_FULL_DIRECTORY_INFO:
+ case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
+ break;
+ case SMB_FIND_FILE_UNIX:
+ if (!lp_unix_extensions())
+ return(ERROR_DOS(ERRDOS,ERRunknownlevel));
break;
-
- case SMB_FIND_ID_FULL_DIRECTORY_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
- p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SOFF_T(p,0,file_size); p += 8;
- SOFF_T(p,0,allocation_size); p += 8;
- SIVAL(p,0,nt_extmode); p += 4;
- q = p; p += 4; /* q is placeholder for name length. */
- {
- unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
- SIVAL(p,0,ea_size); /* Extended attributes */
- p +=4;
- }
- SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
- SIVAL(p,0,sbuf.st_dev); p += 4;
- SIVAL(p,0,sbuf.st_ino); p += 4;
- len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
- SIVAL(q, 0, len);
- p += len;
- len = PTR_DIFF(p, pdata);
- len = (len + 3) & ~3;
- SIVAL(pdata,0,len);
- p = pdata + len;
- break;
-
- case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
- was_8_3 = mangle_is_8_3(fname, True);
- p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SOFF_T(p,0,file_size); p += 8;
- SOFF_T(p,0,allocation_size); p += 8;
- SIVAL(p,0,nt_extmode); p += 4;
- q = p; p += 4; /* q is placeholder for name length */
- {
- unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
- SIVAL(p,0,ea_size); /* Extended attributes */
- p +=4;
- }
- /* Clear the short name buffer. This is
- * IMPORTANT as not doing so will trigger
- * a Win2k client bug. JRA.
- */
- memset(p,'\0',26);
- if (!was_8_3 && lp_manglednames(SNUM(conn))) {
- pstring mangled_name;
- pstrcpy(mangled_name, fname);
- mangle_map(mangled_name,True,True,SNUM(conn));
- mangled_name[12] = 0;
- len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
- SSVAL(p, 0, len);
- } else {
- SSVAL(p,0,0);
- *(p+2) = 0;
- }
- p += 26;
- SSVAL(p,0,0); p += 2; /* Reserved ? */
- SIVAL(p,0,sbuf.st_dev); p += 4;
- SIVAL(p,0,sbuf.st_ino); p += 4;
- len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
- SIVAL(q,0,len);
- p += len;
- len = PTR_DIFF(p, pdata);
- len = (len + 3) & ~3;
- SIVAL(pdata,0,len);
- p = pdata + len;
- break;
-
- /* CIFS UNIX Extension. */
-
- case SMB_FIND_FILE_UNIX:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
- p+= 4;
- SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
-
- /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
- SOFF_T(p,0,get_file_size(sbuf)); /* File size 64 Bit */
- p+= 8;
-
- SOFF_T(p,0,get_allocation_size(NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */
- p+= 8;
-
- put_long_date(p,sbuf.st_ctime); /* Inode change Time 64 Bit */
- put_long_date(p+8,sbuf.st_atime); /* Last access time 64 Bit */
- put_long_date(p+16,sbuf.st_mtime); /* Last modification time 64 Bit */
- p+= 24;
-
- SIVAL(p,0,sbuf.st_uid); /* user id for the owner */
- SIVAL(p,4,0);
- p+= 8;
-
- SIVAL(p,0,sbuf.st_gid); /* group id of owner */
- SIVAL(p,4,0);
- p+= 8;
-
- SIVAL(p,0,unix_filetype(sbuf.st_mode));
- p+= 4;
-
- SIVAL(p,0,unix_dev_major(sbuf.st_rdev)); /* Major device number if type is device */
- SIVAL(p,4,0);
- p+= 8;
-
- SIVAL(p,0,unix_dev_minor(sbuf.st_rdev)); /* Minor device number if type is device */
- SIVAL(p,4,0);
- p+= 8;
-
- SINO_T(p,0,(SMB_INO_T)sbuf.st_ino); /* inode number */
- p+= 8;
-
- SIVAL(p,0, unix_perms_to_wire(sbuf.st_mode)); /* Standard UNIX file permissions */
- SIVAL(p,4,0);
- p+= 8;
-
- SIVAL(p,0,sbuf.st_nlink); /* number of hard links */
- SIVAL(p,4,0);
- p+= 8;
-
- len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
- p += len;
-
- len = PTR_DIFF(p, pdata);
- len = (len + 3) & ~3;
- SIVAL(pdata,0,len); /* Offset from this structure to the beginning of the next one */
- p = pdata + len;
- /* End of SMB_QUERY_FILE_UNIX_BASIC */
-
- break;
-
- default:
- return(False);
- }
-
-
- if (PTR_DIFF(p,pdata) > space_remaining) {
- /* Move the dirptr back to prev_dirpos */
- SeekDir(conn->dirptr, prev_dirpos);
- *out_of_space = True;
- DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
- return False; /* Not finished - just out of space */
- }
-
- /* Setup the last_filename pointer, as an offset from base_data */
- *last_name_off = PTR_DIFF(nameptr,base_data);
- /* Advance the data pointer to the next slot */
- *ppdata = p;
-
- return(found);
-}
-
-/****************************************************************************
- Reply to a TRANS2_FINDFIRST.
-****************************************************************************/
-
-static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data,
- unsigned int max_data_bytes)
-{
- /* We must be careful here that we don't return more than the
- allowed number of data bytes. If this means returning fewer than
- maxentries then so be it. We assume that the redirector has
- enough room for the fixed number of parameter bytes it has
- requested. */
- char *params = *pparams;
- char *pdata = *ppdata;
- int dirtype = SVAL(params,0);
- int maxentries = SVAL(params,2);
- uint16 findfirst_flags = SVAL(params,4);
- BOOL close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
- BOOL close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
- BOOL requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
- int info_level = SVAL(params,6);
- pstring directory;
- pstring mask;
- char *p, *wcard;
- int last_name_off=0;
- int dptr_num = -1;
- int numentries = 0;
- int i;
- BOOL finished = False;
- BOOL dont_descend = False;
- BOOL out_of_space = False;
- int space_remaining;
- BOOL bad_path = False;
- SMB_STRUCT_STAT sbuf;
- NTSTATUS ntstatus = NT_STATUS_OK;
-
- if (total_params < 12)
- return(ERROR_DOS(ERRDOS,ERRinvalidparam));
-
- *directory = *mask = 0;
-
- DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, \
-close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
- dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
- info_level, max_data_bytes));
-
- if (!maxentries) {
- /* W2K3 seems to treat zero as 1. */
- maxentries = 1;
- }
-
- switch (info_level) {
- case SMB_INFO_STANDARD:
- case SMB_INFO_QUERY_EA_SIZE:
- case SMB_FIND_FILE_DIRECTORY_INFO:
- case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
- case SMB_FIND_FILE_NAMES_INFO:
- case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- case SMB_FIND_ID_FULL_DIRECTORY_INFO:
- case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
- break;
- case SMB_FIND_FILE_UNIX:
- if (!lp_unix_extensions())
- return(ERROR_DOS(ERRDOS,ERRunknownlevel));
- break;
- default:
- return(ERROR_DOS(ERRDOS,ERRunknownlevel));
- }
+ default:
+ return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+ }
srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, True);
if (!NT_STATUS_IS_OK(ntstatus)) {
@@ -4574,3 +4245,384 @@
END_PROFILE(SMBtrans2);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
+
+/**************************************************************************
+ * Actually populate the lanman buffer pointed to by *ppdata. Split out
+ * of get_lanman2_dir_entry so that we could short-circuit the dirptr
+ * operations where possible.
+ **************************************************************************/
+static BOOL populate_lanman2_dir_entry(connection_struct *conn,
+ void *outbuf, char** ppdata, char** pp,
+ pstring fname, pstring pathreal,
+ int dirtype, int info_level,
+ int requires_resume_key,
+ SMB_STRUCT_STAT sbuf, char* base_data, int* last_name_off)
+{
+ BOOL was_8_3 = False;
+ SMB_OFF_T file_size;
+ SMB_BIG_UINT allocation_size;
+ int len = 0;
+ char *pdata = *ppdata;
+ char *p = *pp;
+ char *nameptr = p;
+ char *q;
+ int mode;
+ int cdate, mdate, adate;
+ int nt_extmode; /* Used for NT connections instead of mode */
+ uint32 reskey = 0;
+
+ DEBUG(10,("conn 0x%p, outbuf 0x%p, ppdata 0x%p, pp 0x%p, fname %s, pathreal %s, dirtype %d, info_level %d, requires_resume_key %d, base_data 0x%p\n",
+ conn, outbuf, ppdata, pp, fname, pathreal, dirtype, info_level, requires_resume_key, base_data));
+
+ mode = dos_mode(conn,pathreal,&sbuf);
+ DEBUG(5,("dos mode is %d\n",mode));
+ if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
+ DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
+ return False;
+ }
+
+ file_size = get_file_size(sbuf);
+ allocation_size = get_allocation_size(NULL,&sbuf);
+ mdate = sbuf.st_mtime;
+ adate = sbuf.st_atime;
+ cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ cdate &= ~1;
+ mdate &= ~1;
+ adate &= ~1;
+ }
+
+ if(mode & aDIR)
+ file_size = 0;
+
+ nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
+
+ switch (info_level) {
+ case SMB_INFO_STANDARD:
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_INFO_STANDARD\n"));
+ if(requires_resume_key) {
+ SIVAL(p,0,reskey);
+ p += 4;
+ }
+ put_dos_date2(p,l1_fdateCreation,cdate);
+ put_dos_date2(p,l1_fdateLastAccess,adate);
+ put_dos_date2(p,l1_fdateLastWrite,mdate);
+ SIVAL(p,l1_cbFile,(uint32)file_size);
+ SIVAL(p,l1_cbFileAlloc,(uint32)allocation_size);
+ SSVAL(p,l1_attrFile,mode);
+ p += l1_achName;
+ nameptr = p;
+ p += align_string(outbuf, p, 0);
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
+ if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
+ if (len > 2) {
+ SCVAL(nameptr, -1, len - 2);
+ } else {
+ SCVAL(nameptr, -1, 0);
+ }
+ } else {
+ if (len > 1) {
+ SCVAL(nameptr, -1, len - 1);
+ } else {
+ SCVAL(nameptr, -1, 0);
+ }
+ }
+ p += len;
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_INFO_QUERY_EA_SIZE\n"));
+ if(requires_resume_key) {
+ SIVAL(p,0,reskey);
+ p += 4;
+ }
+ put_dos_date2(p,l2_fdateCreation,cdate);
+ put_dos_date2(p,l2_fdateLastAccess,adate);
+ put_dos_date2(p,l2_fdateLastWrite,mdate);
+ SIVAL(p,l2_cbFile,(uint32)file_size);
+ SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size);
+ SSVAL(p,l2_attrFile,mode);
+ {
+ unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+ SIVAL(p,l2_cbList,ea_size); /* Extended attributes */
+ }
+ p += l2_achName;
+ nameptr = p - 1;
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE | STR_NOALIGN);
+ if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
+ if (len > 2) {
+ len -= 2;
+ } else {
+ len = 0;
+ }
+ } else {
+ if (len > 1) {
+ len -= 1;
+ } else {
+ len = 0;
+ }
+ }
+ SCVAL(nameptr,0,len);
+ p += len;
+ SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
+ break;
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
+ was_8_3 = mangle_is_8_3(fname, True);
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,file_size); p += 8;
+ SOFF_T(p,0,allocation_size); p += 8;
+ SIVAL(p,0,nt_extmode); p += 4;
+ q = p; p += 4; /* q is placeholder for name length. */
+ {
+ unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+ SIVAL(p,0,ea_size); /* Extended attributes */
+ p += 4;
+ }
+ /* Clear the short name buffer. This is
+ * IMPORTANT as not doing so will trigger
+ * a Win2k client bug. JRA.
+ */
+ memset(p,'\0',26);
+ if (!was_8_3 && lp_manglednames(SNUM(conn))) {
+ pstring mangled_name;
+ pstrcpy(mangled_name, fname);
+ mangle_map(mangled_name,True,True,SNUM(conn));
+ mangled_name[12] = 0;
+ len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
+ SSVAL(p, 0, len);
+ } else {
+ SSVAL(p,0,0);
+ *(p+2) = 0;
+ }
+ p += 2 + 24;
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+ SIVAL(q,0,len);
+ p += len;
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,file_size); p += 8;
+ SOFF_T(p,0,allocation_size); p += 8;
+ SIVAL(p,0,nt_extmode); p += 4;
+ len = srvstr_push(outbuf, p + 4, fname, -1, STR_TERMINATE_ASCII);
+ SIVAL(p,0,len);
+ p += 4 + len;
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,file_size); p += 8;
+ SOFF_T(p,0,allocation_size); p += 8;
+ SIVAL(p,0,nt_extmode); p += 4;
+ q = p; p += 4; /* q is placeholder for name length. */
+ {
+ unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+ SIVAL(p,0,ea_size); /* Extended attributes */
+ p +=4;
+ }
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+ SIVAL(q, 0, len);
+ p += len;
+
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ p += 4;
+ /* this must *not* be null terminated or w2k gets in a loop trying to set an
+ acl on a dir (tridge) */
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+ SIVAL(p, -4, len);
+ p += len;
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_ID_FULL_DIRECTORY_INFO:
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,file_size); p += 8;
+ SOFF_T(p,0,allocation_size); p += 8;
+ SIVAL(p,0,nt_extmode); p += 4;
+ q = p; p += 4; /* q is placeholder for name length. */
+ {
+ unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+ SIVAL(p,0,ea_size); /* Extended attributes */
+ p +=4;
+ }
+ SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
+ SIVAL(p,0,sbuf.st_dev); p += 4;
+ SIVAL(p,0,sbuf.st_ino); p += 4;
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+ SIVAL(q, 0, len);
+ p += len;
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
+ was_8_3 = mangle_is_8_3(fname, True);
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,file_size); p += 8;
+ SOFF_T(p,0,allocation_size); p += 8;
+ SIVAL(p,0,nt_extmode); p += 4;
+ q = p; p += 4; /* q is placeholder for name length */
+ {
+ unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+ SIVAL(p,0,ea_size); /* Extended attributes */
+ p +=4;
+ }
+ /* Clear the short name buffer. This is
+ * IMPORTANT as not doing so will trigger
+ * a Win2k client bug. JRA.
+ */
+ memset(p,'\0',26);
+ if (!was_8_3 && lp_manglednames(SNUM(conn))) {
+ pstring mangled_name;
+ pstrcpy(mangled_name, fname);
+ mangle_map(mangled_name,True,True,SNUM(conn));
+ mangled_name[12] = 0;
+ len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
+ SSVAL(p, 0, len);
+ } else {
+ SSVAL(p,0,0);
+ *(p+2) = 0;
+ }
+ p += 26;
+ SSVAL(p,0,0); p += 2; /* Reserved ? */
+ SIVAL(p,0,sbuf.st_dev); p += 4;
+ SIVAL(p,0,sbuf.st_ino); p += 4;
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+ SIVAL(q,0,len);
+ p += len;
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ /* CIFS UNIX Extension. */
+
+ case SMB_FIND_FILE_UNIX:
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
+ p+= 4;
+ SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
+
+ /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
+ SOFF_T(p,0,get_file_size(sbuf)); /* File size 64 Bit */
+ p+= 8;
+
+ SOFF_T(p,0,get_allocation_size(NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */
+ p+= 8;
+
+ put_long_date(p,sbuf.st_ctime); /* Inode change Time 64 Bit */
+ put_long_date(p+8,sbuf.st_atime); /* Last access time 64 Bit */
+ put_long_date(p+16,sbuf.st_mtime); /* Last modification time 64 Bit */
+ p+= 24;
+
+ SIVAL(p,0,sbuf.st_uid); /* user id for the owner */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ SIVAL(p,0,sbuf.st_gid); /* group id of owner */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ SIVAL(p,0,unix_filetype(sbuf.st_mode));
+ p+= 4;
+
+ SIVAL(p,0,unix_dev_major(sbuf.st_rdev)); /* Major device number if type is device */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ SIVAL(p,0,unix_dev_minor(sbuf.st_rdev)); /* Minor device number if type is device */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ SINO_T(p,0,(SMB_INO_T)sbuf.st_ino); /* inode number */
+ p+= 8;
+
+ SIVAL(p,0, unix_perms_to_wire(sbuf.st_mode)); /* Standard UNIX file permissions */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ SIVAL(p,0,sbuf.st_nlink); /* number of hard links */
+ SIVAL(p,4,0);
+ p+= 8;
+
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
+ p += len;
+
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len); /* Offset from this structure to the beginning of the next one */
+ p = pdata + len;
+ /* End of SMB_QUERY_FILE_UNIX_BASIC */
+
+ break;
+
+ default:
+ return(False);
+ }
+ DEBUG(10,("at exit: conn 0x%p, outbuf 0x%p, ppdata 0x%p, pp 0x%p, "
+ "fname %s, pathreal %s, dirtype %d, info_level %d, "
+ "requires_resume_key %d, base_data 0x%p\n",
+ conn, outbuf, ppdata, pp, fname, pathreal, dirtype,
+ info_level, requires_resume_key, base_data));
+ DEBUG(10,("at exit: pdata = 0x%p, p = 0x%p\n", pdata, p));
+ *ppdata = pdata;
+ *pp = p;
+ *last_name_off = PTR_DIFF(nameptr,base_data);
+ return(True);
+}
+
-------------- next part --------------
diff -Naur samba-3.0.8.orig/source/smbd/trans2.c samba-3.0.8/source/smbd/trans2.c
--- samba-3.0.8.orig/source/smbd/trans2.c 2004-11-07 14:43:23.000000000 -0600
+++ samba-3.0.8/source/smbd/trans2.c 2004-12-10 15:43:50.000000000 -0600
@@ -815,172 +815,61 @@
}
}
-/****************************************************************************
- Get a level dependent lanman2 dir entry.
-****************************************************************************/
-
-static BOOL get_lanman2_dir_entry(connection_struct *conn,
- void *inbuf, void *outbuf,
- char *path_mask,int dirtype,int info_level,
- int requires_resume_key,
- BOOL dont_descend,char **ppdata,
- char *base_data, int space_remaining,
- BOOL *out_of_space, BOOL *got_exact_match,
- int *last_name_off)
+/**************************************************************************
+ * Actually opulate the lanman buffer pointed to by *ppdata. Split out
+ * of get_lanman2_dir_entry so that we could short-circuit the dirptr
+ * operations where possible.
+ **************************************************************************/
+static BOOL populate_lanman2_dir_entry(connection_struct *conn,
+ void *outbuf, char** ppdata, char** pp,
+ pstring fname, pstring pathreal,
+ int dirtype, int info_level,
+ int requires_resume_key,
+ SMB_STRUCT_STAT sbuf, char* base_data, int* last_name_off)
{
- const char *dname;
- BOOL found = False;
- SMB_STRUCT_STAT sbuf;
- pstring mask;
- pstring pathreal;
- pstring fname;
- char *p, *q, *pdata = *ppdata;
- uint32 reskey=0;
- int prev_dirpos=0;
- int mode=0;
- SMB_OFF_T file_size = 0;
- SMB_BIG_UINT allocation_size = 0;
- uint32 len;
- time_t mdate=0, adate=0, cdate=0;
- char *nameptr;
- BOOL was_8_3;
+ BOOL was_8_3 = False;
+ SMB_OFF_T file_size;
+ SMB_BIG_UINT allocation_size;
+ int len = 0;
+ char *pdata = *ppdata;
+ char *p = *pp;
+ char *nameptr = p;
+ char *q;
+ int mode;
+ int cdate, mdate, adate;
int nt_extmode; /* Used for NT connections instead of mode */
- BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
-
- *fname = 0;
- *out_of_space = False;
- *got_exact_match = False;
-
- if (!conn->dirptr)
- return(False);
-
- p = strrchr_m(path_mask,'/');
- if(p != NULL) {
- if(p[1] == '\0')
- pstrcpy(mask,"*.*");
- else
- pstrcpy(mask, p+1);
- } else
- pstrcpy(mask, path_mask);
-
- while (!found) {
- BOOL got_match;
-
- /* Needed if we run out of space */
- prev_dirpos = TellDir(conn->dirptr);
- dname = ReadDirName(conn->dirptr);
-
- /*
- * Due to bugs in NT client redirectors we are not using
- * resume keys any more - set them to zero.
- * Check out the related comments in findfirst/findnext.
- * JRA.
- */
-
- reskey = 0;
-
- DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
- (long)conn->dirptr,TellDir(conn->dirptr)));
-
- if (!dname)
- return(False);
-
- pstrcpy(fname,dname);
-
- if(!(got_match = *got_exact_match = exact_match(fname, mask, conn->case_sensitive)))
- got_match = mask_match(fname, mask, conn->case_sensitive);
-
- if(!got_match && !mangle_is_8_3(fname, False)) {
-
- /*
- * It turns out that NT matches wildcards against
- * both long *and* short names. This may explain some
- * of the wildcard wierdness from old DOS clients
- * that some people have been seeing.... JRA.
- */
-
- pstring newname;
- pstrcpy( newname, fname);
- mangle_map( newname, True, False, SNUM(conn));
- if(!(got_match = *got_exact_match = exact_match(newname, mask, conn->case_sensitive)))
- got_match = mask_match(newname, mask, conn->case_sensitive);
- }
-
- if(got_match) {
- BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
- if (dont_descend && !isdots)
- continue;
-
- pstrcpy(pathreal,conn->dirpath);
- if(needslash)
- pstrcat(pathreal,"/");
- pstrcat(pathreal,dname);
+ uint32 reskey = 0;
- if (INFO_LEVEL_IS_UNIX(info_level)) {
- if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) {
- DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n",
- pathreal,strerror(errno)));
- continue;
- }
- } else if (SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
+ DEBUG(10,("conn 0x%p, outbuf 0x%p, ppdata 0x%p, pp 0x%p, fname %s, pathreal %s, dirtype %d, info_level %d, requires_resume_key %d, base_data 0x%p\n",
+ conn, outbuf, ppdata, pp, fname, pathreal, dirtype, info_level, requires_resume_key, base_data));
- /* Needed to show the msdfs symlinks as
- * directories */
-
- if(lp_host_msdfs() &&
- lp_msdfs_root(SNUM(conn)) &&
- is_msdfs_link(conn, pathreal, NULL, NULL,
- &sbuf)) {
-
- DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal));
- sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
-
- } else {
-
- DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",
- pathreal,strerror(errno)));
- continue;
- }
- }
-
- mode = dos_mode(conn,pathreal,&sbuf);
-
- if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
- DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
- continue;
- }
-
- file_size = get_file_size(sbuf);
- allocation_size = get_allocation_size(NULL,&sbuf);
- mdate = sbuf.st_mtime;
- adate = sbuf.st_atime;
- cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
-
- if (lp_dos_filetime_resolution(SNUM(conn))) {
- cdate &= ~1;
- mdate &= ~1;
- adate &= ~1;
- }
+ mode = dos_mode(conn,pathreal,&sbuf);
+ DEBUG(5,("dos mode is %d\n",mode));
+ if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
+ DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
+ return False;
+ }
- if(mode & aDIR)
- file_size = 0;
+ file_size = get_file_size(sbuf);
+ allocation_size = get_allocation_size(NULL,&sbuf);
+ mdate = sbuf.st_mtime;
+ adate = sbuf.st_atime;
+ cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
- DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
-
- found = True;
- }
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ cdate &= ~1;
+ mdate &= ~1;
+ adate &= ~1;
}
- mangle_map(fname,False,True,SNUM(conn));
-
- p = pdata;
- nameptr = p;
+ if(mode & aDIR)
+ file_size = 0;
nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
switch (info_level) {
case SMB_INFO_STANDARD:
- DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_STANDARD\n"));
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_INFO_STANDARD\n"));
if(requires_resume_key) {
SIVAL(p,0,reskey);
p += 4;
@@ -1012,7 +901,7 @@
break;
case SMB_INFO_QUERY_EA_SIZE:
- DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_QUERY_EA_SIZE\n"));
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_INFO_QUERY_EA_SIZE\n"));
if(requires_resume_key) {
SIVAL(p,0,reskey);
p += 4;
@@ -1049,7 +938,7 @@
break;
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
was_8_3 = mangle_is_8_3(fname, True);
p += 4;
SIVAL(p,0,reskey); p += 4;
@@ -1093,7 +982,7 @@
break;
case SMB_FIND_FILE_DIRECTORY_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
p += 4;
SIVAL(p,0,reskey); p += 4;
put_long_date(p,cdate); p += 8;
@@ -1113,7 +1002,7 @@
break;
case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
p += 4;
SIVAL(p,0,reskey); p += 4;
put_long_date(p,cdate); p += 8;
@@ -1140,7 +1029,7 @@
break;
case SMB_FIND_FILE_NAMES_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
p += 4;
SIVAL(p,0,reskey); p += 4;
p += 4;
@@ -1156,7 +1045,7 @@
break;
case SMB_FIND_ID_FULL_DIRECTORY_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
p += 4;
SIVAL(p,0,reskey); p += 4;
put_long_date(p,cdate); p += 8;
@@ -1185,7 +1074,7 @@
break;
case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
was_8_3 = mangle_is_8_3(fname, True);
p += 4;
SIVAL(p,0,reskey); p += 4;
@@ -1234,7 +1123,7 @@
/* CIFS UNIX Extension. */
case SMB_FIND_FILE_UNIX:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
+ DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
p+= 4;
SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
@@ -1294,8 +1183,170 @@
default:
return(False);
}
+ DEBUG(10,("at exit: conn 0x%p, outbuf 0x%p, ppdata 0x%p, pp 0x%p, "
+ "fname %s, pathreal %s, dirtype %d, info_level %d, "
+ "requires_resume_key %d, base_data 0x%p\n",
+ conn, outbuf, ppdata, pp, fname, pathreal, dirtype,
+ info_level, requires_resume_key, base_data));
+ DEBUG(10,("at exit: pdata = 0x%p, p = 0x%p\n", pdata, p));
+ *ppdata = pdata;
+ *pp = p;
+ *last_name_off = PTR_DIFF(nameptr,base_data);
+ return(True);
+}
+
+
+/****************************************************************************
+ Get a level dependent lanman2 dir entry.
+****************************************************************************/
+
+static BOOL get_lanman2_dir_entry(connection_struct *conn,
+ void *inbuf, void *outbuf,
+ char *path_mask,int dirtype,int info_level,
+ int requires_resume_key,
+ BOOL dont_descend,char **ppdata,
+ char *base_data, int space_remaining,
+ BOOL *out_of_space, BOOL *got_exact_match,
+ int *last_name_off)
+{
+ const char *dname;
+ BOOL found = False;
+ SMB_STRUCT_STAT sbuf;
+ pstring mask;
+ pstring pathreal;
+ pstring fname;
+ char *p, *pdata = *ppdata;
+ uint32 reskey=0;
+ int prev_dirpos=0;
+ int mode=0;
+ char *nameptr;
+ BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
+
+ *fname = 0;
+ *out_of_space = False;
+ *got_exact_match = False;
+
+ if (!conn->dirptr)
+ return(False);
+
+ p = strrchr_m(path_mask,'/');
+ if(p != NULL) {
+ if(p[1] == '\0')
+ pstrcpy(mask,"*.*");
+ else
+ pstrcpy(mask, p+1);
+ } else
+ pstrcpy(mask, path_mask);
+
+ while (!found) {
+ BOOL got_match;
+
+ /* Needed if we run out of space */
+ prev_dirpos = TellDir(conn->dirptr);
+ dname = ReadDirName(conn->dirptr);
+
+ /*
+ * Due to bugs in NT client redirectors we are not using
+ * resume keys any more - set them to zero.
+ * Check out the related comments in findfirst/findnext.
+ * JRA.
+ */
+
+ reskey = 0;
+
+ DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
+ (long)conn->dirptr,TellDir(conn->dirptr)));
+
+ if (!dname)
+ return(False);
+
+ pstrcpy(fname,dname);
+
+ if(!(got_match = *got_exact_match = exact_match(fname, mask, conn->case_sensitive)))
+ got_match = mask_match(fname, mask, conn->case_sensitive);
+
+ if(!got_match && !mangle_is_8_3(fname, False)) {
+
+ /*
+ * It turns out that NT matches wildcards against
+ * both long *and* short names. This may explain some
+ * of the wildcard wierdness from old DOS clients
+ * that some people have been seeing.... JRA.
+ */
+
+ pstring newname;
+ pstrcpy( newname, fname);
+ mangle_map( newname, True, False, SNUM(conn));
+ if(!(got_match = *got_exact_match = exact_match(newname, mask, conn->case_sensitive)))
+ got_match = mask_match(newname, mask, conn->case_sensitive);
+ }
+
+ if(got_match) {
+ BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
+ if (dont_descend && !isdots)
+ continue;
+
+ pstrcpy(pathreal,conn->dirpath);
+ if(needslash)
+ pstrcat(pathreal,"/");
+ pstrcat(pathreal,dname);
+
+ if (INFO_LEVEL_IS_UNIX(info_level)) {
+ if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) {
+ DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n",
+ pathreal,strerror(errno)));
+ continue;
+ }
+ } else if (SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
+
+ /* Needed to show the msdfs symlinks as
+ * directories */
+
+ if(lp_host_msdfs() &&
+ lp_msdfs_root(SNUM(conn)) &&
+ is_msdfs_link(conn, pathreal, NULL, NULL,
+ &sbuf)) {
+
+ DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal));
+ sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
+
+ } else {
+
+ DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",
+ pathreal,strerror(errno)));
+ continue;
+ }
+ }
+
+ DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
+
+ mode = dos_mode(conn,pathreal,&sbuf);
+
+ if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
+ DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
+ return False;
+ }
+ found = True;
+ }
+ }
+
+ mangle_map(fname,False,True,SNUM(conn));
+ p = pdata;
+ nameptr = p;
+ if(!populate_lanman2_dir_entry(conn,
+ outbuf, ppdata, &p,
+ fname, pathreal,
+ dirtype, info_level,
+ requires_resume_key,
+ sbuf, base_data, last_name_off)) {
+ /* Some problem we should probably do a better job of handling... */
+ DEBUG(3,("populate_lanman2_dir_entry failed!"));
+ return False;
+ }
+
+
if (PTR_DIFF(p,pdata) > space_remaining) {
/* Move the dirptr back to prev_dirpos */
SeekDir(conn->dirptr, prev_dirpos);
@@ -1305,7 +1356,7 @@
}
/* Setup the last_filename pointer, as an offset from base_data */
- *last_name_off = PTR_DIFF(nameptr,base_data);
+ /* *last_name_off = PTR_DIFF(nameptr,base_data); */
/* Advance the data pointer to the next slot */
*ppdata = p;
@@ -1424,84 +1475,124 @@
return ERROR_DOS(ERRDOS,ERRnomem);
*pparams = params;
- dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
- if (dptr_num < 0)
- return(UNIXERROR(ERRDOS,ERRbadfile));
-
- /* Save the wildcard match and attribs we are using on this directory -
- needed as lanman2 assumes these are being saved between calls */
-
- if(!(wcard = strdup(mask))) {
- dptr_close(&dptr_num);
- return ERROR_DOS(ERRDOS,ERRnomem);
- }
-
- dptr_set_wcard(dptr_num, wcard);
- dptr_set_attr(dptr_num, dirtype);
-
- DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
-
- /* We don't need to check for VOL here as this is returned by
- a different TRANS2 call. */
-
- DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn))));
- if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
- dont_descend = True;
-
- p = pdata;
- space_remaining = max_data_bytes;
- out_of_space = False;
-
- for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
- BOOL got_exact_match = False;
-
- /* this is a heuristic to avoid seeking the dirptr except when
- absolutely necessary. It allows for a filename of about 40 chars */
- if (space_remaining < DIRLEN_GUESS && numentries > 0) {
- out_of_space = True;
- finished = False;
- } else {
- finished = !get_lanman2_dir_entry(conn,
+ /* Optimization: if we are in case-sensitive mode and the mask contains
+ * no wildcards, the file exists iff SMB_VFS_STAT can find it. MM */
+ if ((conn->case_sensitive && !ms_has_wild(mask))
+ && (close_after_first || close_if_end)) {
+ DEBUG(5,("case sensitive and no wilds; using VFS result\n"));
+ /* stat buffer from unix_convert should still be valid here */
+ if (sbuf.st_nlink == 0) {
+ DEBUG(5,("sbuf.st_nlink was 0 -> not found\n"));
+ return(ERROR_DOS(ERRDOS,ERRbadfile));
+ } else {
+ pstring pathreal;
+ char* strp;
+ DEBUG(5,("sbuf.st_nlink was non-0 -> found\n"));
+ strp = pstrcpy(pathreal, directory);
+ strp = pstrcpy(strp, "/");
+ strp = pstrcpy(strp, mask);
+ dptr_num = -3; /* should really not be harcoded here */
+ numentries = 1;
+ finished = True;
+ p = pdata;
+ /* Fabricate a response without using the dirptr. */
+ populate_lanman2_dir_entry(conn,
+ outbuf, &pdata, &p,
+ mask, pathreal,
+ dirtype, info_level,
+ requires_resume_key,
+ sbuf, pdata, &last_name_off);
+
+ /*finished = !get_lanman2_dir_entry(conn,
inbuf, outbuf,
mask,dirtype,info_level,
requires_resume_key,dont_descend,
&p,pdata,space_remaining, &out_of_space, &got_exact_match,
&last_name_off);
+ */
+ }
+ } else {
+
+ dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
+ if (dptr_num < 0)
+ return(UNIXERROR(ERRDOS,ERRbadfile));
+
+ /* Save the wildcard match and attribs we are using on this directory -
+ needed as lanman2 assumes these are being saved between calls */
+
+ if(!(wcard = strdup(mask))) {
+ dptr_close(&dptr_num);
+ return ERROR_DOS(ERRDOS,ERRnomem);
}
- if (finished && out_of_space)
- finished = False;
+ dptr_set_wcard(dptr_num, wcard);
+ dptr_set_attr(dptr_num, dirtype);
- if (!finished && !out_of_space)
- numentries++;
+ DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
- /*
- * As an optimisation if we know we aren't looking
- * for a wildcard name (ie. the name matches the wildcard exactly)
- * then we can finish on any (first) match.
- * This speeds up large directory searches. JRA.
- */
+ /* We don't need to check for VOL here as this is returned by
+ a different TRANS2 call. */
+
+ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn))));
+ if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
+ dont_descend = True;
+
+ p = pdata;
+ space_remaining = max_data_bytes;
+ out_of_space = False;
+
+ for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
+ BOOL got_exact_match = False;
+
+ /* this is a heuristic to avoid seeking the dirptr except when
+ absolutely necessary. It allows for a filename of about 40 chars */
+ if (space_remaining < DIRLEN_GUESS && numentries > 0) {
+ out_of_space = True;
+ finished = False;
+ } else {
+ finished = !get_lanman2_dir_entry(conn,
+ inbuf, outbuf,
+ mask,dirtype,info_level,
+ requires_resume_key,dont_descend,
+ &p,pdata,space_remaining, &out_of_space, &got_exact_match,
+ &last_name_off);
+ }
- if(got_exact_match)
- finished = True;
+ if (finished && out_of_space)
+ finished = False;
- space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
- }
-
- /* Check if we can close the dirptr */
- if(close_after_first || (finished && close_if_end)) {
- DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
- dptr_close(&dptr_num);
- }
+ if (!finished && !out_of_space)
+ numentries++;
- /*
- * If there are no matching entries we must return ERRDOS/ERRbadfile -
- * from observation of NT.
- */
+ /*
+ * As an optimisation if we know we aren't looking
+ * for a wildcard name (ie. the name matches the wildcard exactly)
+ * then we can finish on any (first) match.
+ * This speeds up large directory searches. JRA.
+ */
+
+ if(got_exact_match)
+ finished = True;
+
+ space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+ }
+
+ /* Check if we can close the dirptr */
+ if(close_after_first || (finished && close_if_end)) {
+ DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
+ dptr_close(&dptr_num);
+ }
+
+ /*
+ * If there are no matching entries we must return ERRDOS/ERRbadfile -
+ * from observation of NT.
+ */
+
+ if(numentries == 0) {
+ dptr_close(&dptr_num);
+ return ERROR_DOS(ERRDOS,ERRbadfile);
+ }
- if(numentries == 0) {
- dptr_close(&dptr_num);
- return ERROR_DOS(ERRDOS,ERRbadfile);
}
/* At this point pdata points to numentries directory entries. */
More information about the samba-technical
mailing list