summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2019-08-26 10:18:28 -0700
committerKarolin Seeger <kseeger@samba.org>2019-09-19 07:04:30 +0000
commit5cd57eb58b722edd5ccd2f630c5f90ada614c18f (patch)
tree49d0bbf0183f866716e34e0432b87b76b8c83c49
parent588c84d488289c069822ac87f645049f328afd1c (diff)
downloadsamba-5cd57eb58b722edd5ccd2f630c5f90ada614c18f.tar.gz
s3: libsmbclient: Fix smbc_lseekdir() to work with smbc_readdirplus().
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)
-rw-r--r--source3/libsmb/libsmb_dir.c69
1 files changed, 43 insertions, 26 deletions
diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c
index ff2948c9b69..5b0a62418a1 100644
--- a/source3/libsmb/libsmb_dir.c
+++ b/source3/libsmb/libsmb_dir.c
@@ -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;
}