[PATCH] libsmbclient: readdirplus call.

Jeremy Allison jra at samba.org
Tue Apr 24 20:51:32 UTC 2018


Now I'm back from vacation, I (finally, sorry Puran :-) got
the chance to code up a working test suite for the new
readdirplus code.

Readdirplus patch already tested by Puran, the original
author. Just the last patch (test coverage) is new.

Please review and push if happy !

Jeremy.
-------------- next part --------------
From d482f05e385800c6c6bf31a066e1f4f4ba399927 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Fri, 6 Apr 2018 13:35:05 -0700
Subject: [PATCH 1/6] s3: client: Add btime_ts to struct finfo.

Fill it in when available, else return it as zero.

Based on a patch from Puran Chand <pchand at vmware.com>.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 examples/fuse/clifuse.c        |  1 +
 source3/include/client.h       |  1 +
 source3/libsmb/cli_smb2_fnum.c |  1 +
 source3/libsmb/clilist.c       | 19 +++++++++++++++++++
 4 files changed, 22 insertions(+)

diff --git a/examples/fuse/clifuse.c b/examples/fuse/clifuse.c
index da9dd4d3e82..3c7e4982475 100644
--- a/examples/fuse/clifuse.c
+++ b/examples/fuse/clifuse.c
@@ -484,6 +484,7 @@ static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
 		return NT_STATUS_INFO_LENGTH_MISMATCH;
 	}
 
+	finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
 	finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
 	finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
 	finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
diff --git a/source3/include/client.h b/source3/include/client.h
index 1fe3f1cb960..0cb21384f17 100644
--- a/source3/include/client.h
+++ b/source3/include/client.h
@@ -108,6 +108,7 @@ struct file_info {
 	uid_t uid;
 	gid_t gid;
 	/* these times are normally kept in GMT */
+	struct timespec btime_ts; /* Birth-time if supported by system */
 	struct timespec mtime_ts;
 	struct timespec atime_ts;
 	struct timespec ctime_ts;
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index c397b29b381..1eb1bea7a72 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -803,6 +803,7 @@ static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
 		return NT_STATUS_INFO_LENGTH_MISMATCH;
 	}
 
+	finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
 	finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
 	finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
 	finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c
