]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3/4: libsmbclient test. Test using smbc_telldir/smbc_lseekdir with smbc_readdir...
authorJeremy Allison <jra@samba.org>
Mon, 26 Aug 2019 18:22:35 +0000 (11:22 -0700)
committerKarolin Seeger <kseeger@samba.org>
Thu, 19 Sep 2019 10:40:55 +0000 (10:40 +0000)
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

Back-ported from master 3355601fe8541994cc41f5ed800aab9b6a2294f4.

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Böhme <slow@samba.org>
Autobuild-User(v4-9-test): Karolin Seeger <kseeger@samba.org>
Autobuild-Date(v4-9-test): Thu Sep 19 10:40:56 UTC 2019 on sn-devel-144

source4/torture/libsmbclient/libsmbclient.c

index e84ce018a690fa1bf9feb2b0306a351704e9649f..3ed96c4fb94f938d513f34a0ec1514d9d98648f0 100644 (file)
@@ -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"
@@ -316,6 +317,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. */
+       ret = strcmp(dirent_20->name, direntries_20->name);
+       if (ret != 0) {
+               torture_fail_goto(tctx,
+                       done,
+                       talloc_asprintf(tctx,
+                               "after seek (20) readdirplus name missmatch "
+                               "file %s - got %s\n",
+                               dirent_20->name,
+                               direntries_20->name));
+       }
+
+       ret = smbc_closedir(dhandle);
+       torture_assert_int_equal(tctx,
+               ret,
+               0,
+               talloc_asprintf(tctx,
+                       "failed to close directory handle for '%s'",
+                       dname));
+
+       dhandle = -1;
+       success = true;
+
+  done:
+
+       /* Clean up. */
+       if (dhandle != -1) {
+               smbc_closedir(dhandle);
+       }
+       for (i = 0; i < 100; i++) {
+               if (full_filename[i] != NULL) {
+                       smbc_unlink(full_filename[i]);
+               }
+       }
+       if (dname != NULL) {
+               smbc_rmdir(dname);
+       }
+
+       smbc_free_context(ctx, 1);
+
+       return success;
+}
+
 bool torture_libsmbclient_configuration(struct torture_context *tctx)
 {
        SMBCCTX *ctx;
@@ -519,6 +857,8 @@ NTSTATUS torture_libsmbclient_init(TALLOC_CTX *ctx)
        torture_suite_add_simple_test(suite, "opendir", torture_libsmbclient_opendir);
        torture_suite_add_simple_test(suite, "readdirplus",
                torture_libsmbclient_readdirplus);
+       torture_suite_add_simple_test(suite, "readdirplus_seek",
+               torture_libsmbclient_readdirplus_seek);
 
        suite->description = talloc_strdup(suite, "libsmbclient interface tests");