s3:smbd: split the dir entry marshalling into smbd_marshall_dir_entry()
authorStefan Metzmacher <metze@samba.org>
Thu, 6 Aug 2009 10:15:51 +0000 (12:15 +0200)
committerStefan Metzmacher <metze@samba.org>
Fri, 7 Aug 2009 12:18:18 +0000 (14:18 +0200)
So that we can reuse it for SMB2 Find.

metze

source3/smbd/trans2.c

index 9273339b71cda3075b6c000f50c90e97e49255c3..780d7d606c7b1ccf081e305833b4fd69120a76cc 100644 (file)
@@ -1446,88 +1446,41 @@ static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
        return true;
 }
 
-static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
-                               connection_struct *conn,
-                               struct dptr_struct *dirptr,
-                               uint16 flags2,
-                               const char *path_mask,
-                               uint32 dirtype,
-                               int info_level,
-                               int requires_resume_key,
-                               bool dont_descend,
-                               bool ask_sharemode,
-                               char **ppdata,
-                               char *base_data,
-                               char *end_data,
-                               int space_remaining,
-                               bool *out_of_space,
-                               bool *got_exact_match,
-                               int *last_entry_off,
-                               struct ea_list *name_list)
+static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
+                                   connection_struct *conn,
+                                   uint16_t flags2,
+                                   uint32_t info_level,
+                                   struct ea_list *name_list,
+                                   bool check_mangled_names,
+                                   bool requires_resume_key,
+                                   uint32_t mode,
+                                   const char *fname,
+                                   const struct smb_filename *smb_fname,
+                                   uint64_t space_remaining,
+                                   char *base_data,
+                                   char **ppdata,
+                                   char *end_data,
+                                   bool *out_of_space,
+                                   uint64_t *last_entry_off)
 {
-       const char *mask = NULL;
        char *p, *q, *pdata = *ppdata;
-       uint32 reskey=0;
-       long prev_dirpos=0;
-       uint32 mode=0;
-       SMB_OFF_T file_size = 0;
+       uint32_t reskey=0;
+       uint64_t file_size = 0;
        uint64_t allocation_size = 0;
-       uint32 len;
+       uint32_t len;
        struct timespec mdate_ts, adate_ts, create_date_ts;
        time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
        char *nameptr;
        char *last_entry_ptr;
        bool was_8_3;
-       uint32 nt_extmode; /* Used for NT connections instead of mode */
-       char *fname = NULL;
-       struct smb_filename *smb_fname = NULL;
-       struct smbd_dirptr_lanman2_state state;
-       bool ok;
+       uint32_t nt_extmode; /* Used for NT connections instead of mode */
 
-       ZERO_STRUCT(state);
-       state.conn = conn;
-       state.info_level = info_level;
-       state.check_mangled_names = lp_manglednames(conn->params);
-       state.has_wild = dptr_has_wild(dirptr);
-       state.got_exact_match = false;
-
-       *out_of_space = False;
-       *got_exact_match = False;
+       *out_of_space = false;
 
        ZERO_STRUCT(mdate_ts);
        ZERO_STRUCT(adate_ts);
        ZERO_STRUCT(create_date_ts);
 
-       p = strrchr_m(path_mask,'/');
-       if(p != NULL) {
-               if(p[1] == '\0') {
-                       mask = "*.*";
-               } else {
-                       mask = p+1;
-               }
-       } else {
-               mask = path_mask;
-       }
-
-       ok = smbd_dirptr_get_entry(ctx,
-                                  dirptr,
-                                  mask,
-                                  dirtype,
-                                  dont_descend,
-                                  ask_sharemode,
-                                  smbd_dirptr_lanman2_match_fn,
-                                  smbd_dirptr_lanman2_mode_fn,
-                                  &state,
-                                  &fname,
-                                  &smb_fname,
-                                  &mode,
-                                  &prev_dirpos);
-       if (!ok) {
-               return false;
-       }
-
-       *got_exact_match = state.got_exact_match;
-
        if (!(mode & aDIR)) {
                file_size = get_file_size_stat(&smb_fname->st);
        }
@@ -1553,418 +1506,405 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
        nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
 
        switch (info_level) {
-               case SMB_FIND_INFO_STANDARD:
-                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_INFO_STANDARD\n"));
-                       if(requires_resume_key) {
-                               SIVAL(p,0,reskey);
-                               p += 4;
-                       }
-                       srv_put_dos_date2(p,0,create_date);
-                       srv_put_dos_date2(p,4,adate);
-                       srv_put_dos_date2(p,8,mdate);
-                       SIVAL(p,12,(uint32)file_size);
-                       SIVAL(p,16,(uint32)allocation_size);
-                       SSVAL(p,20,mode);
-                       p += 23;
-                       nameptr = p;
-                       if (flags2 & FLAGS2_UNICODE_STRINGS) {
-                               p += ucs2_align(base_data, p, 0);
-                       }
-                       len = srvstr_push(base_data, flags2, p,
-                                         fname, PTR_DIFF(end_data, p),
-                                         STR_TERMINATE);
-                       if (flags2 & FLAGS2_UNICODE_STRINGS) {
-                               if (len > 2) {
-                                       SCVAL(nameptr, -1, len - 2);
-                               } else {
-                                       SCVAL(nameptr, -1, 0);
-                               }
+       case SMB_FIND_INFO_STANDARD:
+               DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_INFO_STANDARD\n"));
+               if(requires_resume_key) {
+                       SIVAL(p,0,reskey);
+                       p += 4;
+               }
+               srv_put_dos_date2(p,0,create_date);
+               srv_put_dos_date2(p,4,adate);
+               srv_put_dos_date2(p,8,mdate);
+               SIVAL(p,12,(uint32)file_size);
+               SIVAL(p,16,(uint32)allocation_size);
+               SSVAL(p,20,mode);
+               p += 23;
+               nameptr = p;
+               if (flags2 & FLAGS2_UNICODE_STRINGS) {
+                       p += ucs2_align(base_data, p, 0);
+               }
+               len = srvstr_push(base_data, flags2, p,
+                                 fname, PTR_DIFF(end_data, p),
+                                 STR_TERMINATE);
+               if (flags2 & FLAGS2_UNICODE_STRINGS) {
+                       if (len > 2) {
+                               SCVAL(nameptr, -1, len - 2);
                        } else {
-                               if (len > 1) {
-                                       SCVAL(nameptr, -1, len - 1);
-                               } else {
-                                       SCVAL(nameptr, -1, 0);
-                               }
-                       }
-                       p += len;
-                       break;
-
-               case SMB_FIND_EA_SIZE:
-                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_SIZE\n"));
-                       if(requires_resume_key) {
-                               SIVAL(p,0,reskey);
-                               p += 4;
-                       }
-                       srv_put_dos_date2(p,0,create_date);
-                       srv_put_dos_date2(p,4,adate);
-                       srv_put_dos_date2(p,8,mdate);
-                       SIVAL(p,12,(uint32)file_size);
-                       SIVAL(p,16,(uint32)allocation_size);
-                       SSVAL(p,20,mode);
-                       {
-                               unsigned int ea_size = estimate_ea_size(conn, NULL,
-                                                                       smb_fname->base_name);
-                               SIVAL(p,22,ea_size); /* Extended attributes */
+                               SCVAL(nameptr, -1, 0);
                        }
-                       p += 27;
-                       nameptr = p - 1;
-                       len = srvstr_push(base_data, flags2,
-                                         p, fname, PTR_DIFF(end_data, p),
-                                         STR_TERMINATE | STR_NOALIGN);
-                       if (flags2 & FLAGS2_UNICODE_STRINGS) {
-                               if (len > 2) {
-                                       len -= 2;
-                               } else {
-                                       len = 0;
-                               }
+               } else {
+                       if (len > 1) {
+                               SCVAL(nameptr, -1, len - 1);
                        } else {
-                               if (len > 1) {
-                                       len -= 1;
-                               } else {
-                                       len = 0;
-                               }
+                               SCVAL(nameptr, -1, 0);
                        }
-                       SCVAL(nameptr,0,len);
-                       p += len;
-                       SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
-                       break;
+               }
+               p += len;
+               break;
 
-               case SMB_FIND_EA_LIST:
+       case SMB_FIND_EA_SIZE:
+               DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_SIZE\n"));
+               if (requires_resume_key) {
+                       SIVAL(p,0,reskey);
+                       p += 4;
+               }
+               srv_put_dos_date2(p,0,create_date);
+               srv_put_dos_date2(p,4,adate);
+               srv_put_dos_date2(p,8,mdate);
+               SIVAL(p,12,(uint32)file_size);
+               SIVAL(p,16,(uint32)allocation_size);
+               SSVAL(p,20,mode);
                {
-                       struct ea_list *file_list = NULL;
-                       size_t ea_len = 0;
-
-                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_LIST\n"));
-                       if (!name_list) {
-                               TALLOC_FREE(fname);
-                               TALLOC_FREE(smb_fname);
-                               return False;
-                       }
-                       if(requires_resume_key) {
-                               SIVAL(p,0,reskey);
-                               p += 4;
-                       }
-                       srv_put_dos_date2(p,0,create_date);
-                       srv_put_dos_date2(p,4,adate);
-                       srv_put_dos_date2(p,8,mdate);
-                       SIVAL(p,12,(uint32)file_size);
-                       SIVAL(p,16,(uint32)allocation_size);
-                       SSVAL(p,20,mode);
-                       p += 22; /* p now points to the EA area. */
-
-                       file_list = get_ea_list_from_file(ctx, conn, NULL,
-                                                         smb_fname->base_name,
-                                                         &ea_len);
-                       name_list = ea_list_union(name_list, file_list, &ea_len);
-
-                       /* We need to determine if this entry will fit in the space available. */
-                       /* Max string size is 255 bytes. */
-                       if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
-                               TALLOC_FREE(fname);
-                               TALLOC_FREE(smb_fname);
-                               /* Move the dirptr back to prev_dirpos */
-                               dptr_SeekDir(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 */
+                       unsigned int ea_size = estimate_ea_size(conn, NULL,
+                                                               smb_fname->base_name);
+                       SIVAL(p,22,ea_size); /* Extended attributes */
+               }
+               p += 27;
+               nameptr = p - 1;
+               len = srvstr_push(base_data, flags2,
+                                 p, fname, PTR_DIFF(end_data, p),
+                                 STR_TERMINATE | STR_NOALIGN);
+               if (flags2 & FLAGS2_UNICODE_STRINGS) {
+                       if (len > 2) {
+                               len -= 2;
+                       } else {
+                               len = 0;
                        }
-
-                       /* Push the ea_data followed by the name. */
-                       p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
-                       nameptr = p;
-                       len = srvstr_push(base_data, flags2,
-                                         p + 1, fname, PTR_DIFF(end_data, p+1),
-                                         STR_TERMINATE | STR_NOALIGN);
-                       if (flags2 & FLAGS2_UNICODE_STRINGS) {
-                               if (len > 2) {
-                                       len -= 2;
-                               } else {
-                                       len = 0;
-                               }
+               } else {
+                       if (len > 1) {
+                               len -= 1;
                        } else {
-                               if (len > 1) {
-                                       len -= 1;
-                               } else {
-                                       len = 0;
-                               }
+                               len = 0;
                        }
-                       SCVAL(nameptr,0,len);
-                       p += len + 1;
-                       SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
-                       break;
                }
+               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,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
-                       was_8_3 = mangle_is_8_3(fname, True, conn->params);
+       case SMB_FIND_EA_LIST:
+       {
+               struct ea_list *file_list = NULL;
+               size_t ea_len = 0;
+
+               DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_LIST\n"));
+               if (!name_list) {
+                       return false;
+               }
+               if (requires_resume_key) {
+                       SIVAL(p,0,reskey);
                        p += 4;
-                       SIVAL(p,0,reskey); p += 4;
-                       put_long_date_timespec(p,create_date_ts); p += 8;
-                       put_long_date_timespec(p,adate_ts); p += 8;
-                       put_long_date_timespec(p,mdate_ts); p += 8;
-                       put_long_date_timespec(p,mdate_ts); 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,
-                                                                       smb_fname->base_name);
-                               SIVAL(p,0,ea_size); /* Extended attributes */
-                               p += 4;
+               }
+               srv_put_dos_date2(p,0,create_date);
+               srv_put_dos_date2(p,4,adate);
+               srv_put_dos_date2(p,8,mdate);
+               SIVAL(p,12,(uint32)file_size);
+               SIVAL(p,16,(uint32)allocation_size);
+               SSVAL(p,20,mode);
+               p += 22; /* p now points to the EA area. */
+
+               file_list = get_ea_list_from_file(ctx, conn, NULL,
+                                                 smb_fname->base_name,
+                                                 &ea_len);
+               name_list = ea_list_union(name_list, file_list, &ea_len);
+
+               /* We need to determine if this entry will fit in the space available. */
+               /* Max string size is 255 bytes. */
+               if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
+                       *out_of_space = true;
+                       DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
+                       return False; /* Not finished - just out of space */
+               }
+
+               /* Push the ea_data followed by the name. */
+               p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
+               nameptr = p;
+               len = srvstr_push(base_data, flags2,
+                                 p + 1, fname, PTR_DIFF(end_data, p+1),
+                                 STR_TERMINATE | STR_NOALIGN);
+               if (flags2 & FLAGS2_UNICODE_STRINGS) {
+                       if (len > 2) {
+                               len -= 2;
+                       } else {
+                               len = 0;
                        }
-                       /* Clear the short name buffer. This is
-                        * IMPORTANT as not doing so will trigger
-                        * a Win2k client bug. JRA.
-                        */
-                       if (!was_8_3 && state.check_mangled_names) {
-                               char mangled_name[13]; /* mangled 8.3 name. */
-                               if (!name_to_8_3(fname,mangled_name,True,
-                                                  conn->params)) {
-                                       /* Error - mangle failed ! */
-                                       memset(mangled_name,'\0',12);
-                               }
-                               mangled_name[12] = 0;
-                               len = srvstr_push(base_data, flags2,
-                                                 p+2, mangled_name, 24,
-                                                 STR_UPPER|STR_UNICODE);
-                               if (len < 24) {
-                                       memset(p + 2 + len,'\0',24 - len);
-                               }
-                               SSVAL(p, 0, len);
+               } else {
+                       if (len > 1) {
+                               len -= 1;
                        } else {
-                               memset(p,'\0',26);
+                               len = 0;
                        }
-                       p += 2 + 24;
-                       len = srvstr_push(base_data, flags2, p,
-                                         fname, PTR_DIFF(end_data, p),
-                                         STR_TERMINATE_ASCII);
-                       SIVAL(q,0,len);
-                       p += len;
-                       SIVAL(p,0,0); /* Ensure any padding is null. */
-                       len = PTR_DIFF(p, pdata);
-                       len = (len + 3) & ~3;
-                       SIVAL(pdata,0,len);
-                       p = pdata + len;
-                       break;
+               }
+               SCVAL(nameptr,0,len);
+               p += len + 1;
+               SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
+               break;
+       }
 
-               case SMB_FIND_FILE_DIRECTORY_INFO:
-                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
+       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, conn->params);
+               p += 4;
+               SIVAL(p,0,reskey); p += 4;
+               put_long_date_timespec(p,create_date_ts); p += 8;
+               put_long_date_timespec(p,adate_ts); p += 8;
+               put_long_date_timespec(p,mdate_ts); p += 8;
+               put_long_date_timespec(p,mdate_ts); 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,
+                                                               smb_fname->base_name);
+                       SIVAL(p,0,ea_size); /* Extended attributes */
                        p += 4;
-                       SIVAL(p,0,reskey); p += 4;
-                       put_long_date_timespec(p,create_date_ts); p += 8;
-                       put_long_date_timespec(p,adate_ts); p += 8;
-                       put_long_date_timespec(p,mdate_ts); p += 8;
-                       put_long_date_timespec(p,mdate_ts); 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;
+               }
+               /* Clear the short name buffer. This is
+                * IMPORTANT as not doing so will trigger
+                * a Win2k client bug. JRA.
+                */
+               if (!was_8_3 && check_mangled_names) {
+                       char mangled_name[13]; /* mangled 8.3 name. */
+                       if (!name_to_8_3(fname,mangled_name,True,
+                                          conn->params)) {
+                               /* Error - mangle failed ! */
+                               memset(mangled_name,'\0',12);
+                       }
+                       mangled_name[12] = 0;
                        len = srvstr_push(base_data, flags2,
-                                         p + 4, fname, PTR_DIFF(end_data, p+4),
-                                         STR_TERMINATE_ASCII);
-                       SIVAL(p,0,len);
-                       p += 4 + len;
-                       SIVAL(p,0,0); /* Ensure any padding is null. */
-                       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_timespec(p,create_date_ts); p += 8;
-                       put_long_date_timespec(p,adate_ts); p += 8;
-                       put_long_date_timespec(p,mdate_ts); p += 8;
-                       put_long_date_timespec(p,mdate_ts); 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,
-                                                                       smb_fname->base_name);
-                               SIVAL(p,0,ea_size); /* Extended attributes */
-                               p +=4;
+                                         p+2, mangled_name, 24,
+                                         STR_UPPER|STR_UNICODE);
+                       if (len < 24) {
+                               memset(p + 2 + len,'\0',24 - len);
                        }
-                       len = srvstr_push(base_data, flags2, p,
-                                         fname, PTR_DIFF(end_data, p),
-                                         STR_TERMINATE_ASCII);
-                       SIVAL(q, 0, len);
-                       p += len;
+                       SSVAL(p, 0, len);
+               } else {
+                       memset(p,'\0',26);
+               }
+               p += 2 + 24;
+               len = srvstr_push(base_data, flags2, p,
+                                 fname, PTR_DIFF(end_data, p),
+                                 STR_TERMINATE_ASCII);
+               SIVAL(q,0,len);
+               p += len;
+               SIVAL(p,0,0); /* Ensure any padding is null. */
+               len = PTR_DIFF(p, pdata);
+               len = (len + 3) & ~3;
+               SIVAL(pdata,0,len);
+               p = pdata + len;
+               break;
 