index 41f585120b9..5cb1fce4338 100644
--- a/source3/libsmb/clilist.c
+++ b/source3/libsmb/clilist.c
@@ -77,6 +77,14 @@ static size_t interpret_long_filename(TALLOC_CTX *ctx,
 			if (pdata_end - base < 27) {
 				return pdata_end - base;
 			}
+			/*
+			 * What we're returning here as ctime_ts is
+			 * actually the server create time.
+			 */
+			finfo->btime_ts = convert_time_t_to_timespec(
+				make_unix_date2(p+4,
+					smb1cli_conn_server_time_zone(
+						cli->conn)));
 			finfo->ctime_ts = convert_time_t_to_timespec(
 				make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
 			finfo->atime_ts = convert_time_t_to_timespec(
@@ -128,6 +136,14 @@ static size_t interpret_long_filename(TALLOC_CTX *ctx,
 			if (pdata_end - base < 31) {
 				return pdata_end - base;
 			}
+			/*
+			 * What we're returning here as ctime_ts is
+			 * actually the server create time.
+			 */
+			finfo->btime_ts = convert_time_t_to_timespec(
+				make_unix_date2(p+4,
+					smb1cli_conn_server_time_zone(
+						cli->conn)));
 			finfo->ctime_ts = convert_time_t_to_timespec(
 				make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
 			finfo->atime_ts = convert_time_t_to_timespec(
@@ -250,6 +266,9 @@ static bool interpret_short_filename(TALLOC_CTX *ctx,
 
 	finfo->mode = CVAL(p,21);
 
+	/* We don't get birth time. */
+	finfo->btime_ts.tv_sec = 0;
+	finfo->btime_ts.tv_nsec = 0;
 	/* this date is converted to GMT by make_unix_date */
 	finfo->ctime_ts.tv_sec = make_unix_date(p+22, smb1cli_conn_server_time_zone(cli->conn));
 	finfo->ctime_ts.tv_nsec = 0;
-- 
2.17.0.484.g0c8726318c-goog


From d1830240ec155febb2351330631ce719ab2b9cd8 Mon Sep 17 00:00:00 2001
From: Puran Chand <pchand at vmware.com>
Date: Fri, 6 Apr 2018 14:08:03 -0700
Subject: [PATCH 2/6] s3: libsmbclient: Add internal/external structures needed
 for readdirplus.

Not yet used.

Signed-off-by: Puran Chand <pchand at vmware.com>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/include/libsmb_internal.h |  5 ++++
 source3/include/libsmbclient.h    | 49 +++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git a/source3/include/libsmb_internal.h b/source3/include/libsmb_internal.h
index 0e0045e8c0e..a7bda3dd1be 100644
--- a/source3/include/libsmb_internal.h
+++ b/source3/include/libsmb_internal.h
@@ -94,6 +94,10 @@ struct smbc_dir_list {
 	struct smbc_dirent *dirent;
 };
 
+struct smbc_dirplus_list {
+	struct smbc_dirplus_list *next;
+	struct libsmb_file_info *smb_finfo;
+};
 
 /*
  * Structure for open file management
@@ -110,6 +114,7 @@ struct _SMBCFILE {
 	struct _SMBCSRV *srv;
 	bool file;
 	struct smbc_dir_list *dir_list, *dir_end, *dir_next;
+	struct smbc_dirplus_list *dirplus_list, *dirplus_end, *dirplus_next;
 	int dir_type, dir_error;
 
 	SMBCFILE *next, *prev;
diff --git a/source3/include/libsmbclient.h b/source3/include/libsmbclient.h
index 7a2067915af..65aa7db21d3 100644
--- a/source3/include/libsmbclient.h
+++ b/source3/include/libsmbclient.h
@@ -129,6 +129,55 @@ struct smbc_dirent
 	char name[1];
 };
 
+/**@ingroup structure
+ * Structure that represents all attributes of a directory entry.
+ *
+ */
+struct libsmb_file_info
+{
+	/**
+	 * Size of file
+	 */
+	uint64_t size;
+	/**
+	 * DOS attributes of file
+	 */
+	uint16_t attrs;
+	/**
+	 * User ID of file
+	 */
+	uid_t uid;
+	/**
+	 * Group ID of file
+	 */
+	gid_t gid;
+	/**
+	 * Birth/Create time of file (if supported by system)
+	 * Otherwise the value will be 0
+	 */
+	struct timespec btime_ts;
+	/**
+	 * Modified time for the file
+	 */
+	struct timespec mtime_ts;
+	/**
+	 * Access time for the file
+	 */
+	struct timespec atime_ts;
+	/**
+	 * Change time for the file
+	 */
+	struct timespec ctime_ts;
+	/**
+	 * Name of file
+	 */
+	char *name;
+	/**
+	 * Short name of file
+	 */
+	char *short_name;
+};
+
 /*
  * Logging callback function
  */
-- 
2.17.0.484.g0c8726318c-goog


From 98046860a9e579d2f7a91565aecdc78791ec981d Mon Sep 17 00:00:00 2001
From: Puran Chand <pchand at vmware.com>
Date: Fri, 6 Apr 2018 14:17:35 -0700
Subject: [PATCH 3/6] s3: libsmbclient: Add readdirplus cleanup code on
 directory close.

Signed-off-by: Puran Chand <pchand at vmware.com>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/libsmb/libsmb_dir.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c
index 8c3fed672f8..bd4f4d59fd7 100644
--- a/source3/libsmb/libsmb_dir.c
+++ b/source3/libsmb/libsmb_dir.c
@@ -40,6 +40,26 @@
  * We accept the URL syntax explained in SMBC_parse_path(), above.
  */
 
+static void remove_dirplus(SMBCFILE *dir)
+{
+	struct smbc_dirplus_list *d, *f;
+
+	d = dir->dirplus_list;
+	while (d) {
+		f = d;
+		d = d->next;
+
+		SAFE_FREE(f->smb_finfo->short_name);
+		SAFE_FREE(f->smb_finfo->name);
+		SAFE_FREE(f->smb_finfo);
+		SAFE_FREE(f);
+	}
+
+	dir->dirplus_list = NULL;
+	dir->dirplus_end = NULL;
+	dir->dirplus_next = NULL;
+}
+
 static void
 remove_dir(SMBCFILE *dir)
 {
@@ -930,6 +950,7 @@ SMBC_closedir_ctx(SMBCCTX *context,
 	}
 
 	remove_dir(dir); /* Clean it up */
+	remove_dirplus(dir);
 
 	DLIST_REMOVE(context->internal->files, dir);
 
-- 
2.17.0.484.g0c8726318c-goog


From 0419a3fddce472dc6183289957e65245503f4a4b Mon Sep 17 00:00:00 2001
From: Puran Chand <pchand at vmware.com>
Date: Fri, 6 Apr 2018 14:50:39 -0700
Subject: [PATCH 4/6] s3: libsmbclient: Add function add_dirplus() to fill the
 list from a returned file info.

Not yet externally visible.

Signed-off-by: Puran Chand <pchand at vmware.com>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/libsmb/libsmb_dir.c | 73 +++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c
index bd4f4d59fd7..89582ff9cf8 100644
--- a/source3/libsmb/libsmb_dir.c
+++ b/source3/libsmb/libsmb_dir.c
@@ -159,6 +159,73 @@ add_dirent(SMBCFILE *dir,
 
 }
 
+static int add_dirplus(SMBCFILE *dir, struct file_info *finfo)
+{
+	struct smbc_dirplus_list *new_entry = NULL;
+	struct libsmb_file_info *info = NULL;
+
+	new_entry = SMB_MALLOC_P(struct smbc_dirplus_list);
+	if (new_entry == NULL) {
+		dir->dir_error = ENOMEM;
+		return -1;
+	}
+	ZERO_STRUCTP(new_entry);
+
+	info = SMB_MALLOC_P(struct libsmb_file_info);
+	if (info == NULL) {
+		SAFE_FREE(new_entry);
+		dir->dir_error = ENOMEM;
+		return -1;
+	}
+
+	ZERO_STRUCTP(info);
+
+	info->btime_ts = finfo->btime_ts;
+	info->atime_ts = finfo->atime_ts;
+	info->ctime_ts = finfo->ctime_ts;
+	info->mtime_ts = finfo->mtime_ts;
+	info->gid = finfo->gid;
+	info->attrs = finfo->mode;
+	info->size = finfo->size;
+	info->uid = finfo->uid;
+	info->name = SMB_STRDUP(finfo->name);
+	if (info->name == NULL) {
+		SAFE_FREE(info);
+		SAFE_FREE(new_entry);
+		dir->dir_error = ENOMEM;
+		return -1;
+	}
+
+	if (finfo->short_name) {
+		info->short_name = SMB_STRDUP(finfo->short_name);
+	} else {
+		info->short_name = SMB_STRDUP("");
+	}
+
+	if (info->short_name == NULL) {
+		SAFE_FREE(info->name);
+		SAFE_FREE(info);
+		SAFE_FREE(new_entry);
+		dir->dir_error = ENOMEM;
+		return -1;
+	}
+	new_entry->smb_finfo = info;
+
+	/* Now add to the list. */
+	if (dir->dirplus_list == NULL) {
+		/* Empty list - point everything at new_entry. */
+		dir->dirplus_list = new_entry;
+		dir->dirplus_end = new_entry;
+		dir->dirplus_next = new_entry;
+	} else {
+		/* Append to list but leave the ->next cursor alone. */
+		dir->dirplus_end->next = new_entry;
+		dir->dirplus_end = new_entry;
+	}
+
+	return 0;
+}
+
 static void
 list_unique_wg_fn(const char *name,
                   uint32_t type,
@@ -268,12 +335,18 @@ dir_list_fn(const char *mnt,
             const char *mask,
             void *state)
 {
+	SMBCFILE *dirp = (SMBCFILE *)state;
+	int ret;
 
 	if (add_dirent((SMBCFILE *)state, finfo->name, "",
 		       (finfo->mode&FILE_ATTRIBUTE_DIRECTORY?SMBC_DIR:SMBC_FILE)) < 0) {
 		SMBCFILE *dir = (SMBCFILE *)state;
 		return map_nt_error_from_unix(dir->dir_error);
 	}
+	ret = add_dirplus(dirp, finfo);
+	if (ret < 0) {
+		return map_nt_error_from_unix(dirp->dir_error);
+	}
 	return NT_STATUS_OK;
 }
 
-- 
2.17.0.484.g0c8726318c-goog


From 842f63598c859df40948534e16481ce34f0827a7 Mon Sep 17 00:00:00 2001
From: Puran Chand <pchand at vmware.com>
Date: Mon, 9 Apr 2018 10:10:28 -0700
Subject: [PATCH 5/6] s3: libsmbclient: Add new function
 SMBC_readdirplus_ctx().

New ABI function, move to library version 0.33.

Signed-off-by: Puran Chand <pchand at vmware.com>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/include/libsmb_internal.h       |   4 +
 source3/include/libsmbclient.h          |  20 +++
 source3/libsmb/ABI/smbclient-0.3.3.sigs | 184 ++++++++++++++++++++++++
 source3/libsmb/libsmb_compat.c          |   6 +
 source3/libsmb/libsmb_context.c         |   1 +
 source3/libsmb/libsmb_dir.c             |  46 ++++++
 source3/libsmb/libsmb_setget.c          |  10 ++
 source3/libsmb/wscript                  |   2 +-
 8 files changed, 272 insertions(+), 1 deletion(-)
 create mode 100644 source3/libsmb/ABI/smbclient-0.3.3.sigs

diff --git a/source3/include/libsmb_internal.h b/source3/include/libsmb_internal.h
index a7bda3dd1be..f3e44e875d8 100644
--- a/source3/include/libsmb_internal.h
+++ b/source3/include/libsmb_internal.h
@@ -301,6 +301,10 @@ struct smbc_dirent *
 SMBC_readdir_ctx(SMBCCTX *context,
                  SMBCFILE *dir);
 
+const struct libsmb_file_info *
+SMBC_readdirplus_ctx(SMBCCTX *context,
+                     SMBCFILE *dir);
+
 int
 SMBC_getdents_ctx(SMBCCTX *context,
                   SMBCFILE *dir,
diff --git a/source3/include/libsmbclient.h b/source3/include/libsmbclient.h
index 65aa7db21d3..3faf2e07703 100644
--- a/source3/include/libsmbclient.h
+++ b/source3/include/libsmbclient.h
@@ -1024,6 +1024,11 @@ typedef struct smbc_dirent * (*smbc_readdir_fn)(SMBCCTX *c,
 smbc_readdir_fn smbc_getFunctionReaddir(SMBCCTX *c);
 void smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn fn);
 
+typedef const struct libsmb_file_info * (*smbc_readdirplus_fn)(SMBCCTX *c,
+                                                               SMBCFILE *dir);
+smbc_readdirplus_fn smbc_getFunctionReaddirPlus(SMBCCTX *c);
+void smbc_setFunctionReaddirPlus(SMBCCTX *c, smbc_readdirplus_fn fn);
+
 typedef int (*smbc_getdents_fn)(SMBCCTX *c,
                                 SMBCFILE *dir,
                                 struct smbc_dirent *dirp,
@@ -1618,6 +1623,20 @@ int smbc_getdents(unsigned int dh, struct smbc_dirent *dirp, int count);
  */
 struct smbc_dirent* smbc_readdir(unsigned int dh);
 
+/**@ingroup directory
+ * Works similar as smbc_readdir but returns more information about file.
+ *
+ * @param dh        Valid directory as returned by smbc_opendir()
+ *
+ * @return          A const pointer to a libsmb_file_info structure,
+ *                  or NULL if an error occurs or end-of-directory is reached:
+ *                  - EBADF Invalid directory handle
+ *                  - EINVAL smbc_init() failed or has not been called
+ *
+ * @see             smbc_open(), smbc_readdir()
+ */
+const struct libsmb_file_info *smbc_readdirplus(unsigned int dh);
+
 
 /**@ingroup directory
  * Get the current directory offset.
@@ -3067,6 +3086,7 @@ struct _SMBCCTX
         smbc_opendir_fn                 opendir DEPRECATED_SMBC_INTERFACE;
         smbc_closedir_fn                closedir DEPRECATED_SMBC_INTERFACE;
         smbc_readdir_fn                 readdir DEPRECATED_SMBC_INTERFACE;
+	smbc_readdirplus_fn             readdirplus DEPRECATED_SMBC_INTERFACE;
         smbc_getdents_fn                getdents DEPRECATED_SMBC_INTERFACE;
         smbc_mkdir_fn                   mkdir DEPRECATED_SMBC_INTERFACE;
         smbc_rmdir_fn                   rmdir DEPRECATED_SMBC_INTERFACE;
diff --git a/source3/libsmb/ABI/smbclient-0.3.3.sigs b/source3/libsmb/ABI/smbclient-0.3.3.sigs
new file mode 100644
index 00000000000..833d0df6b5f
--- /dev/null
+++ b/source3/libsmb/ABI/smbclient-0.3.3.sigs
@@ -0,0 +1,184 @@
+smbc_chmod: int (const char *, mode_t)
+smbc_close: int (int)
+smbc_closedir: int (int)
+smbc_creat: int (const char *, mode_t)
+smbc_fgetxattr: int (int, const char *, const void *, size_t)
+smbc_flistxattr: int (int, char *, size_t)
+smbc_free_context: int (SMBCCTX *, int)
+smbc_fremovexattr: int (int, const char *)
+smbc_fsetxattr: int (int, const char *, const void *, size_t, int)
+smbc_fstat: int (int, struct stat *)
+smbc_fstatvfs: int (int, struct statvfs *)
+smbc_ftruncate: int (int, off_t)
+smbc_getDebug: int (SMBCCTX *)
+smbc_getFunctionAddCachedServer: smbc_add_cached_srv_fn (SMBCCTX *)
+smbc_getFunctionAuthData: smbc_get_auth_data_fn (SMBCCTX *)
+smbc_getFunctionAuthDataWithContext: smbc_get_auth_data_with_context_fn (SMBCCTX *)
+smbc_getFunctionCheckServer: smbc_check_server_fn (SMBCCTX *)
+smbc_getFunctionChmod: smbc_chmod_fn (SMBCCTX *)
+smbc_getFunctionClose: smbc_close_fn (SMBCCTX *)
+smbc_getFunctionClosedir: smbc_closedir_fn (SMBCCTX *)
+smbc_getFunctionCreat: smbc_creat_fn (SMBCCTX *)
+smbc_getFunctionFstat: smbc_fstat_fn (SMBCCTX *)
+smbc_getFunctionFstatVFS: smbc_fstatvfs_fn (SMBCCTX *)
+smbc_getFunctionFstatdir: smbc_fstatdir_fn (SMBCCTX *)
+smbc_getFunctionFtruncate: smbc_ftruncate_fn (SMBCCTX *)
+smbc_getFunctionGetCachedServer: smbc_get_cached_srv_fn (SMBCCTX *)
+smbc_getFunctionGetdents: smbc_getdents_fn (SMBCCTX *)
+smbc_getFunctionGetxattr: smbc_getxattr_fn (SMBCCTX *)
+smbc_getFunctionListPrintJobs: smbc_list_print_jobs_fn (SMBCCTX *)
+smbc_getFunctionListxattr: smbc_listxattr_fn (SMBCCTX *)
+smbc_getFunctionLseek: smbc_lseek_fn (SMBCCTX *)
+smbc_getFunctionLseekdir: smbc_lseekdir_fn (SMBCCTX *)
+smbc_getFunctionMkdir: smbc_mkdir_fn (SMBCCTX *)
+smbc_getFunctionNotify: smbc_notify_fn (SMBCCTX *)
+smbc_getFunctionOpen: smbc_open_fn (SMBCCTX *)
+smbc_getFunctionOpenPrintJob: smbc_open_print_job_fn (SMBCCTX *)
+smbc_getFunctionOpendir: smbc_opendir_fn (SMBCCTX *)
+smbc_getFunctionPrintFile: smbc_print_file_fn (SMBCCTX *)
+smbc_getFunctionPurgeCachedServers: smbc_purge_cached_fn (SMBCCTX *)
+smbc_getFunctionRead: smbc_read_fn (SMBCCTX *)
+smbc_getFunctionReaddir: smbc_readdir_fn (SMBCCTX *)
+smbc_getFunctionReaddirPlus: smbc_readdirplus_fn (SMBCCTX *)
+smbc_getFunctionRemoveCachedServer: smbc_remove_cached_srv_fn (SMBCCTX *)
+smbc_getFunctionRemoveUnusedServer: smbc_remove_unused_server_fn (SMBCCTX *)
+smbc_getFunctionRemovexattr: smbc_removexattr_fn (SMBCCTX *)
+smbc_getFunctionRename: smbc_rename_fn (SMBCCTX *)
+smbc_getFunctionRmdir: smbc_rmdir_fn (SMBCCTX *)
+smbc_getFunctionSetxattr: smbc_setxattr_fn (SMBCCTX *)
+smbc_getFunctionSplice: smbc_splice_fn (SMBCCTX *)
+smbc_getFunctionStat: smbc_stat_fn (SMBCCTX *)
+smbc_getFunctionStatVFS: smbc_statvfs_fn (SMBCCTX *)
+smbc_getFunctionTelldir: smbc_telldir_fn (SMBCCTX *)
+smbc_getFunctionUnlink: smbc_unlink_fn (SMBCCTX *)
+smbc_getFunctionUnlinkPrintJob: smbc_unlink_print_job_fn (SMBCCTX *)
+smbc_getFunctionUtimes: smbc_utimes_fn (SMBCCTX *)
+smbc_getFunctionWrite: smbc_write_fn (SMBCCTX *)
+smbc_getNetbiosName: char *(SMBCCTX *)
+smbc_getOptionBrowseMaxLmbCount: int (SMBCCTX *)
+smbc_getOptionCaseSensitive: smbc_bool (SMBCCTX *)
+smbc_getOptionDebugToStderr: smbc_bool (SMBCCTX *)
+smbc_getOptionFallbackAfterKerberos: smbc_bool (SMBCCTX *)
+smbc_getOptionFullTimeNames: smbc_bool (SMBCCTX *)
+smbc_getOptionNoAutoAnonymousLogin: smbc_bool (SMBCCTX *)
+smbc_getOptionOneSharePerServer: smbc_bool (SMBCCTX *)
+smbc_getOptionOpenShareMode: smbc_share_mode (SMBCCTX *)
+smbc_getOptionSmbEncryptionLevel: smbc_smb_encrypt_level (SMBCCTX *)
+smbc_getOptionUrlEncodeReaddirEntries: smbc_bool (SMBCCTX *)
+smbc_getOptionUseCCache: smbc_bool (SMBCCTX *)
+smbc_getOptionUseKerberos: smbc_bool (SMBCCTX *)
+smbc_getOptionUseNTHash: smbc_bool (SMBCCTX *)
+smbc_getOptionUserData: void *(SMBCCTX *)
+smbc_getPort: uint16_t (SMBCCTX *)
+smbc_getServerCacheData: struct smbc_server_cache *(SMBCCTX *)
+smbc_getTimeout: int (SMBCCTX *)
+smbc_getUser: char *(SMBCCTX *)
+smbc_getWorkgroup: char *(SMBCCTX *)
+smbc_getdents: int (unsigned int, struct smbc_dirent *, int)
+smbc_getxattr: int (const char *, const char *, const void *, size_t)
+smbc_init: int (smbc_get_auth_data_fn, int)
+smbc_init_context: SMBCCTX *(SMBCCTX *)
+smbc_lgetxattr: int (const char *, const char *, const void *, size_t)
+smbc_list_print_jobs: int (const char *, smbc_list_print_job_fn)
+smbc_listxattr: int (const char *, char *, size_t)
+smbc_llistxattr: int (const char *, char *, size_t)
+smbc_lremovexattr: int (const char *, const char *)
+smbc_lseek: off_t (int, off_t, int)
+smbc_lseekdir: int (int, off_t)
+smbc_lsetxattr: int (const char *, const char *, const void *, size_t, int)
+smbc_mkdir: int (const char *, mode_t)
+smbc_new_context: SMBCCTX *(void)
+smbc_notify: int (int, smbc_bool, uint32_t, unsigned int, smbc_notify_callback_fn, void *)
+smbc_open: int (const char *, int, mode_t)
+smbc_open_print_job: int (const char *)
+smbc_opendir: int (const char *)
+smbc_option_get: void *(SMBCCTX *, char *)
+smbc_option_set: void (SMBCCTX *, char *, ...)
+smbc_print_file: int (const char *, const char *)
+smbc_read: ssize_t (int, void *, size_t)
+smbc_readdir: struct smbc_dirent *(unsigned int)
+smbc_readdirplus: const struct libsmb_file_info *(unsigned int)
+smbc_removexattr: int (const char *, const char *)
+smbc_rename: int (const char *, const char *)
+smbc_rmdir: int (const char *)
+smbc_setConfiguration: int (SMBCCTX *, const char *)
+smbc_setDebug: void (SMBCCTX *, int)
+smbc_setFunctionAddCachedServer: void (SMBCCTX *, smbc_add_cached_srv_fn)
+smbc_setFunctionAuthData: void (SMBCCTX *, smbc_get_auth_data_fn)
+smbc_setFunctionAuthDataWithContext: void (SMBCCTX *, smbc_get_auth_data_with_context_fn)
+smbc_setFunctionCheckServer: void (SMBCCTX *, smbc_check_server_fn)
+smbc_setFunctionChmod: void (SMBCCTX *, smbc_chmod_fn)
+smbc_setFunctionClose: void (SMBCCTX *, smbc_close_fn)
+smbc_setFunctionClosedir: void (SMBCCTX *, smbc_closedir_fn)
+smbc_setFunctionCreat: void (SMBCCTX *, smbc_creat_fn)
+smbc_setFunctionFstat: void (SMBCCTX *, smbc_fstat_fn)
+smbc_setFunctionFstatVFS: void (SMBCCTX *, smbc_fstatvfs_fn)
+smbc_setFunctionFstatdir: void (SMBCCTX *, smbc_fstatdir_fn)
+smbc_setFunctionFtruncate: void (SMBCCTX *, smbc_ftruncate_fn)
+smbc_setFunctionGetCachedServer: void (SMBCCTX *, smbc_get_cached_srv_fn)
+smbc_setFunctionGetdents: void (SMBCCTX *, smbc_getdents_fn)
+smbc_setFunctionGetxattr: void (SMBCCTX *, smbc_getxattr_fn)
+smbc_setFunctionListPrintJobs: void (SMBCCTX *, smbc_list_print_jobs_fn)
+smbc_setFunctionListxattr: void (SMBCCTX *, smbc_listxattr_fn)
+smbc_setFunctionLseek: void (SMBCCTX *, smbc_lseek_fn)
+smbc_setFunctionLseekdir: void (SMBCCTX *, smbc_lseekdir_fn)
+smbc_setFunctionMkdir: void (SMBCCTX *, smbc_mkdir_fn)
+smbc_setFunctionNotify: void (SMBCCTX *, smbc_notify_fn)
+smbc_setFunctionOpen: void (SMBCCTX *, smbc_open_fn)
+smbc_setFunctionOpenPrintJob: void (SMBCCTX *, smbc_open_print_job_fn)
+smbc_setFunctionOpendir: void (SMBCCTX *, smbc_opendir_fn)
+smbc_setFunctionPrintFile: void (SMBCCTX *, smbc_print_file_fn)
+smbc_setFunctionPurgeCachedServers: void (SMBCCTX *, smbc_purge_cached_fn)
+smbc_setFunctionRead: void (SMBCCTX *, smbc_read_fn)
+smbc_setFunctionReaddir: void (SMBCCTX *, smbc_readdir_fn)
+smbc_setFunctionReaddirPlus: void (SMBCCTX *, smbc_readdirplus_fn)
+smbc_setFunctionRemoveCachedServer: void (SMBCCTX *, smbc_remove_cached_srv_fn)
+smbc_setFunctionRemoveUnusedServer: void (SMBCCTX *, smbc_remove_unused_server_fn)
+smbc_setFunctionRemovexattr: void (SMBCCTX *, smbc_removexattr_fn)
+smbc_setFunctionRename: void (SMBCCTX *, smbc_rename_fn)
+smbc_setFunctionRmdir: void (SMBCCTX *, smbc_rmdir_fn)
+smbc_setFunctionSetxattr: void (SMBCCTX *, smbc_setxattr_fn)
+smbc_setFunctionSplice: void (SMBCCTX *, smbc_splice_fn)
+smbc_setFunctionStat: void (SMBCCTX *, smbc_stat_fn)
+smbc_setFunctionStatVFS: void (SMBCCTX *, smbc_statvfs_fn)
+smbc_setFunctionTelldir: void (SMBCCTX *, smbc_telldir_fn)
+smbc_setFunctionUnlink: void (SMBCCTX *, smbc_unlink_fn)
+smbc_setFunctionUnlinkPrintJob: void (SMBCCTX *, smbc_unlink_print_job_fn)
+smbc_setFunctionUtimes: void (SMBCCTX *, smbc_utimes_fn)
+smbc_setFunctionWrite: void (SMBCCTX *, smbc_write_fn)
+smbc_setLogCallback: void (SMBCCTX *, void *, smbc_debug_callback_fn)
+smbc_setNetbiosName: void (SMBCCTX *, char *)
+smbc_setOptionBrowseMaxLmbCount: void (SMBCCTX *, int)
+smbc_setOptionCaseSensitive: void (SMBCCTX *, smbc_bool)
+smbc_setOptionDebugToStderr: void (SMBCCTX *, smbc_bool)
+smbc_setOptionFallbackAfterKerberos: void (SMBCCTX *, smbc_bool)
+smbc_setOptionFullTimeNames: void (SMBCCTX *, smbc_bool)
+smbc_setOptionNoAutoAnonymousLogin: void (SMBCCTX *, smbc_bool)
+smbc_setOptionOneSharePerServer: void (SMBCCTX *, smbc_bool)
+smbc_setOptionOpenShareMode: void (SMBCCTX *, smbc_share_mode)
+smbc_setOptionSmbEncryptionLevel: void (SMBCCTX *, smbc_smb_encrypt_level)
+smbc_setOptionUrlEncodeReaddirEntries: void (SMBCCTX *, smbc_bool)
+smbc_setOptionUseCCache: void (SMBCCTX *, smbc_bool)
+smbc_setOptionUseKerberos: void (SMBCCTX *, smbc_bool)
+smbc_setOptionUseNTHash: void (SMBCCTX *, smbc_bool)
+smbc_setOptionUserData: void (SMBCCTX *, void *)
+smbc_setPort: void (SMBCCTX *, uint16_t)
+smbc_setServerCacheData: void (SMBCCTX *, struct smbc_server_cache *)
+smbc_setTimeout: void (SMBCCTX *, int)
+smbc_setUser: void (SMBCCTX *, const char *)
+smbc_setWorkgroup: void (SMBCCTX *, char *)
+smbc_set_context: SMBCCTX *(SMBCCTX *)
+smbc_set_credentials: void (const char *, const char *, const char *, smbc_bool, const char *)
+smbc_set_credentials_with_fallback: void (SMBCCTX *, const char *, const char *, const char *)
+smbc_setxattr: int (const char *, const char *, const void *, size_t, int)
+smbc_stat: int (const char *, struct stat *)
+smbc_statvfs: int (char *, struct statvfs *)
+smbc_telldir: off_t (int)
+smbc_unlink: int (const char *)
+smbc_unlink_print_job: int (const char *, int)
+smbc_urldecode: int (char *, char *, size_t)
+smbc_urlencode: int (char *, char *, int)
+smbc_utime: int (const char *, struct utimbuf *)
+smbc_utimes: int (const char *, struct timeval *)
+smbc_version: const char *(void)
+smbc_write: ssize_t (int, const void *, size_t)
diff --git a/source3/libsmb/libsmb_compat.c b/source3/libsmb/libsmb_compat.c
index 5fed44abc4a..eb38480a5c6 100644
--- a/source3/libsmb/libsmb_compat.c
+++ b/source3/libsmb/libsmb_compat.c
@@ -285,6 +285,12 @@ smbc_readdir(unsigned int dh)
         return smbc_getFunctionReaddir(statcont)(statcont, file);
 }
 
+const struct libsmb_file_info *smbc_readdirplus(unsigned int dh)
+{
+	SMBCFILE * file = find_fd(dh);
+	return smbc_getFunctionReaddirPlus(statcont)(statcont, file);
+}
+
 off_t
 smbc_telldir(int dh)
 {
diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c
index b55cf1e2d15..80b2666b40b 100644
--- a/source3/libsmb/libsmb_context.c
+++ b/source3/libsmb/libsmb_context.c
@@ -208,6 +208,7 @@ smbc_new_context(void)
         smbc_setFunctionOpendir(context, SMBC_opendir_ctx);
         smbc_setFunctionClosedir(context, SMBC_closedir_ctx);
         smbc_setFunctionReaddir(context, SMBC_readdir_ctx);
+	smbc_setFunctionReaddirPlus(context, SMBC_readdirplus_ctx);
         smbc_setFunctionGetdents(context, SMBC_getdents_ctx);
         smbc_setFunctionMkdir(context, SMBC_mkdir_ctx);
         smbc_setFunctionRmdir(context, SMBC_rmdir_ctx);
diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c
index 89582ff9cf8..918a1b2ce9e 100644
--- a/source3/libsmb/libsmb_dir.c
+++ b/source3/libsmb/libsmb_dir.c
@@ -1140,6 +1140,52 @@ SMBC_readdir_ctx(SMBCCTX *context,
         return dirp;
 }
 
+/*
+ * Routine to get a directory entry with all attributes
+ */
+
+const struct libsmb_file_info *
+SMBC_readdirplus_ctx(SMBCCTX *context,
+                     SMBCFILE *dir)
+{
+	struct libsmb_file_info *smb_finfo = NULL;
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	/* Check that all is ok first ... */
+
+	if (!context || !context->internal->initialized) {
+		DBG_ERR("Invalid context in SMBC_readdirplus_ctx()\n");
+		TALLOC_FREE(frame);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (dir == NULL ||
+			SMBC_dlist_contains(context->internal->files,
+					dir) == 0) {
+		DBG_ERR("Invalid dir in SMBC_readdirplus_ctx()\n");
+		TALLOC_FREE(frame);
+		errno = EBADF;
+		return NULL;
+	}
+
+	if (dir->dirplus_next == NULL) {
+		TALLOC_FREE(frame);
+		return NULL;
+	}
+
+	smb_finfo = dir->dirplus_next->smb_finfo;
+	if (smb_finfo == NULL) {
+		TALLOC_FREE(frame);
+		errno = ENOENT;
+		return NULL;
+	}
+	dir->dirplus_next = dir->dirplus_next->next;
+
+	TALLOC_FREE(frame);
+	return smb_finfo;
+}
+
 /*
  * Routine to get directory entries
  */
diff --git a/source3/libsmb/libsmb_setget.c b/source3/libsmb/libsmb_setget.c
index cb32f5fc20e..7a17cadc891 100644
--- a/source3/libsmb/libsmb_setget.c
+++ b/source3/libsmb/libsmb_setget.c
@@ -879,6 +879,16 @@ smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn fn)
         c->readdir = fn;
 }
 
+smbc_readdirplus_fn smbc_getFunctionReaddirPlus(SMBCCTX *c)
+{
+	return c->readdirplus;
+}
+
+void smbc_setFunctionReaddirPlus(SMBCCTX *c, smbc_readdirplus_fn fn)
+{
+	c->readdirplus = fn;
+}
+
 smbc_getdents_fn
 smbc_getFunctionGetdents(SMBCCTX *c)
 {
diff --git a/source3/libsmb/wscript b/source3/libsmb/wscript
index 526434eabe0..15575bcc6ab 100644
--- a/source3/libsmb/wscript
+++ b/source3/libsmb/wscript
@@ -27,5 +27,5 @@ def build(bld):
                        public_headers='../include/libsmbclient.h',
                        abi_directory='ABI',
                        abi_match='smbc_*',
-                       vnum='0.3.2',
+                       vnum='0.3.3',
                        pc_files='smbclient.pc')
-- 
2.17.0.484.g0c8726318c-goog


From 324170bcf3957b0655959025371069c8acb54d36 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 24 Apr 2018 13:47:54 -0700
Subject: [PATCH 6/6] tests: libsmbclient: Add a readdirplus() test suite.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 source3/selftest/tests.py                   |  8 +-
 source4/selftest/tests.py                   |  3 +-
 source4/torture/libsmbclient/libsmbclient.c | 96 +++++++++++++++++++++
 3 files changed, 104 insertions(+), 3 deletions(-)

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 06bda707ddb..d172dfd53e3 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -551,8 +551,12 @@ for t in tests:
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD --option=torture:wksname=samba3rpctest')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD --option=torture:wksname=samba3rpctest')
     elif t == "libsmbclient":
-        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%%$PASSWORD --option=torture:replace_smbconf=%s' % os.path.join(srcdir(), "testdata/samba3/smb_new.conf"))
-        plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%%$PASSWORD --option=torture:replace_smbconf=%s' % os.path.join(srcdir(), "testdata/samba3/smb_new.conf"))
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%%$PASSWORD '
+                                    '--option=torture:smburl=smb://$USERNAME:$PASSWORD@$SERVER/tmp '
+                                    '--option=torture:replace_smbconf=%s' % os.path.join(srcdir(), "testdata/samba3/smb_new.conf"))
+        plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%%$PASSWORD '
+                                    '--option=torture:smburl=smb://$USERNAME:$PASSWORD@$SERVER/tmp '
+                                    '--option=torture:replace_smbconf=%s' % os.path.join(srcdir(), "testdata/samba3/smb_new.conf"))
     else:
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index d1e5bc6a509..1b91d76e663 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -313,7 +313,8 @@ base = smbtorture4_testsuites("base.")
 netapi = smbtorture4_testsuites("netapi.")
 
 libsmbclient = smbtorture4_testsuites("libsmbclient.")
-libsmbclient_testargs = ["--option=torture:replace_smbconf=%s/testdata/samba3/smb_new.conf" % srcdir()]
+libsmbclient_testargs = ["--option=torture:smburl=smb://$USERNAME:$PASSWORD@$SERVER/tmp",
+                         "--option=torture:replace_smbconf=%s/testdata/samba3/smb_new.conf" % srcdir()]
 
 for t in base + raw + smb2 + netapi + libsmbclient:
     plansmbtorture4testsuite(t, "ad_dc_ntvfs", ['//$SERVER/tmp', '-U$USERNAME%$PASSWORD'] + ntvfsargs + libsmbclient_testargs)
diff --git a/source4/torture/libsmbclient/libsmbclient.c b/source4/torture/libsmbclient/libsmbclient.c
index 00e766c488a..91579f4b1b7 100644
--- a/source4/torture/libsmbclient/libsmbclient.c
+++ b/source4/torture/libsmbclient/libsmbclient.c
@@ -223,6 +223,100 @@ static bool torture_libsmbclient_opendir(struct torture_context *tctx)
 	return ret;
 }
 
+static bool torture_libsmbclient_readdirplus(struct torture_context *tctx)
+{
+	SMBCCTX *ctx;
+	int ret = -1;
+	int dhandle = -1;
+	int fhandle = -1;
+	bool found = false;
+	const char *filename = NULL;
+	const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+
+	if (smburl == NULL) {
+		torture_fail(tctx,
+			"option --option=torture:smburl="
+			"smb://user:password@server/share missing\n");
+	}
+
+	torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
+	smbc_set_context(ctx);
+
+	filename = talloc_asprintf(tctx,
+				"%s/test_readdirplus.txt",
+				smburl);
+	if (filename == NULL) {
+		torture_fail(tctx,
+			"talloc fail\n");
+	}
+	/* Ensure the file doesn't exist. */
+	smbc_unlink(filename);
+
+	/* Create it. */
+	fhandle = smbc_creat(filename, 0666);
+	if (fhandle < 0) {
+		torture_fail(tctx,
+			talloc_asprintf(tctx,
+				"failed to create file '%s': %s",
+				filename,
+				strerror(errno)));
+	}
+	ret = smbc_close(fhandle);
+	torture_assert_int_equal(tctx,
+		ret,
+		0,
+		talloc_asprintf(tctx,
+			"failed to close handle for '%s'",
+			filename));
+
+	dhandle = smbc_opendir(smburl);
+	if (dhandle < 0) {
+		int saved_errno = errno;
+		smbc_unlink(filename);
+		torture_fail(tctx,
+			talloc_asprintf(tctx,
+				"failed to obtain "
+				"directory handle for '%s' : %s",
+				smburl,
+				strerror(saved_errno)));
+	}
+
+	/* Readdirplus to ensure we see the new file. */
+	for (;;) {
+		const struct libsmb_file_info *exstat =
+			smbc_readdirplus(dhandle);
+		if (exstat == NULL) {
+			break;
+		}
+		if (strcmp(exstat->name, "test_readdirplus.txt") == 0) {
+			found = true;
+			break;
+		}
+	}
+
+	/* Remove it again. */
+	smbc_unlink(filename);
+	ret = smbc_closedir(dhandle);
+	torture_assert_int_equal(tctx,
+		ret,
+		0,
+		talloc_asprintf(tctx,
+			"failed to close directory handle for '%s'",
+			smburl));
+
+	smbc_free_context(ctx, 1);
+
+	if (!found) {
+		torture_fail(tctx,
+			talloc_asprintf(tctx,
+				"failed to find file '%s'",
+				filename));
+	}
+
+	return true;
+}
+
+
 /* note the strdup for string options on smbc_set calls. I think libsmbclient is
  * really doing something wrong here: in smbc_free_context libsmbclient just
  * calls free() on the string options so it assumes the callers have malloced
@@ -298,6 +392,8 @@ NTSTATUS torture_libsmbclient_init(TALLOC_CTX *ctx)
 	torture_suite_add_simple_test(suite, "setConfiguration", torture_libsmbclient_setConfiguration);
 	torture_suite_add_simple_test(suite, "options", torture_libsmbclient_options);
 	torture_suite_add_simple_test(suite, "opendir", torture_libsmbclient_opendir);
+	torture_suite_add_simple_test(suite, "readdirplus",
+		torture_libsmbclient_readdirplus);
 
 	suite->description = talloc_strdup(suite, "libsmbclient interface tests");
 
-- 
2.17.0.484.g0c8726318c-goog



More information about the samba-technical mailing list