source: branches/samba-3.2.x/source/libsmb/libsmb_dir.c@ 612

Last change on this file since 612 was 233, checked in by Herwig Bauernfeind, 17 years ago

Update 3.2 branch to 3.2.9

File size: 50.6 KB
RevLine 
[232]1/*
2 Unix SMB/Netbios implementation.
3 SMB client library implementation
4 Copyright (C) Andrew Tridgell 1998
5 Copyright (C) Richard Sharpe 2000, 2002
6 Copyright (C) John Terpstra 2000
7 Copyright (C) Tom Jansen (Ninja ISD) 2002
8 Copyright (C) Derrell Lipman 2003-2008
9 Copyright (C) Jeremy Allison 2007, 2008
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "includes.h"
26#include "libsmbclient.h"
27#include "libsmb_internal.h"
28
29
30/*
31 * Routine to open a directory
32 * We accept the URL syntax explained in SMBC_parse_path(), above.
33 */
34
35static void
36remove_dir(SMBCFILE *dir)
37{
38 struct smbc_dir_list *d,*f;
39
40 d = dir->dir_list;
41 while (d) {
42
43 f = d; d = d->next;
44
45 SAFE_FREE(f->dirent);
46 SAFE_FREE(f);
47
48 }
49
50 dir->dir_list = dir->dir_end = dir->dir_next = NULL;
51
52}
53
54static int
55add_dirent(SMBCFILE *dir,
56 const char *name,
57 const char *comment,
58 uint32 type)
59{
60 struct smbc_dirent *dirent;
61 int size;
62 int name_length = (name == NULL ? 0 : strlen(name));
63 int comment_len = (comment == NULL ? 0 : strlen(comment));
64
65 /*
66 * Allocate space for the dirent, which must be increased by the
67 * size of the name and the comment and 1 each for the null terminator.
68 */
69
70 size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
71
72 dirent = (struct smbc_dirent *)SMB_MALLOC(size);
73
74 if (!dirent) {
75
76 dir->dir_error = ENOMEM;
77 return -1;
78
79 }
80
81 ZERO_STRUCTP(dirent);
82
83 if (dir->dir_list == NULL) {
84
85 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
86 if (!dir->dir_list) {
87
88 SAFE_FREE(dirent);
89 dir->dir_error = ENOMEM;
90 return -1;
91
92 }
93 ZERO_STRUCTP(dir->dir_list);
94
95 dir->dir_end = dir->dir_next = dir->dir_list;
96 }
97 else {
98
99 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
100
101 if (!dir->dir_end->next) {
102
103 SAFE_FREE(dirent);
104 dir->dir_error = ENOMEM;
105 return -1;
106
107 }
108 ZERO_STRUCTP(dir->dir_end->next);
109
110 dir->dir_end = dir->dir_end->next;
111 }
112
113 dir->dir_end->next = NULL;
114 dir->dir_end->dirent = dirent;
115
116 dirent->smbc_type = type;
117 dirent->namelen = name_length;
118 dirent->commentlen = comment_len;
119 dirent->dirlen = size;
120
121 /*
122 * dirent->namelen + 1 includes the null (no null termination needed)
123 * Ditto for dirent->commentlen.
124 * The space for the two null bytes was allocated.
125 */
126 strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
127 dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
128 strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
129
130 return 0;
131
132}
133
134static void
135list_unique_wg_fn(const char *name,
136 uint32 type,
137 const char *comment,
138 void *state)
139{
140 SMBCFILE *dir = (SMBCFILE *)state;
141 struct smbc_dir_list *dir_list;
142 struct smbc_dirent *dirent;
143 int dirent_type;
144 int do_remove = 0;
145
146 dirent_type = dir->dir_type;
147
148 if (add_dirent(dir, name, comment, dirent_type) < 0) {
149
150 /* An error occurred, what do we do? */
151 /* FIXME: Add some code here */
152 }
153
154 /* Point to the one just added */
155 dirent = dir->dir_end->dirent;
156
157 /* See if this was a duplicate */
158 for (dir_list = dir->dir_list;
159 dir_list != dir->dir_end;
160 dir_list = dir_list->next) {
161 if (! do_remove &&
162 strcmp(dir_list->dirent->name, dirent->name) == 0) {
163 /* Duplicate. End end of list need to be removed. */
164 do_remove = 1;
165 }
166
167 if (do_remove && dir_list->next == dir->dir_end) {
168 /* Found the end of the list. Remove it. */
169 dir->dir_end = dir_list;
170 free(dir_list->next);
171 free(dirent);
172 dir_list->next = NULL;
173 break;
174 }
175 }
176}
177
178static void
179list_fn(const char *name,
180 uint32 type,
181 const char *comment,
182 void *state)
183{
184 SMBCFILE *dir = (SMBCFILE *)state;
185 int dirent_type;
186
187 /*
188 * We need to process the type a little ...
189 *
190 * Disk share = 0x00000000
191 * Print share = 0x00000001
192 * Comms share = 0x00000002 (obsolete?)
193 * IPC$ share = 0x00000003
194 *
195 * administrative shares:
196 * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000
197 */
198
199 if (dir->dir_type == SMBC_FILE_SHARE) {
200 switch (type) {
201 case 0 | 0x80000000:
202 case 0:
203 dirent_type = SMBC_FILE_SHARE;
204 break;
205
206 case 1:
207 dirent_type = SMBC_PRINTER_SHARE;
208 break;
209
210 case 2:
211 dirent_type = SMBC_COMMS_SHARE;
212 break;
213
214 case 3 | 0x80000000:
215 case 3:
216 dirent_type = SMBC_IPC_SHARE;
217 break;
218
219 default:
220 dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
221 break;
222 }
223 }
224 else {
225 dirent_type = dir->dir_type;
226 }
227
228 if (add_dirent(dir, name, comment, dirent_type) < 0) {
229
230 /* An error occurred, what do we do? */
231 /* FIXME: Add some code here */
232
233 }
234}
235
236static void
237dir_list_fn(const char *mnt,
238 file_info *finfo,
239 const char *mask,
240 void *state)
241{
242
243 if (add_dirent((SMBCFILE *)state, finfo->name, "",
244 (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
245
246 /* Handle an error ... */
247
248 /* FIXME: Add some code ... */
249
250 }
251
252}
253
254static int
255net_share_enum_rpc(struct cli_state *cli,
256 void (*fn)(const char *name,
257 uint32 type,
258 const char *comment,
259 void *state),
260 void *state)
261{
262 int i;
263 WERROR result;
264 uint32 preferred_len = 0xffffffff;
265 uint32 type;
266 struct srvsvc_NetShareInfoCtr info_ctr;
267 struct srvsvc_NetShareCtr1 ctr1;
268 fstring name = "";
269 fstring comment = "";
270 struct rpc_pipe_client *pipe_hnd;
271 NTSTATUS nt_status;
272 uint32_t resume_handle = 0;
273 uint32_t total_entries = 0;
274
275 /* Open the server service pipe */
276 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status);
277 if (!pipe_hnd) {
278 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
279 return -1;
280 }
281
282 ZERO_STRUCT(info_ctr);
283 ZERO_STRUCT(ctr1);
284
285 info_ctr.level = 1;
286 info_ctr.ctr.ctr1 = &ctr1;
287
288 /* Issue the NetShareEnum RPC call and retrieve the response */
289 nt_status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, talloc_tos(),
290 pipe_hnd->cli->desthost,
291 &info_ctr,
292 preferred_len,
293 &total_entries,
294 &resume_handle,
295 &result);
296
297 /* Was it successful? */
298 if (!NT_STATUS_IS_OK(nt_status) || !W_ERROR_IS_OK(result) ||
299 total_entries == 0) {
300 /* Nope. Go clean up. */
301 goto done;
302 }
303
304 /* For each returned entry... */
305 for (i = 0; i < total_entries; i++) {
306
307 /* pull out the share name */
308 fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
309
310 /* pull out the share's comment */
311 fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
312
313 /* Get the type value */
314 type = info_ctr.ctr.ctr1->array[i].type;
315
316 /* Add this share to the list */
317 (*fn)(name, type, comment, state);
318 }
319
320done:
321 /* Close the server service pipe */
322 cli_rpc_pipe_close(pipe_hnd);
323
324 /* Tell 'em if it worked */
325 return W_ERROR_IS_OK(result) ? 0 : -1;
326}
327
328
329/*
330 * Verify that the options specified in a URL are valid
331 */
332int
333SMBC_check_options(char *server,
334 char *share,
335 char *path,
336 char *options)
337{
338 DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
339 "path='%s' options='%s'\n",
340 server, share, path, options));
341
342 /* No options at all is always ok */
343 if (! *options) return 0;
344
345 /* Currently, we don't support any options. */
346 return -1;
347}
348
349
350SMBCFILE *
351SMBC_opendir_ctx(SMBCCTX *context,
352 const char *fname)
353{
354 int saved_errno;
355 char *server = NULL;
356 char *share = NULL;
357 char *user = NULL;
358 char *password = NULL;
359 char *options = NULL;
360 char *workgroup = NULL;
361 char *path = NULL;
362 uint16 mode;
363 char *p = NULL;
364 SMBCSRV *srv = NULL;
365 SMBCFILE *dir = NULL;
366 struct sockaddr_storage rem_ss;
367 TALLOC_CTX *frame = talloc_stackframe();
368
369 if (!context || !context->internal->initialized) {
370 DEBUG(4, ("no valid context\n"));
371 errno = EINVAL + 8192;
372 TALLOC_FREE(frame);
373 return NULL;
374
375 }
376
377 if (!fname) {
378 DEBUG(4, ("no valid fname\n"));