libsmb: Implement smbc_notify
authorVolker Lendecke <vl@samba.org>
Fri, 26 Jun 2015 11:36:43 +0000 (13:36 +0200)
committerJeremy Allison <jra@samba.org>
Fri, 10 Jul 2015 07:35:13 +0000 (09:35 +0200)
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Fri Jul 10 09:35:13 CEST 2015 on sn-devel-104

examples/libsmbclient/testnotify.c [new file with mode: 0644]
examples/libsmbclient/wscript_build
source3/include/libsmb_internal.h
source3/include/libsmbclient.h
source3/libsmb/ABI/smbclient-0.2.3.sigs [new file with mode: 0644]
source3/libsmb/libsmb_compat.c
source3/libsmb/libsmb_context.c
source3/libsmb/libsmb_dir.c
source3/libsmb/libsmb_setget.c
source3/libsmb/wscript

diff --git a/examples/libsmbclient/testnotify.c b/examples/libsmbclient/testnotify.c
new file mode 100644 (file)
index 0000000..68513af
--- /dev/null
@@ -0,0 +1,78 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <libsmbclient.h>
+#include <inttypes.h>
+#include "get_auth_data_fn.h"
+
+static int notify_cb(const struct smbc_notify_callback_action *actions,
+                    size_t num_actions, void *private_data)
+{
+       int *count = private_data;
+       size_t i;
+
+       printf("%zu\n", num_actions);
+
+       for (i=0; i<num_actions; i++) {
+               const struct smbc_notify_callback_action *a = &actions[i];
+               printf("%s: %"PRIu32"\n", a->filename, a->action);
+       }
+
+       *count -= 1;
+       if (*count < 0) {
+               return 1;
+       }
+
+       return 0;
+}
+
+int main(int argc, char * argv[])
+{
+       int             fd;
+       int             ret;
+       int             debug = 0;
+       int             saved_errno;
+       char            path[2048];
+       char *          p;
+       int count = 1000;
+
+       smbc_init(get_auth_data_fn, debug);
+
+       fprintf(stdout, "Path: ");
+       *path = '\0';
+       fgets(path, sizeof(path) - 1, stdin);
+       if (strlen(path) == 0) {
+               return 0;
+       }
+
+       p = path + strlen(path) - 1;
+       if (*p == '\n') {
+               *p = '\0';
+       }
+
+       fd = smbc_opendir(path);
+       if (fd < 0) {
+               perror("smbc_open");
+               return 1;
+       }
+
+       ret = smbc_notify(fd, 1,
+                         SMBC_NOTIFY_CHANGE_SECURITY|
+                         SMBC_NOTIFY_CHANGE_FILE_NAME,
+                         1000, notify_cb, &count);
+       if (ret < 0) {
+               saved_errno = errno;
+       }
+
+       smbc_close(fd);
+
+       if (ret < 0) {
+               errno = saved_errno;
+               perror("notify");
+       }
+
+       return 0;
+}
index aa39965..c58a5b9 100644 (file)
@@ -6,6 +6,7 @@ names = ['testsmbc',
          'testacl3',
          'testbrowse',
          'testbrowse2',
+         'testnotify',
          'teststat',
          'teststat2',
          'teststat3',
index cf51f34..0e0045e 100644 (file)
@@ -247,6 +247,7 @@ struct SMBC_internal_data {
         struct
         {
                 smbc_splice_fn                  splice_fn;
+               smbc_notify_fn                  notify_fn;
         }               smb;
 
        uint16_t        port;
@@ -344,6 +345,12 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
                 SMBCCTX *ncontext,
                 const char *nname);
 
+int
+SMBC_notify_ctx(SMBCCTX *c, SMBCFILE *dir, smbc_bool recursive,
+               uint32_t completion_filter, unsigned callback_timeout_ms,
+               smbc_notify_callback_fn cb, void *private_data);
+
+
 
 /* Functions in libsmb_file.c */
 SMBCFILE *
index faaab2e..cf67b1d 100644 (file)
@@ -993,6 +993,30 @@ typedef int (*smbc_fstatdir_fn)(SMBCCTX *c,
 smbc_fstatdir_fn smbc_getFunctionFstatdir(SMBCCTX *c);
 void smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn);
 
+#define SMBC_NOTIFY_ACTION_ADDED               1
+#define SMBC_NOTIFY_ACTION_REMOVED             2
+#define SMBC_NOTIFY_ACTION_MODIFIED            3
+#define SMBC_NOTIFY_ACTION_OLD_NAME            4
+#define SMBC_NOTIFY_ACTION_NEW_NAME            5
+#define SMBC_NOTIFY_ACTION_ADDED_STREAM        6
+#define SMBC_NOTIFY_ACTION_REMOVED_STREAM      7
+#define SMBC_NOTIFY_ACTION_MODIFIED_STREAM     8
+
+struct smbc_notify_callback_action {
+       uint32_t action;
+       const char *filename;
+};
+
+typedef int (*smbc_notify_callback_fn)(
+       const struct smbc_notify_callback_action *actions,
+       size_t num_actions, void *private_data);
+
+typedef int (*smbc_notify_fn)(SMBCCTX *c, SMBCFILE *dir, smbc_bool recursive,
+                             uint32_t completion_filter,
+                             unsigned callback_timeout_ms,
+                             smbc_notify_callback_fn cb, void *private_data);
+smbc_notify_fn smbc_getFunctionNotify(SMBCCTX *c);
+void smbc_setFunctionNotify(SMBCCTX *c, smbc_notify_fn fn);
 
 
 /*****************************************************************
@@ -1620,6 +1644,47 @@ int smbc_mkdir(const char *durl, mode_t mode);
  */
 int smbc_rmdir(const char *durl);
 
+/**@ingroup directory
+ * Request directory notifications
+ *
+ * @param dh                    Valid directory as returned by smbc_opendir()
+ *
+ * @param recursive            Are changes in subdirectories wanted?
+ *
+ * @param completion_filter    Bitwise-or of the SMBC_NOTIFY_CHANGE_*
+ *                              events that are interesting
+ *
+ * @param callback_timeout_ms   If set to non-zero, interval in milliseconds
+ *                              that "cb" will be called with 0 actions.
+ *                              This gives "cb" the chance to cancel the
+ *                              smbc_notify call.
+ *
+ * @param cb                    Callback functions taking events. If "cb"
+ *                              returns nonzero, smbc_notify will return.
+ *
+ * @param private_data          Pointer given to "cb"
+ *
+ * @return                      0 on success, -1 on error with errno set
+ *
+ * @see                         smbc_opendir(), smbc_closedir()
+ */
+
+#define SMBC_NOTIFY_CHANGE_FILE_NAME           0x001
+#define SMBC_NOTIFY_CHANGE_DIR_NAME            0x002
+#define SMBC_NOTIFY_CHANGE_ATTRIBUTES          0x004
+#define SMBC_NOTIFY_CHANGE_SIZE                0x008
+#define SMBC_NOTIFY_CHANGE_LAST_WRITE          0x010
+#define SMBC_NOTIFY_CHANGE_LAST_ACCESS         0x020
+#define SMBC_NOTIFY_CHANGE_CREATION            0x040
+#define SMBC_NOTIFY_CHANGE_EA                  0x080
+#define SMBC_NOTIFY_CHANGE_SECURITY            0x100
+#define SMBC_NOTIFY_CHANGE_STREAM_NAME         0x200
+#define SMBC_NOTIFY_CHANGE_STREAM_SIZE         0x400
+#define SMBC_NOTIFY_CHANGE_STREAM_WRITE        0x800
+
+int smbc_notify(int dh, smbc_bool recursive, uint32_t completion_filter,
+               unsigned callback_timeout_ms,
+               smbc_notify_callback_fn cb, void *private_data);
 
 /**@ingroup attribute
  * Get information about a file or directory.
diff --git a/source3/libsmb/ABI/smbclient-0.2.3.sigs b/source3/libsmb/ABI/smbclient-0.2.3.sigs
new file mode 100644 (file)
index 0000000..cda537c
--- /dev/null
@@ -0,0 +1,179 @@
+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_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_removexattr: int (const char *, const char *)
+smbc_rename: int (const char *, const char *)
+smbc_rmdir: int (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_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_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 *, 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)
index 38f7d36..5fed44a 100644 (file)
@@ -313,6 +313,17 @@ smbc_rmdir(const char *durl)
         return smbc_getFunctionRmdir(statcont)(statcont, durl);
 }
 
+int
+smbc_notify(int dh, smbc_bool recursive, uint32_t completion_filter,
+           unsigned callback_timeout_ms,
+           smbc_notify_callback_fn cb, void *private_data)
+{
+       SMBCFILE *dir = find_fd(dh);
+       return smbc_getFunctionNotify(statcont)(
+               statcont, dir, recursive, completion_filter,
+               callback_timeout_ms, cb, private_data);
+}
+
 int
 smbc_stat(const char *url,
           struct stat *st)
index 9541fc1..5e31dfb 100644 (file)
@@ -214,6 +214,7 @@ smbc_new_context(void)
         smbc_setFunctionTelldir(context, SMBC_telldir_ctx);
         smbc_setFunctionLseekdir(context, SMBC_lseekdir_ctx);
         smbc_setFunctionFstatdir(context, SMBC_fstatdir_ctx);
+        smbc_setFunctionNotify(context, SMBC_notify_ctx);
         smbc_setFunctionChmod(context, SMBC_chmod_ctx);
         smbc_setFunctionUtimes(context, SMBC_utimes_ctx);
         smbc_setFunctionSetxattr(context, SMBC_setxattr_ctx);
index d131c30..f332525 100644 (file)
@@ -31,6 +31,8 @@
 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
 #include "libsmb/nmblib.h"
 #include "../libcli/smb/smbXcli_base.h"
+#include "../libcli/security/security.h"
+#include "lib/util/tevent_ntstatus.h"
 
 /*
  * Routine to open a directory
@@ -2047,3 +2049,255 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
        return 0; /* Success */
 }
 