-                       SIVAL(p,0,0); /* Ensure any padding is null. */
-                       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,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
+               p += 4;
+               SIVAL(p,0,reskey); p += 4;
+               put_long_date_timespec(p,create_date_ts); p += 8;
+               put_long_date_timespec(p,adate_ts); p += 8;
+               put_long_date_timespec(p,mdate_ts); p += 8;
+               put_long_date_timespec(p,mdate_ts); 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(base_data, flags2,
+                                 p + 4, fname, PTR_DIFF(end_data, p+4),
+                                 STR_TERMINATE_ASCII);
+               SIVAL(p,0,len);
+               p += 4 + len;
+               SIVAL(p,0,0); /* Ensure any padding is null. */
+               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,("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(base_data, flags2, p,
-                                         fname, PTR_DIFF(end_data, p),
-                                         STR_TERMINATE_ASCII);
-                       SIVAL(p, -4, len);
-                       p += len;
-                       SIVAL(p,0,0); /* Ensure any padding is null. */
-                       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_timespec(p,create_date_ts); p += 8;
+               put_long_date_timespec(p,adate_ts); p += 8;
+               put_long_date_timespec(p,mdate_ts); p += 8;
+               put_long_date_timespec(p,mdate_ts); 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,
+                                                               smb_fname->base_name);
+                       SIVAL(p,0,ea_size); /* Extended attributes */
+                       p +=4;
+               }
+               len = srvstr_push(base_data, flags2, p,
+                                 fname, PTR_DIFF(end_data, p),
+                                 STR_TERMINATE_ASCII);
+               SIVAL(q, 0, len);
+               p += len;
+
+               SIVAL(p,0,0); /* Ensure any padding is null. */
+               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,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
-                       p += 4;
-                       SIVAL(p,0,reskey); p += 4;
-                       put_long_date_timespec(p,create_date_ts); p += 8;
-                       put_long_date_timespec(p,adate_ts); p += 8;
-                       put_long_date_timespec(p,mdate_ts); p += 8;
-                       put_long_date_timespec(p,mdate_ts); 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,
-                                                                       smb_fname->base_name);
-                               SIVAL(p,0,ea_size); /* Extended attributes */
-                               p +=4;
-                       }
-                       SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
-                       SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
-                       SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
-                       len = srvstr_push(base_data, flags2, p,
-                                         fname, PTR_DIFF(end_data, p),
-                                         STR_TERMINATE_ASCII);
-                       SIVAL(q, 0, len);
-                       p += len; 
-                       SIVAL(p,0,0); /* Ensure any padding is null. */
-                       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,("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(base_data, flags2, p,
+                                 fname, PTR_DIFF(end_data, p),
+                                 STR_TERMINATE_ASCII);
+               SIVAL(p, -4, len);
+               p += len;
+               SIVAL(p,0,0); /* Ensure any padding is null. */
+               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, conn->params);
-                       p += 4;
-                       SIVAL(p,0,reskey); p += 4;
-                       put_long_date_timespec(p,create_date_ts); p += 8;
-                       put_long_date_timespec(p,adate_ts); p += 8;
-                       put_long_date_timespec(p,mdate_ts); p += 8;
-                       put_long_date_timespec(p,mdate_ts); 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,
-                                                                       smb_fname->base_name);
-                               SIVAL(p,0,ea_size); /* Extended attributes */
-                               p +=4;
+       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_timespec(p,create_date_ts); p += 8;
+               put_long_date_timespec(p,adate_ts); p += 8;
+               put_long_date_timespec(p,mdate_ts); p += 8;
+               put_long_date_timespec(p,mdate_ts); 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,
+                                                               smb_fname->base_name);
+                       SIVAL(p,0,ea_size); /* Extended attributes */
+                       p +=4;
+               }
+               SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
+               SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
+               SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
+               len = srvstr_push(base_data, flags2, p,
+                                 fname, PTR_DIFF(end_data, p),
+                                 STR_TERMINATE_ASCII);
+               SIVAL(q, 0, len);
+               p += len;
+               SIVAL(p,0,0); /* Ensure any padding is null. */
+               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, conn->params);
+               p += 4;
+               SIVAL(p,0,reskey); p += 4;
+               put_long_date_timespec(p,create_date_ts); p += 8;
+               put_long_date_timespec(p,adate_ts); p += 8;
+               put_long_date_timespec(p,mdate_ts); p += 8;
+               put_long_date_timespec(p,mdate_ts); 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,
+                                                               smb_fname->base_name);
+                       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.
+                */
+               if (!was_8_3 && check_mangled_names) {
+                       char mangled_name[13]; /* mangled 8.3 name. */
+                       if (!name_to_8_3(fname,mangled_name,True,
+                                       conn->params)) {
+                               /* Error - mangle failed ! */
+                               memset(mangled_name,'\0',12);
                        }
-                       /* Clear the short name buffer. This is
-                        * IMPORTANT as not doing so will trigger
-                        * a Win2k client bug. JRA.
-                        */
-                       if (!was_8_3 && state.check_mangled_names) {
-                               char mangled_name[13]; /* mangled 8.3 name. */
-                               if (!name_to_8_3(fname,mangled_name,True,
-                                               conn->params)) {
-                                       /* Error - mangle failed ! */
-                                       memset(mangled_name,'\0',12);
-                               }
-                               mangled_name[12] = 0;
-                               len = srvstr_push(base_data, flags2,
-                                                 p+2, mangled_name, 24,
-                                                 STR_UPPER|STR_UNICODE);
-                               SSVAL(p, 0, len);
-                               if (len < 24) {
-                                       memset(p + 2 + len,'\0',24 - len);
-                               }
-                               SSVAL(p, 0, len);
-                       } else {
-                               memset(p,'\0',26);
+                       mangled_name[12] = 0;
+                       len = srvstr_push(base_data, flags2,
+                                         p+2, mangled_name, 24,
+                                         STR_UPPER|STR_UNICODE);
+                       SSVAL(p, 0, len);
+                       if (len < 24) {
+                               memset(p + 2 + len,'\0',24 - len);
                        }
-                       p += 26;
-                       SSVAL(p,0,0); p += 2; /* Reserved ? */
-                       SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
-                       SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
-                       len = srvstr_push(base_data, flags2, p,
-                                         fname, PTR_DIFF(end_data, p),
-                                         STR_TERMINATE_ASCII);
-                       SIVAL(q,0,len);
-                       p += len;
-                       SIVAL(p,0,0); /* Ensure any padding is null. */
-                       len = PTR_DIFF(p, pdata);
-                       len = (len + 3) & ~3;
-                       SIVAL(pdata,0,len);
-                       p = pdata + len;
-                       break;
+                       SSVAL(p, 0, len);
+               } else {
+                       memset(p,'\0',26);
+               }
+               p += 26;
+               SSVAL(p,0,0); p += 2; /* Reserved ? */
+               SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
+               SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
+               len = srvstr_push(base_data, flags2, p,
+                                 fname, PTR_DIFF(end_data, p),
+                                 STR_TERMINATE_ASCII);
+               SIVAL(q,0,len);
+               p += len;
+               SIVAL(p,0,0); /* Ensure any padding is null. */
+               len = PTR_DIFF(p, pdata);
+               len = (len + 3) & ~3;
+               SIVAL(pdata,0,len);
+               p = pdata + len;
+               break;
 
-               /* CIFS UNIX Extension. */
+       /* CIFS UNIX Extension. */
 
-               case SMB_FIND_FILE_UNIX:
-               case SMB_FIND_FILE_UNIX_INFO2:
-                       p+= 4;
-                       SIVAL(p,0,reskey); p+= 4;    /* Used for continuing search. */
+       case SMB_FIND_FILE_UNIX:
+       case SMB_FIND_FILE_UNIX_INFO2:
+               p+= 4;
+               SIVAL(p,0,reskey); p+= 4;    /* Used for continuing search. */
 
-                       /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
+               /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
 
-                       if (info_level == SMB_FIND_FILE_UNIX) {
-                               DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
-                               p = store_file_unix_basic(conn, p,
-                                                       NULL, &smb_fname->st);
-                               len = srvstr_push(base_data, flags2, p,
-                                                 fname, PTR_DIFF(end_data, p),
-                                                 STR_TERMINATE);
-                       } else {
-                               DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
-                               p = store_file_unix_basic_info2(conn, p,
-                                                       NULL, &smb_fname->st);
-                               nameptr = p;
-                               p += 4;
-                               len = srvstr_push(base_data, flags2, p, fname,
-                                                 PTR_DIFF(end_data, p), 0);
-                               SIVAL(nameptr, 0, len);
-                       }
+               if (info_level == SMB_FIND_FILE_UNIX) {
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
+                       p = store_file_unix_basic(conn, p,
+                                               NULL, &smb_fname->st);
+                       len = srvstr_push(base_data, flags2, p,
+                                         fname, PTR_DIFF(end_data, p),
+                                         STR_TERMINATE);
+               } else {
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
+                       p = store_file_unix_basic_info2(conn, p,
+                                               NULL, &smb_fname->st);
+                       nameptr = p;
+                       p += 4;
+                       len = srvstr_push(base_data, flags2, p, fname,
+                                         PTR_DIFF(end_data, p), 0);
+                       SIVAL(nameptr, 0, len);
+               }
 
-                       p += len;
-                       SIVAL(p,0,0); /* Ensure any padding is null. */
+               p += len;
+               SIVAL(p,0,0); /* Ensure any padding is null. */
 
-                       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 */
+               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;
+               break;
 
-               default:
-                       TALLOC_FREE(fname);
-                       TALLOC_FREE(smb_fname);
-                       return false;
+       default:
+               return false;
        }
 
