diff options
author | Tim Beale <timbeale@catalyst.net.nz> | 2018-12-12 13:45:46 +1300 |
---|---|---|
committer | Tim Beale <timbeale@samba.org> | 2019-01-07 01:23:08 +0100 |
commit | 9a3e640bbaa45f2b6cd2e9a2ff514fdfa26759d0 (patch) | |
tree | 14be44053ceaf546e645b87415b079a51e758bd5 /source3 | |
parent | ea00215d53891215e20531f75a7ec7e5dec3df5e (diff) | |
download | samba-9a3e640bbaa45f2b6cd2e9a2ff514fdfa26759d0.tar.gz |
s3:pylibsmb: Add .deltree() API to SMB py bindings
This basically re-uses the underlying functionality of existing APIs in
order to support a .deltree() API, i.e.
- we use the .list() functionality (i.e. do_listing()) to traverse every
item in the given directory.
- we then use either .unlink() (i.e. unlink_file()) or .rmdir() (i.e.
remove_dir()) to delete the individual item.
- sub-directories are handled recursively, by repeating the process.
Note that the .deltree() API is currently only really used for testing
(and deleting GPO files). So the recursion is never going to be
excessive.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
Signed-off-by: Tim Beale <timbeale@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'source3')
-rw-r--r-- | source3/libsmb/pylibsmb.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/source3/libsmb/pylibsmb.c b/source3/libsmb/pylibsmb.c index 44389454d6f..452c30e9490 100644 --- a/source3/libsmb/pylibsmb.c +++ b/source3/libsmb/pylibsmb.c @@ -1380,6 +1380,98 @@ static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args) return PyBool_FromLong(dir_exists); } +struct deltree_state { + struct py_cli_state *self; + const char *full_dirpath; +}; + +static NTSTATUS delete_dir_tree(struct py_cli_state *self, + const char *dirpath); + +/* + * Deletes a single item in the directory tree. This could be either a file + * or a directory. This function gets invoked as a callback for every item in + * the given directory's listings. + */ +static NTSTATUS delete_tree_callback(const char *mntpoint, + struct file_info *finfo, + const char *mask, void *priv) +{ + char *filepath = NULL; + struct deltree_state *state = priv; + NTSTATUS status; + + /* skip '.' or '..' directory listings */ + if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) { + return NT_STATUS_OK; + } + + /* get the absolute filepath */ + filepath = talloc_asprintf(NULL, "%s\\%s", state->full_dirpath, + finfo->name); + if (filepath == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) { + + /* recursively delete the sub-directory and its contents */ + status = delete_dir_tree(state->self, filepath); + } else { + status = unlink_file(state->self, filepath); + } + + TALLOC_FREE(filepath); + return status; +} + +/* + * Removes a directory and all its contents + */ +static NTSTATUS delete_dir_tree(struct py_cli_state *self, + const char *filepath) +{ + NTSTATUS status; + const char *mask = "*"; + struct deltree_state state = { 0 }; + + /* go through the directory's contents, deleting each item */ + state.self = self; + state.full_dirpath = filepath; + status = do_listing(self, filepath, mask, LIST_ATTRIBUTE_MASK, + delete_tree_callback, &state); + + /* remove the directory itself */ + if (NT_STATUS_IS_OK(status)) { + status = remove_dir(self, filepath); + } + return status; +} + +static PyObject *py_smb_deltree(struct py_cli_state *self, PyObject *args) +{ + NTSTATUS status; + const char *filepath = NULL; + bool dir_exists; + + if (!PyArg_ParseTuple(args, "s:deltree", &filepath)) { + return NULL; + } + + /* check whether we're removing a directory or a file */ + dir_exists = check_dir_path(self, filepath); + + if (dir_exists) { + status = delete_dir_tree(self, filepath); + } else { + status = unlink_file(self, filepath); + } + + PyErr_NTSTATUS_IS_ERR_RAISE(status); + + Py_RETURN_NONE; +} + static PyMethodDef py_cli_state_methods[] = { { "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS, "settimeout(new_timeout_msecs) => return old_timeout_msecs" }, @@ -1426,6 +1518,9 @@ static PyMethodDef py_cli_state_methods[] = { { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS, "loadfile(path) -> file contents as a " PY_DESC_PY3_BYTES "\n\n\t\tRead contents of a file." }, + { "deltree", (PyCFunction)py_smb_deltree, METH_VARARGS, + "deltree(path) -> None\n\n" + "\t\tDelete a directory and all its contents." }, { NULL, NULL, 0, NULL } }; |