+struct smbc_notify_cb_state {
+       struct tevent_context *ev;
+       struct cli_state *cli;
+       uint16_t fnum;
+       bool recursive;
+       uint32_t completion_filter;
+       unsigned callback_timeout_ms;
+       smbc_notify_callback_fn cb;
+       void *private_data;
+};
+
+static void smbc_notify_cb_got_changes(struct tevent_req *subreq);
+static void smbc_notify_cb_timedout(struct tevent_req *subreq);
+
+static struct tevent_req *smbc_notify_cb_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+       uint16_t fnum, bool recursive, uint32_t completion_filter,
+       unsigned callback_timeout_ms,
+       smbc_notify_callback_fn cb, void *private_data)
+{
+       struct tevent_req *req, *subreq;
+       struct smbc_notify_cb_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct smbc_notify_cb_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->ev = ev;
+       state->cli = cli;
+       state->fnum = fnum;
+       state->recursive = recursive;
+       state->completion_filter = completion_filter;
+       state->callback_timeout_ms = callback_timeout_ms;
+       state->cb = cb;
+       state->private_data = private_data;
+
+       subreq = cli_notify_send(
+               state, state->ev, state->cli, state->fnum, 1000,
+               state->completion_filter, state->recursive);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
+
+       if (state->callback_timeout_ms == 0) {
+               return req;
+       }
+
+       subreq = tevent_wakeup_send(
+               state, state->ev,
+               tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
+                                          state->callback_timeout_ms*1000));
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
+
+       return req;
+}
+
+static void smbc_notify_cb_got_changes(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct smbc_notify_cb_state *state = tevent_req_data(
+               req, struct smbc_notify_cb_state);
+       uint32_t num_changes;
+       struct notify_change *changes;
+       NTSTATUS status;
+       int cb_ret;
+
+       status = cli_notify_recv(subreq, state, &num_changes, &changes);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       {
+               struct smbc_notify_callback_action actions[num_changes];
+               uint32_t i;
+
+               for (i=0; i<num_changes; i++) {
+                       actions[i].action = changes[i].action;
+                       actions[i].filename = changes[i].name;
+               }
+
+               cb_ret = state->cb(actions, num_changes, state->private_data);
+       }
+
+       TALLOC_FREE(changes);
+
+       if (cb_ret != 0) {
+               tevent_req_done(req);
+               return;
+       }
+
+       subreq = cli_notify_send(
+               state, state->ev, state->cli, state->fnum, 1000,
+               state->completion_filter, state->recursive);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
+}
+
+static void smbc_notify_cb_timedout(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct smbc_notify_cb_state *state = tevent_req_data(
+               req, struct smbc_notify_cb_state);
+       int cb_ret;
+       bool ok;
+
+       ok = tevent_wakeup_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!ok) {
+               tevent_req_oom(req);
+               return;
+       }
+
+       cb_ret = state->cb(NULL, 0, state->private_data);
+       if (cb_ret != 0) {
+               tevent_req_done(req);
+               return;
+       }
+
+       subreq = tevent_wakeup_send(
+               state, state->ev,
+               tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
+                                          state->callback_timeout_ms*1000));
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
+}
+
+static NTSTATUS smbc_notify_cb_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS smbc_notify_cb(struct cli_state *cli, uint16_t fnum,
+                              bool recursive, uint32_t completion_filter,
+                              unsigned callback_timeout_ms,
+                              smbc_notify_callback_fn cb, void *private_data)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = samba_tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = smbc_notify_cb_send(frame, ev, cli, fnum, recursive,
+                                 completion_filter,
+                                 callback_timeout_ms, cb, private_data);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = smbc_notify_cb_recv(req);
+       TALLOC_FREE(req);
+fail:
+       TALLOC_FREE(frame);
+       return status;
+}
+
+int
+SMBC_notify_ctx(SMBCCTX *context, SMBCFILE *dir, smbc_bool recursive,
+               uint32_t completion_filter, unsigned callback_timeout_ms,
+               smbc_notify_callback_fn cb, void *private_data)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct cli_state *cli = dir->srv->cli;
+       char *server = NULL;
+       char *share = NULL;
+       char *user = NULL;
+       char *password = NULL;
+       char *options = NULL;
+       char *workgroup = NULL;
+       char *path = NULL;
+       uint16_t port;
+       NTSTATUS status;
+       uint16_t fnum;
+
+       if ((context == NULL) || !context->internal->initialized) {
+               TALLOC_FREE(frame);
+               errno = EINVAL;
+               return -1;
+       }
+       if ((dir == NULL) ||
+           !SMBC_dlist_contains(context->internal->files, dir)) {
+               TALLOC_FREE(frame);
+               errno = EBADF;
+               return -1;
+       }
+
+       if (SMBC_parse_path(frame,
+                            context,
+                            dir->fname,
+                            &workgroup,
+                            &server,
+                            &port,
+                            &share,
+                            &path,
+                            &user,
+                            &password,
+                            &options)) {
+               DEBUG(4, ("no valid path\n"));
+               TALLOC_FREE(frame);
+               errno = EINVAL + 8194;
+               return -1;
+       }
+
+       DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
+                  "path='%s' options='%s'\n",
+                  dir->fname, server, share, path, options));
+
+       DEBUG(4, ("%s(%p, %d, %"PRIu32")\n", __func__, dir,
+                 (int)recursive, completion_filter));
+
+       status = cli_ntcreate(
+               cli, path, 0, FILE_READ_DATA, 0,
+               FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+               FILE_OPEN, 0, 0, &fnum, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
+               int err = SMBC_errno(context, cli);
+               TALLOC_FREE(frame);
+               errno = err;
+               return -1;
+       }
+
+       status = smbc_notify_cb(cli, fnum, recursive != 0, completion_filter,
+                               callback_timeout_ms, cb, private_data);
+       if (!NT_STATUS_IS_OK(status)) {
+               int err = SMBC_errno(context, cli);
+               cli_close(cli, fnum);
+               TALLOC_FREE(frame);
+               errno = err;
+               return -1;
+       }
+
+       cli_close(cli, fnum);
+
+       TALLOC_FREE(frame);
+       return 0;
+}
index 0bdb715..80ac673 100644 (file)
@@ -928,6 +928,18 @@ smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn)
         c->fstatdir = fn;
 }
 
+smbc_notify_fn
+smbc_getFunctionNotify(SMBCCTX *c)
+{
+        return c->internal->smb.notify_fn;
+}
+
+void
+smbc_setFunctionNotify(SMBCCTX *c, smbc_notify_fn fn)
+{
+        c->internal->smb.notify_fn = fn;
+}
+
 
 /**
  * Callable functions applicable to both files and directories.
index 8770aa3..4f8b217 100644 (file)
@@ -27,5 +27,5 @@ def build(bld):
                        public_headers='../include/libsmbclient.h',
                        abi_directory='ABI',
                        abi_match='smbc_*',
-                       vnum='0.2.2',
+                       vnum='0.2.3',
                        pc_files='smbclient.pc')