summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2019-08-26 11:22:35 -0700
committerKarolin Seeger <kseeger@samba.org>2019-09-19 10:40:55 +0000
commitc50486c09a2bda0fac5113b869e33521bfe0dcef (patch)
treefcc093e56b42e9e3a02e19573f5b9fa0be33ebd9
parent5cd57eb58b722edd5ccd2f630c5f90ada614c18f (diff)
downloadsamba-c50486c09a2bda0fac5113b869e33521bfe0dcef.tar.gz
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 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
-rw-r--r--source4/torture/libsmbclient/libsmbclient.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/source4/torture/libsmbclient/libsmbclient.c b/source4/torture/libsmbclient/libsmbclient.c
index e84ce018a69..3ed96c4fb94 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"
@@ -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");