Fix for NT redirector bug where deltree fails if the resume key
authorJeremy Allison <jra@samba.org>
Thu, 26 Feb 1998 19:53:55 +0000 (19:53 +0000)
committerJeremy Allison <jra@samba.org>
Thu, 26 Feb 1998 19:53:55 +0000 (19:53 +0000)
indexes are changed between directory scans. This fix does what
NT4.x SP3 does in that it stops using resume keys and returns
zero instead. We now use the filename in findnext to continue
the search in the correct place (as NT does).
Jeremy.
(This used to be commit b813fb22c4c1b0ee48667e99e82434d20266bbf2)

source3/include/proto.h
source3/smbd/dir.c
source3/smbd/trans2.c

index 6f8edb445eb08771f92a1affccf90a14c8e242b1..802d9973df081bc1240ad5d728360645bb175056 100644 (file)
@@ -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);
index d751653263286a25caab9efd47488a408fc3e7d0..a34406cc65af5705a8faba46a70a43e34f6c3ca5 100644 (file)
@@ -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);
 }
index 893f1adc66b0c28fd207c22ebe423a3e87664d1e..35272ae3d96a6aa45e1b9675ab63705480be0b29 100644 (file)
@@ -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++)
     {