r2654: fixed some more server memory leaks. We are now down to a single leak
[sfrench/samba-autobuild/.git] / source4 / libcli / clideltree.c
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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 struct delete_state {
24         struct smbcli_tree *tree;
25         int total_deleted;
26         BOOL failed;
27 };
28
29 /* 
30    callback function for torture_deltree() 
31 */
32 static void delete_fn(file_info *finfo, const char *name, void *state)
33 {
34         struct delete_state *dstate = state;
35         char *s, *n;
36         if (strcmp(finfo->name, ".") == 0 ||
37             strcmp(finfo->name, "..") == 0) return;
38
39         n = strdup(name);
40         n[strlen(n)-1] = 0;
41         asprintf(&s, "%s%s", n, finfo->name);
42
43         if (finfo->mode & FILE_ATTRIBUTE_READONLY) {
44                 if (NT_STATUS_IS_ERR(smbcli_setatr(dstate->tree, s, 0, 0))) {
45                         DEBUG(2,("Failed to remove READONLY on %s - %s\n",
46                                  s, smbcli_errstr(dstate->tree)));                      
47                 }
48         }
49
50         if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
51                 char *s2;
52                 asprintf(&s2, "%s\\*", s);
53                 smbcli_unlink(dstate->tree, s2);
54                 smbcli_list(dstate->tree, s2, 
55                          FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, 
56                          delete_fn, state);
57                 free(s2);
58                 if (NT_STATUS_IS_ERR(smbcli_rmdir(dstate->tree, s))) {
59                         DEBUG(2,("Failed to delete %s - %s\n", 
60                                  s, smbcli_errstr(dstate->tree)));
61                         dstate->failed = True;
62                 }
63                 dstate->total_deleted++;
64         } else {
65                 if (NT_STATUS_IS_ERR(smbcli_unlink(dstate->tree, s))) {
66                         DEBUG(2,("Failed to delete %s - %s\n", 
67                                  s, smbcli_errstr(dstate->tree)));
68                         dstate->failed = True;
69                 }
70                 dstate->total_deleted++;
71         }
72         free(s);
73         free(n);
74 }
75
76 /* 
77    recursively descend a tree deleting all files
78    returns the number of files deleted, or -1 on error
79 */
80 int smbcli_deltree(struct smbcli_tree *tree, const char *dname)
81 {
82         char *mask;
83         struct delete_state dstate;
84
85         dstate.tree = tree;
86         dstate.total_deleted = 0;
87         dstate.failed = False;
88
89         /* it might be a file */
90         if (NT_STATUS_IS_OK(smbcli_unlink(tree, dname))) {
91                 return 1;
92         }
93         if (NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
94             NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
95             NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_NO_SUCH_FILE)) {
96                 return 0;
97         }
98
99         asprintf(&mask, "%s\\*", dname);
100         smbcli_unlink(dstate.tree, mask);
101         smbcli_list(dstate.tree, mask, 
102                  FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, 
103                  delete_fn, &dstate);
104         free(mask);
105         if (NT_STATUS_IS_ERR(smbcli_rmdir(dstate.tree, dname))) {
106                 DEBUG(2,("Failed to delete %s - %s\n", 
107                          dname, smbcli_errstr(dstate.tree)));
108                 return -1;
109         }
110         dstate.total_deleted++;
111
112         if (dstate.failed) {
113                 return -1;
114         }
115
116         return dstate.total_deleted;
117 }