The branch, v4-11-test has been updated via d702f662901 s3/4: libsmbclient test. Test using smbc_telldir/smbc_lseekdir with smbc_readdir/smbc_readdirplus/smbc_getdents. via 411eb45f2c9 s3: libsmbclient: Fix smbc_lseekdir() to work with smbc_readdirplus(). via a70eee31213 s3: libsmbclient: Ensure SMBC_getdents_ctx() also updates the readdirplus pointers. via 0fbd2c08b54 s3: libsmbclient: Ensure SMBC_readdirplus_ctx() also updates the readdir pointers. via a0342e92f3a s3: libsmbclient: Ensure SMBC_readdir_ctx() also updates the readdirplus pointers. from 872e03c2dc8 VERSION: Bump version up to 4.11.1...
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-11-test - Log ----------------------------------------------------------------- commit d702f66290159d72c8f3c5d08ec9e9f23772611f Author: Jeremy Allison <j...@samba.org> Date: Mon Aug 26 11:22:35 2019 -0700 s3/4: libsmbclient test. Test using smbc_telldir/smbc_lseekdir with smbc_readdir/smbc_readdirplus/smbc_getdents. Ensure that for file access you can mix any of these three access methods for directory entries and the returned names/structs stay in sync across telldir/seekdir changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094 Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Ralph Böhme <s...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Tue Sep 3 17:31:29 UTC 2019 on sn-devel-184 (cherry picked from commit 3355601fe8541994cc41f5ed800aab9b6a2294f4) Autobuild-User(v4-11-test): Karolin Seeger <ksee...@samba.org> Autobuild-Date(v4-11-test): Wed Sep 18 13:51:56 UTC 2019 on sn-devel-184 commit 411eb45f2c9b9019d8a54c3c7092a3c0fc515e15 Author: Jeremy Allison <j...@samba.org> Date: Mon Aug 26 10:18:28 2019 -0700 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 <j...@samba.org> Reviewed-by: Ralph Böhme <s...@samba.org> (cherry picked from commit 0d9b1645499ce12a79a137d3482434aa5d2eb47c) commit a70eee31213189d9cf0e4b40d14e2c301ef4f2c8 Author: Jeremy Allison <j...@samba.org> Date: Mon Aug 26 10:07:32 2019 -0700 s3: libsmbclient: Ensure SMBC_getdents_ctx() also updates the readdirplus pointers. If we are returning file entries, we have a duplicate list in dirplus. Update dirplus_next also so readdir and readdirplus are kept in sync. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094 Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Ralph Böhme <s...@samba.org> (cherry picked from commit 754cec7756b2ddb1cfcc3984265f01cb366beb76) commit 0fbd2c08b548bd2588de960a5475ed5fc2de9bf7 Author: Jeremy Allison <j...@samba.org> Date: Mon Aug 26 10:02:47 2019 -0700 s3: libsmbclient: Ensure SMBC_readdirplus_ctx() also updates the readdir pointers. If we are returning file entries, we have a duplicate list in dir_list. Update dir_next also so readdir and readdirplus are kept in sync. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094 Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Ralph Böhme <s...@samba.org> (cherry picked from commit 3d82b7d11cd7b78adc6b3642e64e3a8f251de869) commit a0342e92f3a25fbf15ab0f3ad3f05e597726be81 Author: Jeremy Allison <j...@samba.org> Date: Mon Aug 26 09:54:06 2019 -0700 s3: libsmbclient: Ensure SMBC_readdir_ctx() also updates the readdirplus pointers. If we are returning file entries, we have a duplicate list in dirplus. Update dirplus_next also so readdir and readdirplus are kept in sync. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094 Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Ralph Böhme <s...@samba.org> (cherry picked from commit 4bca8e097f5a909c628daa4dbfa932ddc1725ebc) ----------------------------------------------------------------------- Summary of changes: source3/libsmb/libsmb_dir.c | 102 ++++++--- source3/selftest/tests.py | 3 +- source4/torture/libsmbclient/libsmbclient.c | 340 ++++++++++++++++++++++++++++ 3 files changed, 418 insertions(+), 27 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c index 886aa626509..df606c4adfe 100644 --- a/source3/libsmb/libsmb_dir.c +++ b/source3/libsmb/libsmb_dir.c @@ -1174,6 +1174,17 @@ SMBC_readdir_ctx(SMBCCTX *context, dir->dir_next = dir->dir_next->next; + /* + * If we are returning file entries, we + * have a duplicate list in dirplus. + * + * Update dirplus_next also so readdir and + * readdirplus are kept in sync. + */ + if (dir->dirplus_list != NULL) { + dir->dirplus_next = dir->dirplus_next->next; + } + TALLOC_FREE(frame); return dirp; } @@ -1220,6 +1231,17 @@ SMBC_readdirplus_ctx(SMBCCTX *context, } dir->dirplus_next = dir->dirplus_next->next; + /* + * If we are returning file entries, we + * have a duplicate list in dir_list + * + * Update dir_next also so readdir and + * readdirplus are kept in sync. + */ + if (dir->dir_list) { + dir->dir_next = dir->dir_next->next; + } + TALLOC_FREE(frame); return smb_finfo; } @@ -1336,6 +1358,17 @@ SMBC_getdents_ctx(SMBCCTX *context, } dir->dir_next = dirlist = dirlist -> next; + + /* + * If we are returning file entries, we + * have a duplicate list in dirplus. + * + * Update dirplus_next also so readdir and + * readdirplus are kept in sync. + */ + if (dir->dirplus_list != NULL) { + dir->dirplus_next = dir->dirplus_next->next; + } } TALLOC_FREE(frame); @@ -1639,35 +1672,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 */ @@ -1679,8 +1720,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) { @@ -1703,6 +1744,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; @@ -1710,21 +1755,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; } diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 20f2eea7661..5b5a1978988 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -495,7 +495,8 @@ nbt = ["nbt.dgram"] libsmbclient = ["libsmbclient.version", "libsmbclient.initialize", "libsmbclient.configuration", "libsmbclient.setConfiguration", "libsmbclient.options", "libsmbclient.opendir", - "libsmbclient.list_shares", "libsmbclient.readdirplus"] + "libsmbclient.list_shares", "libsmbclient.readdirplus", + "libsmbclient.readdirplus_seek"] vfs = [ "vfs.fruit", diff --git a/source4/torture/libsmbclient/libsmbclient.c b/source4/torture/libsmbclient/libsmbclient.c index f9154e8a19c..b74d87aabed 100644 --- a/source4/torture/libsmbclient/libsmbclient.c +++ b/source4/torture/libsmbclient/libsmbclient.c @@ -18,6 +18,7 @@ */ #include "includes.h" +#include "system/dir.h" #include "torture/smbtorture.h" #include "auth/credentials/credentials.h" #include "lib/cmdline/popt_common.h" @@ -375,6 +376,343 @@ static bool torture_libsmbclient_readdirplus(struct torture_context *tctx) return true; } +static bool torture_libsmbclient_readdirplus_seek(struct torture_context *tctx) +{ + SMBCCTX *ctx; + int ret = -1; + int dhandle = -1; + int fhandle = -1; + const char *dname = NULL; + const char *full_filename[100] = {0}; + const char *filename[100] = {0}; + const struct libsmb_file_info *direntries[102] = {0}; + unsigned int i = 0; + const char *smburl = torture_setting_string(tctx, "smburl", NULL); + bool success = false; + off_t telldir_50 = (off_t)-1; + off_t telldir_20 = (off_t)-1; + size_t getdentries_size = 0; + struct smbc_dirent *getdentries = NULL; + struct smbc_dirent *dirent_20 = NULL; + const struct libsmb_file_info *direntries_20 = NULL; + + if (smburl == NULL) { + torture_fail(tctx, + "option --option=torture:smburl=" + "smb://user:password@server/share missing\n"); + } + + DEBUG(0,("torture_libsmbclient_readdirplus_seek start\n")); + + torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), ""); + smbc_set_context(ctx); + + dname = talloc_asprintf(tctx, + "%s/rd_seek", + smburl); + if (dname == NULL) { + torture_fail_goto(tctx, + done, + "talloc fail\n"); + } + + /* Ensure the files don't exist. */ + for (i = 0; i < 100; i++) { + filename[i] = talloc_asprintf(tctx, + "test_readdirplus_%u.txt", + i); + if (filename[i] == NULL) { + torture_fail_goto(tctx, + done, + "talloc fail\n"); + } + full_filename[i] = talloc_asprintf(tctx, + "%s/%s", + dname, + filename[i]); + if (full_filename[i] == NULL) { + torture_fail_goto(tctx, + done, + "talloc fail\n"); + } + (void)smbc_unlink(full_filename[i]); + } + /* Ensure the directory doesn't exist. */ + (void)smbc_rmdir(dname); + + /* Create containing directory. */ + ret = smbc_mkdir(dname, 0777); + if (ret != 0) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "failed to create directory '%s': %s", + dname, + strerror(errno))); + } + + DEBUG(0,("torture_libsmbclient_readdirplus_seek create\n")); + + /* Create them. */ + for (i = 0; i < 100; i++) { + fhandle = smbc_creat(full_filename[i], 0666); + if (fhandle < 0) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "failed to create file '%s': %s", + full_filename[i], + strerror(errno))); + } + ret = smbc_close(fhandle); + torture_assert_int_equal_goto(tctx, + ret, + 0, + success, + done, + talloc_asprintf(tctx, + "failed to close handle for '%s'", + full_filename[i])); + } + + DEBUG(0,("torture_libsmbclient_readdirplus_seek enum\n")); + + /* Now enumerate the directory. */ + dhandle = smbc_opendir(dname); + if (dhandle < 0) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "failed to obtain " + "directory handle for '%s' : %s", + dname, + strerror(errno))); + } + + /* Read all the files. 100 we created plus . and .. */ + for (i = 0; i < 102; i++) { + bool found = false; + unsigned int j; + + direntries[i] = smbc_readdirplus(dhandle); + if (direntries[i] == NULL) { + break; + } + + /* Store at offset 50. */ + if (i == 50) { + telldir_50 = smbc_telldir(dhandle); + if (telldir_50 == (off_t)-1) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "telldir failed file %s\n", + direntries[i]->name)); + } + } + + if (ISDOT(direntries[i]->name)) { + continue; + } + if (ISDOTDOT(direntries[i]->name)) { + continue; + } + + /* Ensure all our files exist. */ + for (j = 0; j < 100; j++) { + if (strcmp(direntries[i]->name, + filename[j]) == 0) { + found = true; + } + } + if (!found) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "failed to find file %s\n", + direntries[i]->name)); + } + } + + /* + * We're seeking on in-memory lists here, so + * whilst the handle is open we really should + * get the same files back in the same order. + */ + + ret = smbc_lseekdir(dhandle, telldir_50); + torture_assert_int_equal_goto(tctx, + ret, + 0, + success, + done, + talloc_asprintf(tctx, + "failed to seek (50) directory handle for '%s'", + dname)); + + DEBUG(0,("torture_libsmbclient_readdirplus_seek seek\n")); + + for (i = 51; i < 102; i++) { + const struct libsmb_file_info *entry = + smbc_readdirplus(dhandle); + if (entry != direntries[i]) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "after seek - failed to find " + "file %s - got %s\n", + direntries[i]->name, + entry->name)); + } + } + + /* Seek back to the start. */ + ret = smbc_lseekdir(dhandle, 0); + torture_assert_int_equal_goto(tctx, + ret, + 0, + success, + done, + talloc_asprintf(tctx, + "failed to seek directory handle to start for '%s'", + dname)); + + /* + * Mix getdents/readdir/readdirplus with lseek to ensure + * we get the same result. + */ + + /* Allocate the space for 20 entries. + * Tricky as we need to allocate 20 struct smbc_dirent's + space + * for the name lengths. + */ + getdentries_size = 20 * (sizeof(struct smbc_dirent) + + strlen("test_readdirplus_1000.txt") + 1); + + getdentries = (struct smbc_dirent *)talloc_array_size(tctx, + getdentries_size, + 1); + + ret = smbc_getdents(dhandle, getdentries, getdentries_size); + torture_assert_goto(tctx, + (ret != -1), + success, + done, + talloc_asprintf(tctx, + "smbd_getdents(1) for '%s' failed\n", + dname)); + + telldir_20 = smbc_telldir(dhandle); + if (telldir_20 == (off_t)-1) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "telldir (20) failed\n")); + } + /* Read another 20. */ + ret = smbc_getdents(dhandle, getdentries, getdentries_size); + torture_assert_goto(tctx, + (ret != -1), + success, + done, + talloc_asprintf(tctx, + "smbd_getdents(2) for '%s' failed\n", + dname)); + + /* Seek back to 20. */ + ret = smbc_lseekdir(dhandle, telldir_20); + torture_assert_int_equal_goto(tctx, + ret, + 0, + success, + done, + talloc_asprintf(tctx, + "failed to seek (20) directory handle for '%s'", + dname)); + + /* Read with readdir. */ + dirent_20 = smbc_readdir(dhandle); + if (dirent_20 == NULL) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "smbc_readdir (20) failed\n")); + } + + /* Ensure the getdents and readdir names are the same. */ + ret = strcmp(dirent_20->name, getdentries[0].name); + if (ret != 0) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "after seek (20) readdir name missmatch " + "file %s - got %s\n", + dirent_20->name, + getdentries[0].name)); + } + + /* Seek back to 20. */ + ret = smbc_lseekdir(dhandle, telldir_20); + torture_assert_int_equal_goto(tctx, + ret, + 0, + success, + done, + talloc_asprintf(tctx, + "failed to seek (20) directory handle for '%s'", + dname)); + /* Read with readdirplus. */ + direntries_20 = smbc_readdirplus(dhandle); + if (direntries_20 == NULL) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "smbc_readdirplus (20) failed\n")); + } + + /* Ensure the readdirplus and readdir names are the same. */ -- Samba Shared Repository