-       TALLOC_FREE(fname);
-       TALLOC_FREE(smb_fname);
-
        if (PTR_DIFF(p,pdata) > space_remaining) {
-               /* Move the dirptr back to prev_dirpos */
-               dptr_SeekDir(dirptr, prev_dirpos);
-               *out_of_space = True;
+               *out_of_space = true;
                DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
-               return False; /* Not finished - just out of space */
+               return false; /* Not finished - just out of space */
        }
 
        /* Setup the last entry pointer, as an offset from base_data */
@@ -1975,6 +1915,105 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
        return true;
 }
 
+static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
+                               connection_struct *conn,
+                               struct dptr_struct *dirptr,
+                               uint16 flags2,
+                               const char *path_mask,
+                               uint32 dirtype,
+                               int info_level,
+                               int requires_resume_key,
+                               bool dont_descend,
+                               bool ask_sharemode,
+                               char **ppdata,
+                               char *base_data,
+                               char *end_data,
+                               int space_remaining,
+                               bool *out_of_space,
+                               bool *got_exact_match,
+                               int *_last_entry_off,
+                               struct ea_list *name_list)
+{
+       const char *p;
+       const char *mask = NULL;
+       long prev_dirpos = 0;
+       uint32_t mode = 0;
+       char *fname = NULL;
+       struct smb_filename *smb_fname = NULL;
+       struct smbd_dirptr_lanman2_state state;
+       bool ok;
+       uint64_t last_entry_off = 0;
+
+       ZERO_STRUCT(state);
+       state.conn = conn;
+       state.info_level = info_level;
+       state.check_mangled_names = lp_manglednames(conn->params);
+       state.has_wild = dptr_has_wild(dirptr);
+       state.got_exact_match = false;
+
+       *out_of_space = false;
+       *got_exact_match = false;
+
+       p = strrchr_m(path_mask,'/');
+       if(p != NULL) {
+               if(p[1] == '\0') {
+                       mask = "*.*";
+               } else {
+                       mask = p+1;
+               }
+       } else {
+               mask = path_mask;
+       }
+
+       ok = smbd_dirptr_get_entry(ctx,
+                                  dirptr,
+                                  mask,
+                                  dirtype,
+                                  dont_descend,
+                                  ask_sharemode,
+                                  smbd_dirptr_lanman2_match_fn,
+                                  smbd_dirptr_lanman2_mode_fn,
+                                  &state,
+                                  &fname,
+                                  &smb_fname,
+                                  &mode,
+                                  &prev_dirpos);
+       if (!ok) {
+               return false;
+       }
+
+       *got_exact_match = state.got_exact_match;
+
+       ok = smbd_marshall_dir_entry(ctx,
+                                    conn,
+                                    flags2,
+                                    info_level,
+                                    name_list,
+                                    state.check_mangled_names,
+                                    requires_resume_key,
+                                    mode,
+                                    fname,
+                                    smb_fname,
+                                    space_remaining,
+                                    base_data,
+                                    ppdata,
+                                    end_data,
+                                    out_of_space,
+                                    &last_entry_off);
+       TALLOC_FREE(fname);
+       TALLOC_FREE(smb_fname);
+       if (*out_of_space) {
+               dptr_SeekDir(dirptr, prev_dirpos);
+               return false;
+       }
+       if (!ok) {
+               return false;
+       }
+
+       *_last_entry_off = last_entry_off;
+       return true;
+}
+
 /****************************************************************************
  Reply to a TRANS2_FINDFIRST.
 ****************************************************************************/