Line data Source code
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 :
25 : struct delete_state {
26 : struct smbcli_tree *tree;
27 : int total_deleted;
28 : bool failed;
29 : };
30 :
31 : /*
32 : callback function for torture_deltree()
33 : */
34 21184 : static void delete_fn(struct clilist_file_info *finfo, const char *name, void *state)
35 : {
36 21184 : struct delete_state *dstate = (struct delete_state *)state;
37 101 : char *s, *n;
38 21184 : if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
39 14478 : return;
40 : }
41 :
42 6706 : n = strdup(name);
43 6706 : n[strlen(n)-1] = 0;
44 6706 : if (asprintf(&s, "%s%s", n, finfo->name) < 0) {
45 0 : free(n);
46 0 : return;
47 : }
48 :
49 6706 : if (finfo->attrib & FILE_ATTRIBUTE_READONLY) {
50 10 : if (NT_STATUS_IS_ERR(smbcli_setatr(dstate->tree, s, 0, 0))) {
51 0 : DEBUG(2,("Failed to remove READONLY on %s - %s\n",
52 : s, smbcli_errstr(dstate->tree)));
53 : }
54 : }
55 :
56 6706 : if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY) {
57 6 : char *s2;
58 6254 : if (asprintf(&s2, "%s\\*", s) < 0) {
59 0 : free(s);
60 0 : free(n);
61 0 : return;
62 : }
63 6254 : smbcli_unlink(dstate->tree, s2);
64 6254 : smbcli_list(dstate->tree, s2,
65 : FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
66 : delete_fn, state);
67 6254 : free(s2);
68 6254 : if (NT_STATUS_IS_ERR(smbcli_rmdir(dstate->tree, s))) {
69 0 : DEBUG(2,("Failed to delete %s - %s\n",
70 : s, smbcli_errstr(dstate->tree)));
71 0 : dstate->failed = true;
72 : }
73 6254 : dstate->total_deleted++;
74 : } else {
75 452 : if (NT_STATUS_IS_ERR(smbcli_unlink(dstate->tree, s))) {
76 12 : DEBUG(2,("Failed to delete %s - %s\n",
77 : s, smbcli_errstr(dstate->tree)));
78 12 : dstate->failed = true;
79 : }
80 452 : dstate->total_deleted++;
81 : }
82 6706 : free(s);
83 6706 : free(n);
84 : }
85 :
86 : /*
87 : recursively descend a tree deleting all files
88 : returns the number of files deleted, or -1 on error
89 : */
90 2290 : int smbcli_deltree(struct smbcli_tree *tree, const char *dname)
91 : {
92 116 : char *mask;
93 116 : struct delete_state dstate;
94 116 : NTSTATUS status;
95 :
96 2290 : dstate.tree = tree;
97 2290 : dstate.total_deleted = 0;
98 2290 : dstate.failed = false;
99 :
100 : /* it might be a file */
101 2290 : status = smbcli_unlink(tree, dname);
102 2290 : if (NT_STATUS_IS_OK(status)) {
103 3 : return 1;
104 : }
105 2287 : if (NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
106 990 : NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
107 990 : NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_NO_SUCH_FILE) ||
108 990 : NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_DOS(ERRDOS, ERRbadfile))) {
109 1297 : return 0;
110 : }
111 990 : if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
112 : /* it could be read-only */
113 0 : smbcli_setatr(tree, dname, FILE_ATTRIBUTE_NORMAL, 0);
114 0 : if (NT_STATUS_IS_OK(smbcli_unlink(tree, dname))) {
115 0 : return 1;
116 : }
117 : }
118 :
119 990 : if (asprintf(&mask, "%s\\*", dname) < 0) {
120 0 : return -1;
121 : }
122 990 : smbcli_unlink_wcard(dstate.tree, mask);
123 990 : smbcli_list(dstate.tree, mask,
124 : FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
125 : delete_fn, &dstate);
126 990 : free(mask);
127 :
128 990 : status = smbcli_rmdir(dstate.tree, dname);
129 990 : if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
130 : /* it could be read-only */
131 0 : smbcli_setatr(dstate.tree, dname, FILE_ATTRIBUTE_NORMAL, 0);
132 0 : status = smbcli_rmdir(dstate.tree, dname);
133 : }
134 990 : if (NT_STATUS_IS_ERR(status)) {
135 16 : DEBUG(2,("Failed to delete %s - %s\n",
136 : dname, smbcli_errstr(dstate.tree)));
137 16 : return -1;
138 : }
139 974 : dstate.total_deleted++;
140 :
141 974 : if (dstate.failed) {
142 0 : return -1;
143 : }
144 :
145 936 : return dstate.total_deleted;
146 : }
|