summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorTim Beale <timbeale@catalyst.net.nz>2018-12-12 13:45:46 +1300
committerTim Beale <timbeale@samba.org>2019-01-07 01:23:08 +0100
commit9a3e640bbaa45f2b6cd2e9a2ff514fdfa26759d0 (patch)
tree14be44053ceaf546e645b87415b079a51e758bd5 /source3
parentea00215d53891215e20531f75a7ec7e5dec3df5e (diff)
downloadsamba-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.c95
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 }
};