1/* 2 Unix SMB/CIFS implementation. 3 useful function for deleting a whole directory tree 4 Copyright (C) Andrew Tridgell 2003 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21#include "libcli/raw/libcliraw.h" 22#include "libcli/libcli.h" 23#include "system/dir.h" 24 25struct delete_state { 26 struct smbcli_tree *tree; 27 int total_deleted; 28 bool failed; 29}; 30 31/* 32 callback function for torture_deltree() 33*/ 34static void delete_fn(struct clilist_file_info *finfo, const char *name, void *state) 35{ 36 struct delete_state *dstate = (struct delete_state *)state; 37 char *s, *n; 38 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) { 39 return; 40 } 41 42 n = strdup(name); 43 n[strlen(n)-1] = 0; 44 asprintf(&s, "%s%s", n, finfo->name); 45 46 if (finfo->attrib & FILE_ATTRIBUTE_READONLY) { 47 if (NT_STATUS_IS_ERR(smbcli_setatr(dstate->tree, s, 0, 0))) { 48 DEBUG(2,("Failed to remove READONLY on %s - %s\n", 49 s, smbcli_errstr(dstate->tree))); 50 } 51 } 52 53 if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY) { 54 char *s2; 55 asprintf(&s2, "%s\\*", s); 56 smbcli_unlink(dstate->tree, s2); 57 smbcli_list(dstate->tree, s2, 58 FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, 59 delete_fn, state); 60 free(s2); 61 if (NT_STATUS_IS_ERR(smbcli_rmdir(dstate->tree, s))) { 62 DEBUG(2,("Failed to delete %s - %s\n", 63 s, smbcli_errstr(dstate->tree))); 64 dstate->failed = true; 65 } 66 dstate->total_deleted++; 67 } else { 68 if (NT_STATUS_IS_ERR(smbcli_unlink(dstate->tree, s))) { 69 DEBUG(2,("Failed to delete %s - %s\n", 70 s, smbcli_errstr(dstate->tree))); 71 dstate->failed = true; 72 } 73 dstate->total_deleted++; 74 } 75 free(s); 76 free(n); 77} 78 79/* 80 recursively descend a tree deleting all files 81 returns the number of files deleted, or -1 on error 82*/ 83int smbcli_deltree(struct smbcli_tree *tree, const char *dname) 84{ 85 char *mask; 86 struct delete_state dstate; 87 NTSTATUS status; 88 89 dstate.tree = tree; 90 dstate.total_deleted = 0; 91 dstate.failed = false; 92 93 /* it might be a file */ 94 status = smbcli_unlink(tree, dname); 95 if (NT_STATUS_IS_OK(smbcli_unlink(tree, dname))) { 96 return 1; 97 } 98 if (NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_NAME_NOT_FOUND) || 99 NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_PATH_NOT_FOUND) || 100 NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_NO_SUCH_FILE) || 101 NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_DOS(ERRDOS, ERRbadfile))) { 102 return 0; 103 } 104 if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) { 105 /* it could be read-only */ 106 status = smbcli_setatr(tree, dname, FILE_ATTRIBUTE_NORMAL, 0); 107 if (NT_STATUS_IS_OK(smbcli_unlink(tree, dname))) { 108 return 1; 109 } 110 } 111 112 asprintf(&mask, "%s\\*", dname); 113 smbcli_unlink(dstate.tree, mask); 114 smbcli_list(dstate.tree, mask, 115 FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, 116 delete_fn, &dstate); 117 free(mask); 118 119 status = smbcli_rmdir(dstate.tree, dname); 120 if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) { 121 /* it could be read-only */ 122 status = smbcli_setatr(dstate.tree, dname, FILE_ATTRIBUTE_NORMAL, 0); 123 status = smbcli_rmdir(dstate.tree, dname); 124 } 125 if (NT_STATUS_IS_ERR(status)) { 126 DEBUG(2,("Failed to delete %s - %s\n", 127 dname, smbcli_errstr(dstate.tree))); 128 return -1; 129 } 130 dstate.total_deleted++; 131 132 if (dstate.failed) { 133 return -1; 134 } 135 136 return dstate.total_deleted; 137} 138