diff options
-rw-r--r-- | source3/include/proto.h | 2 | ||||
-rw-r--r-- | source3/smbd/dir.c | 9 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 78 |
3 files changed, 72 insertions, 17 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index 6f8edb445e..802d9973df 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -164,7 +164,7 @@ int dptr_create(int cnum,char *path, BOOL expect_close,int pid); BOOL dptr_fill(char *buf1,unsigned int key); BOOL dptr_zero(char *buf); void *dptr_fetch(char *buf,int *num); -void *dptr_fetch_lanman2(char *params,int dptr_num); +void *dptr_fetch_lanman2(int dptr_num); BOOL dir_check_ftype(int cnum,int mode,struct stat *st,int dirtype); BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend); void *OpenDir(int cnum, char *name, BOOL use_veto); diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index d751653263..a34406cc65 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -393,21 +393,16 @@ void *dptr_fetch(char *buf,int *num) } /**************************************************************************** -fetch the dir ptr and seek it given the lanman2 parameter block +fetch the dir ptr. ****************************************************************************/ -void *dptr_fetch_lanman2(char *params,int dptr_num) +void *dptr_fetch_lanman2(int dptr_num) { void *p = dptr_get(dptr_num,dircounter++); - uint32 resume_key = SVAL(params,6); - BOOL uses_resume_key = BITSETW(params+10,2); - BOOL continue_bit = BITSETW(params+10,3); if (!p) { DEBUG(3,("fetched null dirptr %d\n",dptr_num)); return(NULL); } - if(uses_resume_key && !continue_bit) - SeekDir(p,resume_key); DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num))); return(p); } diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 893f1adc66..35272ae3d9 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -301,7 +301,8 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l pstring fname; BOOL matched; char *p, *pdata = *ppdata; - int reskey=0, prev_dirpos=0; + uint32 reskey=0; + int prev_dirpos=0; int mode=0; uint32 size=0,len; uint32 mdate=0, adate=0, cdate=0; @@ -336,7 +337,14 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l prev_dirpos = TellDir(Connections[cnum].dirptr); dname = ReadDirName(Connections[cnum].dirptr); - reskey = TellDir(Connections[cnum].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%x now at offset %d\n", Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr))); @@ -796,6 +804,7 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz BOOL close_if_end = BITSETW(params+10,1); BOOL requires_resume_key = BITSETW(params+10,2); BOOL continue_bit = BITSETW(params+10,3); + pstring resume_name; pstring mask; pstring directory; char *p; @@ -807,11 +816,15 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz BOOL out_of_space = False; int space_remaining; - *mask = *directory = 0; + *mask = *directory = *resume_name = 0; + + pstrcpy( resume_name, params+12); - DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, close_after_request=%d, close_if_end = %d requires_resume_key = %d resume_key = %d continue=%d level = %d\n", + DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \ +close_after_request=%d, close_if_end = %d requires_resume_key = %d \ +resume_key = %d resume name = %s continue=%d level = %d\n", dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, - requires_resume_key, resume_key, continue_bit, info_level)); + requires_resume_key, resume_key, resume_name, continue_bit, info_level)); switch (info_level) { @@ -839,7 +852,7 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz return(ERROR(ERRDOS,ERRnomem)); /* Check that the dptr is valid */ - if(!(Connections[cnum].dirptr = dptr_fetch_lanman2(params, dptr_num))) + if(!(Connections[cnum].dirptr = dptr_fetch_lanman2(dptr_num))) return(ERROR(ERRDOS,ERRnofiles)); string_set(&Connections[cnum].dirpath,dptr_path(dptr_num)); @@ -871,9 +884,56 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz space_remaining = max_data_bytes; out_of_space = False; - /* If we have a resume key - seek to the correct position. */ - if(requires_resume_key && !continue_bit) - SeekDir(Connections[cnum].dirptr, resume_key); + /* + * Seek to the correct position. We no longer use the resume key but + * depend on the last file name instead. + */ + if(requires_resume_key && *resume_name && !continue_bit) + { + /* + * Fix for NT redirector problem triggered by resume key indexes + * changing between directory scans. We now return a resume key of 0 + * and instead look for the filename to continue from (also given + * to us by NT/95/smbfs/smbclient). If no other scans have been done between the + * findfirst/findnext (as is usual) then the directory pointer + * should already be at the correct place. Check this by scanning + * backwards looking for an exact (ie. case sensitive) filename match. + * If we get to the beginning of the directory and haven't found it then scan + * forwards again looking for a match. JRA. + */ + + int current_pos, start_pos; + char *dname; + void *dirptr = Connections[cnum].dirptr; + start_pos = TellDir(dirptr); + for(current_pos = start_pos; current_pos >= 0; current_pos--) + { + SeekDir(dirptr, current_pos); + dname = ReadDirName(dirptr); + if(dname && strcsequal( resume_name, dname)) + { + SeekDir(dirptr, current_pos+1); + break; + } + } + + /* + * Scan forward from start if not found going backwards. + */ + + if(current_pos < 0) + { + SeekDir(dirptr, start_pos); + for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) + { + if(strcsequal( resume_name, dname)) + { + SeekDir(dirptr, current_pos+1); + break; + } + } /* end for */ + } /* end if current_pos */ + } /* end if requires_resume_key && !continue_bit */ for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) { |