]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
smbd: add opens_below_forall() and opens_below_forall_read()
authorRalph Boehme <slow@samba.org>
Sat, 12 Oct 2024 14:33:47 +0000 (16:33 +0200)
committerRalph Boehme <slow@samba.org>
Tue, 5 Nov 2024 14:39:30 +0000 (14:39 +0000)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15608

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/smbd/dir.c
source3/smbd/dir.h

index 17e7d0f4ac54c469f3d928c7e515514325b6de93..d974d36cdf53e0348c53ea2c4d76b325a7f4d651 100644 (file)
@@ -1372,6 +1372,188 @@ bool have_file_open_below(connection_struct *conn,
        return state.found_one;
 }
 
+struct opens_below_forall_read_state {
+       char *dirpath;
+       ssize_t dirpath_len;
+       int (*fn)(const struct share_mode_data *data,
+                 const struct share_mode_entry *e,
+                 void *private_data);
+       void *private_data;
+};
+
+static int opens_below_forall_read_fn(struct file_id fid,
+                                     const struct share_mode_data *data,
+                                     const struct share_mode_entry *entry,
+                                     void *private_data)
+{
+       struct opens_below_forall_read_state *state = private_data;
+       char tmpbuf[PATH_MAX];
+       char *fullpath = NULL;
+       char *to_free = NULL;
+       ssize_t len;
+
+       len = full_path_tos(data->servicepath,
+                           data->base_name,
+                           tmpbuf,
+                           sizeof(tmpbuf),
+                           &fullpath,
+                           &to_free);
+       if (len == -1) {
+               return -1;
+       }
+       if (state->dirpath_len >= len) {
+               /*
+                * Filter files above dirpath
+                */
+               goto out;
+       }
+       if (fullpath[state->dirpath_len] != '/') {
+               /*
+                * Filter file that don't have a path separator at the end of
+                * dirpath's length
+                */
+               goto out;
+       }
+
+       if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
+               /*
+                * Not a parent
+                */
+               goto out;
+       }
+
+       TALLOC_FREE(to_free);
+       return state->fn(data, entry, state->private_data);
+
+out:
+       TALLOC_FREE(to_free);
+       return 1;
+}
+
+bool opens_below_forall_read(struct connection_struct *conn,
+                            const struct smb_filename *dir_name,
+                            int (*fn)(const struct share_mode_data *data,
+                                      const struct share_mode_entry *e,
+                                      void *private_data),
+                            void *private_data)
+{
+       struct opens_below_forall_read_state state = {
+               .fn = fn,
+               .private_data = private_data,
+       };
+       int ret;
+       char tmpbuf[PATH_MAX];
+       char *to_free = NULL;
+
+       state.dirpath_len = full_path_tos(conn->connectpath,
+                                         dir_name->base_name,
+                                         tmpbuf,
+                                         sizeof(tmpbuf),
+                                         &state.dirpath,
+                                         &to_free);
+       if (state.dirpath_len == -1) {
+               return false;
+       }
+
+       ret = share_entry_forall_read(opens_below_forall_read_fn, &state);
+       TALLOC_FREE(to_free);
+       if (ret == -1) {
+               return false;
+       }
+       return true;
+}
+
+struct opens_below_forall_state {
+       char *dirpath;
+       ssize_t dirpath_len;
+       int (*fn)(struct share_mode_data *data,
+                 struct share_mode_entry *e,
+                 void *private_data);
+       void *private_data;
+};
+
+static int opens_below_forall_fn(struct file_id fid,
+                                struct share_mode_data *data,
+                                struct share_mode_entry *entry,
+                                void *private_data)
+{
+       struct opens_below_forall_state *state = private_data;
+       char tmpbuf[PATH_MAX];
+       char *fullpath = NULL;
+       char *to_free = NULL;
+       ssize_t len;
+
+       len = full_path_tos(data->servicepath,
+                           data->base_name,
+                           tmpbuf,
+                           sizeof(tmpbuf),
+                           &fullpath,
+                           &to_free);
+       if (len == -1) {
+               return -1;
+       }
+       if (state->dirpath_len >= len) {
+               /*
+                * Filter files above dirpath
+                */
+               goto out;
+       }
+       if (fullpath[state->dirpath_len] != '/') {
+               /*
+                * Filter file that don't have a path separator at the end of
+                * dirpath's length
+                */
+               goto out;
+       }
+
+       if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
+               /*
+                * Not a parent
+                */
+               goto out;
+       }
+
+       TALLOC_FREE(to_free);
+       return state->fn(data, entry, state->private_data);
+
+out:
+       TALLOC_FREE(to_free);
+       return 1;
+}
+
+bool opens_below_forall(struct connection_struct *conn,
+                       const struct smb_filename *dir_name,
+                       int (*fn)(struct share_mode_data *data,
+                                 struct share_mode_entry *e,
+                                 void *private_data),
+                       void *private_data)
+{
+       struct opens_below_forall_state state = {
+               .fn = fn,
+               .private_data = private_data,
+       };
+       int ret;
+       char tmpbuf[PATH_MAX];
+       char *to_free = NULL;
+
+       state.dirpath_len = full_path_tos(conn->connectpath,
+                                         dir_name->base_name,
+                                         tmpbuf,
+                                         sizeof(tmpbuf),
+                                         &state.dirpath,
+                                         &to_free);
+       if (state.dirpath_len == -1) {
+               return false;
+       }
+
+       ret = share_entry_forall(opens_below_forall_fn, &state);
+       TALLOC_FREE(to_free);
+       if (ret == -1) {
+               return false;
+       }
+       return true;
+}
+
 /*****************************************************************
  Is this directory empty ?
 *****************************************************************/
index d520d1380b5a14cbc782addd6207cef08d247307..c6272652c0db679c6f99f93051b3a907ae64e042 100644 (file)
@@ -49,6 +49,18 @@ void dptr_set_priv(struct dptr_struct *dptr);
 const char *dptr_wcard(struct smbd_server_connection *sconn, int key);
 bool have_file_open_below(connection_struct *conn,
                          const struct smb_filename *name);
+bool opens_below_forall(struct connection_struct *conn,
+                       const struct smb_filename *dir_name,
+                       int (*fn)(struct share_mode_data *data,
+                                 struct share_mode_entry *e,
+                                 void *private_data),
+                       void *private_data);
+bool opens_below_forall_read(struct connection_struct *conn,
+                            const struct smb_filename *dir_name,
+                            int (*fn)(const struct share_mode_data *data,
+                                      const struct share_mode_entry *e,
+                                      void *private_data),
+                            void *private_data);
 bool init_dptrs(struct smbd_server_connection *sconn);
 bool is_visible_fsp(files_struct *fsp);
 NTSTATUS OpenDir(TALLOC_CTX *mem_ctx,