Merge branch 'v4-0-local' of git://git.id10ts.net/samba into 4-0-local
[kai/samba.git] / source4 / libcli / smb2 / util.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    SMB2 client utility functions
5
6    Copyright (C) Andrew Tridgell 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "libcli/smb2/smb2.h"
26 #include "libcli/smb2/smb2_calls.h"
27 #include "libcli/smb_composite/smb_composite.h"
28
29 /*
30   simple close wrapper with SMB2
31 */
32 NTSTATUS smb2_util_close(struct smb2_tree *tree, struct smb2_handle h)
33 {
34         struct smb2_close c;
35
36         ZERO_STRUCT(c);
37         c.in.file.handle = h;
38
39         return smb2_close(tree, &c);
40 }
41
42 /*
43   unlink a file with SMB2
44 */
45 NTSTATUS smb2_util_unlink(struct smb2_tree *tree, const char *fname)
46 {
47         union smb_unlink io;
48         
49         ZERO_STRUCT(io);
50         io.unlink.in.pattern = fname;
51
52         return smb2_composite_unlink(tree, &io);
53 }
54
55
56 /*
57   rmdir with SMB2
58 */
59 NTSTATUS smb2_util_rmdir(struct smb2_tree *tree, const char *dname)
60 {
61         struct smb_rmdir io;
62         
63         ZERO_STRUCT(io);
64         io.in.path = dname;
65
66         return smb2_composite_rmdir(tree, &io);
67 }
68
69
70 /*
71   mkdir with SMB2
72 */
73 NTSTATUS smb2_util_mkdir(struct smb2_tree *tree, const char *dname)
74 {
75         union smb_mkdir io;
76         
77         ZERO_STRUCT(io);
78         io.mkdir.level = RAW_MKDIR_MKDIR;
79         io.mkdir.in.path = dname;
80
81         return smb2_composite_mkdir(tree, &io);
82 }
83
84
85 /*
86   set file attribute with SMB2
87 */
88 NTSTATUS smb2_util_setatr(struct smb2_tree *tree, const char *name, uint32_t attrib)
89 {
90         union smb_setfileinfo io;
91         
92         ZERO_STRUCT(io);
93         io.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
94         io.basic_info.in.file.path = name;
95         io.basic_info.in.attrib = attrib;
96
97         return smb2_composite_setpathinfo(tree, &io);
98 }
99
100
101
102
103 /* 
104    recursively descend a tree deleting all files
105    returns the number of files deleted, or -1 on error
106 */
107 int smb2_deltree(struct smb2_tree *tree, const char *dname)
108 {
109         NTSTATUS status;
110         uint32_t total_deleted = 0;
111         uint_t count, i;
112         union smb_search_data *list;
113         TALLOC_CTX *tmp_ctx = talloc_new(tree);
114         struct smb2_find f;
115         struct smb2_create create_parm;
116
117         /* it might be a file */
118         status = smb2_util_unlink(tree, dname);
119         if (NT_STATUS_IS_OK(status)) {
120                 talloc_free(tmp_ctx);
121                 return 1;
122         }
123         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
124             NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
125             NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_FILE)) {
126                 talloc_free(tmp_ctx);
127                 return 0;
128         }
129
130         ZERO_STRUCT(create_parm);
131         create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
132         create_parm.in.share_access = 
133                 NTCREATEX_SHARE_ACCESS_READ|
134                 NTCREATEX_SHARE_ACCESS_WRITE;
135         create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
136         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
137         create_parm.in.fname = dname;
138
139         status = smb2_create(tree, tmp_ctx, &create_parm);
140         if (NT_STATUS_IS_ERR(status)) {
141                 DEBUG(2,("Failed to open %s - %s\n", dname, nt_errstr(status)));
142                 talloc_free(tmp_ctx);
143                 return -1;
144         }
145         
146
147         ZERO_STRUCT(f);
148         f.in.file.handle       = create_parm.out.file.handle;
149         f.in.max_response_size = 0x10000;
150         f.in.level             = SMB2_FIND_NAME_INFO;
151         f.in.pattern           = "*";
152
153         status = smb2_find_level(tree, tmp_ctx, &f, &count, &list);
154         if (NT_STATUS_IS_ERR(status)) {
155                 DEBUG(2,("Failed to list %s - %s\n", 
156                          dname, nt_errstr(status)));
157                 smb2_util_close(tree, create_parm.out.file.handle);
158                 talloc_free(tmp_ctx);
159                 return -1;
160         }
161
162         for (i=0;i<count;i++) {
163                 char *name;
164                 if (strcmp(".", list[i].name_info.name.s) == 0 ||
165                     strcmp("..", list[i].name_info.name.s) == 0) {
166                         continue;
167                 }
168                 name = talloc_asprintf(tmp_ctx, "%s\\%s", dname, list[i].name_info.name.s);
169                 status = smb2_util_unlink(tree, name);
170                 if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
171                         /* it could be read-only */
172                         status = smb2_util_setatr(tree, name, FILE_ATTRIBUTE_NORMAL);
173                         status = smb2_util_unlink(tree, name);
174                 }
175
176                 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
177                         int ret;
178                         ret = smb2_deltree(tree, name);
179                         if (ret > 0) total_deleted += ret;
180                 }
181                 talloc_free(name);
182                 if (NT_STATUS_IS_OK(status)) {
183                         total_deleted++;
184                 }
185         }
186
187         smb2_util_close(tree, create_parm.out.file.handle);
188
189         status = smb2_util_rmdir(tree, dname);
190         if (NT_STATUS_IS_ERR(status)) {
191                 DEBUG(2,("Failed to delete %s - %s\n", 
192                          dname, nt_errstr(status)));
193                 talloc_free(tmp_ctx);
194                 return -1;
195         }
196
197         talloc_free(tmp_ctx);
198
199         return total_deleted;
200 }