]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3: libsmbclient: Fix smbc_lseekdir() to work with smbc_readdirplus().
authorJeremy Allison <jra@samba.org>
Mon, 26 Aug 2019 17:18:28 +0000 (10:18 -0700)
committerKarolin Seeger <kseeger@samba.org>
Thu, 19 Sep 2019 07:04:30 +0000 (07:04 +0000)
If returning files the dir_list and the dirplus_list have exactly the same
entries, we just need to keep the next pointers in sync on seek.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Böhme <slow@samba.org>
(cherry picked from commit 0d9b1645499ce12a79a137d3482434aa5d2eb47c)

source3/libsmb/libsmb_dir.c

index ff2948c9b69dd3ddfb41017383ee81b830a4f9b9..5b0a62418a1f351ecbec9d921e2e80918caf6574 100644 (file)
@@ -1671,35 +1671,43 @@ SMBC_telldir_ctx(SMBCCTX *context,
 
 /*
  * A routine to run down the list and see if the entry is OK
+ * Modifies the dir list and the dirplus list (if it exists)
+ * to point at the correct next entry on success.
  */
 
-static struct smbc_dir_list *
-check_dir_ent(struct smbc_dir_list *list,
-              struct smbc_dirent *dirent)
+static bool update_dir_ents(SMBCFILE *dir, struct smbc_dirent *dirent)
 {
+       struct smbc_dir_list *tmp_dir = dir->dir_list;
+       struct smbc_dirplus_list *tmp_dirplus = dir->dirplus_list;
 
-       /* Run down the list looking for what we want */
-
-       if (dirent) {
-
-               struct smbc_dir_list *tmp = list;
-
-               while (tmp) {
-
-                       if (tmp->dirent == dirent)
-                               return tmp;
-
-                       tmp = tmp->next;
+       /*
+        * Run down the list looking for what we want.
+        * If we're enumerating files both dir_list
+        * and dirplus_list contain the same entry
+        * list, as they were seeded from the same
+        * cli_list callback.
+        *
+        * If we're enumerating servers then
+        * dirplus_list will be NULL, so don't
+        * update in that case.
+        */
 
+       while (tmp_dir != NULL) {
+               if (tmp_dir->dirent == dirent) {
+                       dir->dir_next = tmp_dir;
+                       if (tmp_dirplus != NULL) {
+                               dir->dirplus_next = tmp_dirplus;
+                       }
+                       return true;
+               }
+               tmp_dir = tmp_dir->next;
+               if (tmp_dirplus != NULL) {
+                       tmp_dirplus = tmp_dirplus->next;
                }
-
        }
-
-       return NULL;  /* Not found, or an error */
-
+       return false;
 }
 
-
 /*
  * Routine to seek on a directory
  */
@@ -1711,8 +1719,8 @@ SMBC_lseekdir_ctx(SMBCCTX *context,
 {
        long int l_offset = offset;  /* Handle problems of size */
        struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
-       struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL;
        TALLOC_CTX *frame = talloc_stackframe();
+       bool ok;
 
        if (!context || !context->internal->initialized) {
 
@@ -1735,6 +1743,10 @@ SMBC_lseekdir_ctx(SMBCCTX *context,
        if (dirent == NULL) {  /* Seek to the begining of the list */
 
                dir->dir_next = dir->dir_list;
+
+               /* Do the same for dirplus. */
+               dir->dirplus_next = dir->dirplus_list;
+
                TALLOC_FREE(frame);
                return 0;
 
@@ -1742,21 +1754,26 @@ SMBC_lseekdir_ctx(SMBCCTX *context,
 
         if (offset == -1) {     /* Seek to the end of the list */
                 dir->dir_next = NULL;
+
+               /* Do the same for dirplus. */
+               dir->dirplus_next = NULL;
+
                TALLOC_FREE(frame);
                 return 0;
         }
 
-       /* Now, run down the list and make sure that the entry is OK       */
-       /* This may need to be changed if we change the format of the list */
+        /*
+         * Run down the list and make sure that the entry is OK.
+         * Update the position of both dir and dirplus lists.
+         */
 
-       if ((list_ent = check_dir_ent(dir->dir_list, dirent)) == NULL) {
+       ok = update_dir_ents(dir, dirent);
+       if (!ok) {
                errno = EINVAL;   /* Bad entry */
                TALLOC_FREE(frame);
                return -1;
        }
 
-       dir->dir_next = list_ent;
-
        TALLOC_FREE(frame);
        return 0;
 }