From b6f484ae9ca737a0772b279b88fc285fe1cec0e9 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 5 Jul 2017 17:21:18 -0700 Subject: [PATCH] s3: smbclient: Add new command deltree. Signed-off-by: Jeremy Allison Reviewed-by: Alexander Bokovoy Reviewed-by: Andreas Schneider --- source3/client/client.c | 178 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/source3/client/client.c b/source3/client/client.c index a9d842441b6..d8c96e68190 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -2438,6 +2438,183 @@ static int cmd_del(void) return 0; } +/**************************************************************************** + Delete some files. +****************************************************************************/ + +static NTSTATUS delete_remote_files_list(struct cli_state *cli_state, + struct file_list *flist) +{ + NTSTATUS status = NT_STATUS_OK; + struct file_list *deltree_list_iter = NULL; + + for (deltree_list_iter = flist; + deltree_list_iter != NULL; + deltree_list_iter = deltree_list_iter->next) { + if (CLI_DIRSEP_CHAR == '/') { + /* POSIX. */ + status = cli_posix_unlink(cli_state, + deltree_list_iter->file_path); + } else if (deltree_list_iter->isdir) { + status = cli_rmdir(cli_state, + deltree_list_iter->file_path); + } else { + status = cli_unlink(cli_state, + deltree_list_iter->file_path, + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN); + } + if (!NT_STATUS_IS_OK(status)) { + d_printf("%s deleting remote %s %s\n", + nt_errstr(status), + deltree_list_iter->isdir ? + "directory" : "file", + deltree_list_iter->file_path); + return status; + } + } + return NT_STATUS_OK; +} + +/**************************************************************************** + Save a list of files to delete. +****************************************************************************/ + +static struct file_list *deltree_list_head; + +static NTSTATUS do_deltree_list(struct cli_state *cli_state, + struct file_info *finfo, + const char *dir) +{ + struct file_list **file_list_head_pp = &deltree_list_head; + struct file_list *dt = NULL; + + if (!do_this_one(finfo)) { + return NT_STATUS_OK; + } + + /* skip if this is . or .. */ + if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) { + return NT_STATUS_OK; + } + + dt = talloc_zero(NULL, struct file_list); + if (dt == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* create absolute filename for cli_ntcreate() */ + dt->file_path = talloc_asprintf(dt, + "%s%s%s", + dir, + CLI_DIRSEP_STR, + finfo->name); + if (dt->file_path == NULL) { + TALLOC_FREE(dt); + return NT_STATUS_NO_MEMORY; + } + + if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) { + dt->isdir = true; + } + + DLIST_ADD(*file_list_head_pp, dt); + return NT_STATUS_OK; +} + +static int cmd_deltree(void) +{ + TALLOC_CTX *ctx = talloc_tos(); + char *buf = NULL; + NTSTATUS status = NT_STATUS_OK; + struct file_list *deltree_list_norecurse = NULL; + struct file_list *deltree_list_iter = NULL; + uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_DIRECTORY; + bool ok; + char *mask = talloc_strdup(ctx, client_get_cur_dir()); + if (mask == NULL) { + return 1; + } + ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL); + if (!ok) { + d_printf("deltree \n"); + return 1; + } + mask = talloc_asprintf_append(mask, "%s", buf); + if (mask == NULL) { + return 1; + } + + deltree_list_head = NULL; + + /* + * Get the list of directories to + * delete (in case mask has a wildcard). + */ + status = do_list(mask, attribute, do_deltree_list, false, true); + if (!NT_STATUS_IS_OK(status)) { + goto err; + } + deltree_list_norecurse = deltree_list_head; + deltree_list_head = NULL; + + for (deltree_list_iter = deltree_list_norecurse; + deltree_list_iter != NULL; + deltree_list_iter = deltree_list_iter->next) { + + if (deltree_list_iter->isdir == false) { + /* Just a regular file. */ + if (CLI_DIRSEP_CHAR == '/') { + /* POSIX. */ + status = cli_posix_unlink(cli, + deltree_list_iter->file_path); + } else { + status = cli_unlink(cli, + deltree_list_iter->file_path, + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN); + } + if (!NT_STATUS_IS_OK(status)) { + goto err; + } + continue; + } + + /* + * Get the list of files or directories to + * delete in depth order. + */ + status = do_list(deltree_list_iter->file_path, + attribute, + do_deltree_list, + true, + true); + if (!NT_STATUS_IS_OK(status)) { + goto err; + } + status = delete_remote_files_list(cli, deltree_list_head); + free_file_list(deltree_list_head); + deltree_list_head = NULL; + if (!NT_STATUS_IS_OK(status)) { + goto err; + } + } + + free_file_list(deltree_list_norecurse); + free_file_list(deltree_list_head); + return 0; + + err: + + free_file_list(deltree_list_norecurse); + free_file_list(deltree_list_head); + deltree_list_head = NULL; + return 1; +} + + /**************************************************************************** Wildcard delete some files. ****************************************************************************/ @@ -5005,6 +5182,7 @@ static struct { {"chown",cmd_chown," chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_NONE}}, {"close",cmd_close," close a file given a fid",{COMPL_REMOTE,COMPL_NONE}}, {"del",cmd_del," delete all matching files",{COMPL_REMOTE,COMPL_NONE}}, + {"deltree",cmd_deltree," recursively delete all matching files and directories",{COMPL_REMOTE,COMPL_NONE}}, {"dir",cmd_dir," list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}}, {"du",cmd_du," computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}}, {"echo",cmd_echo,"ping the server",{COMPL_NONE,COMPL_NONE}},