r23779: Change from v2 or later to v3 or later.
[kai/samba-autobuild/.git] / examples / libsmbclient / smbwrapper / smbw_dir.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.0
4    SMB wrapper directory functions
5    Copyright (C) Andrew Tridgell 1998
6    Copyright (C) Derrell Lipman 2003-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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "smbw.h"
24 #include "bsd-strlfunc.h"
25
26 /***************************************************** 
27 determine if a directory handle is a smb one
28 *******************************************************/
29 int smbw_dirp(DIR * dirp)
30 {
31         return ((char *) dirp >= (char *) smbw_fd_map &&
32                 (char *) dirp < (char *) &smbw_fd_map[__FD_SETSIZE] &&
33                 *(int *) dirp != -1);
34 }
35
36
37 /***************************************************** 
38 a wrapper for getdents()
39 *******************************************************/
40 int smbw_getdents(unsigned int fd_smbw,
41                   struct SMBW_dirent *dirent_external,
42                   int count)
43 {
44         int remaining;
45         int fd_client = smbw_fd_map[fd_smbw];
46         struct smbc_dirent *dirent_internal;
47
48
49         for (remaining = count;
50              remaining > sizeof(struct SMBW_dirent);
51              dirent_external++) {
52
53                 /*
54                  * We do these one at a time because there's otherwise no way
55                  * to limit how many smbc_getdents() will return for us, and
56                  * if it returns too many, it also doesn't give us offsets to
57                  * be able to seek back to where we need to be.  In practice,
58                  * this one-at-a-time retrieval isn't a problem because the
59                  * time-consuming network transaction is all done at
60                  * smbc_opendir() time.
61                  */
62                 dirent_internal = smbc_readdir(fd_client);
63                 if (dirent_internal == NULL) {
64                         break;
65                 }
66
67                 remaining -= sizeof(struct SMBW_dirent);
68
69                 dirent_external->d_ino = -1; /* not supported */
70                 dirent_external->d_off = smbc_telldir(fd_client);
71                 dirent_external->d_reclen = sizeof(struct SMBW_dirent);
72                 dirent_external->d_type = dirent_internal->smbc_type;
73
74                 smbw_strlcpy(dirent_external->d_name,
75                              dirent_internal->name,
76                              sizeof(dirent_external->d_name) - 1);
77                 smbw_strlcpy(dirent_external->d_comment,
78                              dirent_internal->comment,
79                              sizeof(dirent_external->d_comment) - 1);
80         }
81
82         return(count - remaining);
83 }
84
85
86 /***************************************************** 
87 a wrapper for chdir()
88 *******************************************************/
89 int smbw_chdir(const char *name)
90 {
91         int simulate;
92         struct stat statbuf;
93         char path[PATH_MAX];
94         char *p;
95
96         SMBW_INIT();
97
98         if (!name) {
99                 errno = EINVAL;
100                 return -1;
101         }
102
103         if (! smbw_path((char *) name)) {
104                 if ((* smbw_libc.chdir)(name) == 0) {
105                         *smbw_cwd = '\0';
106                         return 0;
107                 }
108
109                 return -1;
110         }
111
112         smbw_fix_path(name, path);
113
114         /* ensure it exists */
115         p = path + 6;           /* look just past smb:// */
116         simulate = (strchr(p, '/') == NULL);
117
118         /* special case for full-network scan, workgroups, and servers */
119         if (! simulate) {
120             
121             if (smbc_stat(path, &statbuf) < 0) {
122                 return -1;
123             }
124             
125             /* ensure it's a directory */
126             if (! S_ISDIR(statbuf.st_mode)) {
127                 errno = ENOTDIR;
128                 return -1;
129             }
130         }
131
132         smbw_strlcpy(smbw_cwd, path, PATH_MAX);
133
134         /* we don't want the old directory to be busy */
135         (* smbw_libc.chdir)("/");
136
137         return 0;
138 }
139
140
141 /***************************************************** 
142 a wrapper for mkdir()
143 *******************************************************/
144 int smbw_mkdir(const char *fname, mode_t mode)
145 {
146         char path[PATH_MAX];
147
148         if (!fname) {
149                 errno = EINVAL;
150                 return -1;
151         }
152
153         SMBW_INIT();
154
155         smbw_fix_path(fname, path);
156         return smbc_mkdir(path, mode);
157 }
158
159 /***************************************************** 
160 a wrapper for rmdir()
161 *******************************************************/
162 int smbw_rmdir(const char *fname)
163 {
164         char path[PATH_MAX];
165
166         if (!fname) {
167                 errno = EINVAL;
168                 return -1;
169         }
170
171         SMBW_INIT();
172
173         smbw_fix_path(fname, path);
174         return smbc_rmdir(path);
175 }
176
177
178 /***************************************************** 
179 a wrapper for getcwd()
180 *******************************************************/
181 char *smbw_getcwd(char *buf, size_t size)
182 {
183         SMBW_INIT();
184
185         if (*smbw_cwd == '\0') {
186                 return (* smbw_libc.getcwd)(buf, size);
187         }
188
189         if (buf == NULL) {
190                 if (size == 0) {
191                         size = strlen(smbw_cwd) + 1;
192                 }
193                 buf = malloc(size);
194                 if (buf == NULL) {
195                         errno = ENOMEM;
196                         return NULL;
197                 }
198         }
199
200         smbw_strlcpy(buf, smbw_cwd, size);
201         buf[size-1] = '\0';
202         return buf;
203 }
204
205 /***************************************************** 
206 a wrapper for fchdir()
207 *******************************************************/
208 int smbw_fchdir(int fd_smbw)
209 {
210         int ret;
211
212         SMBW_INIT();
213
214         if (! smbw_fd(fd_smbw)) {
215                 ret = (* smbw_libc.fchdir)(fd_smbw);
216                 (void) (* smbw_libc.getcwd)(smbw_cwd, PATH_MAX);
217                 return ret;
218         }
219
220         errno = EACCES;
221         return -1;
222 }
223
224 /***************************************************** 
225 open a directory on the server
226 *******************************************************/
227 DIR *smbw_opendir(const char *fname)
228 {
229         int fd_client;
230         int fd_smbw;
231         char path[PATH_MAX];
232         DIR * dirp;
233
234         SMBW_INIT();
235
236         if (!fname) {
237                 errno = EINVAL;
238                 return NULL;
239         }
240
241         fd_smbw = (smbw_libc.open)(SMBW_DUMMY, O_WRONLY, 0200);
242         if (fd_smbw == -1) {
243                 errno = EMFILE;
244                 return NULL;
245         }
246
247         smbw_fix_path(fname, path);
248         fd_client =  smbc_opendir(path);
249
250         if (fd_client < 0) {
251                 (* smbw_libc.close)(fd_smbw);
252                 return NULL;
253         }
254
255         smbw_fd_map[fd_smbw] = fd_client;
256         smbw_ref(fd_client, SMBW_RCT_Increment);
257         dirp = (DIR *) &smbw_fd_map[fd_smbw];
258         return dirp;
259 }
260
261 /***************************************************** 
262 read one entry from a directory
263 *******************************************************/
264 struct SMBW_dirent *smbw_readdir(DIR *dirp)
265 {
266         int fd_smbw;
267         int fd_client;
268         struct smbc_dirent *dirent_internal;
269         static struct SMBW_dirent dirent_external;
270
271         fd_smbw = (int *) dirp - smbw_fd_map;
272         fd_client = smbw_fd_map[fd_smbw];
273
274         if ((dirent_internal = smbc_readdir(fd_client)) == NULL) {
275                 return NULL;
276         }
277  
278         dirent_external.d_ino = -1; /* not supported */
279         dirent_external.d_off = smbc_telldir(fd_client);
280         dirent_external.d_reclen = sizeof(struct SMBW_dirent);
281         dirent_external.d_type = dirent_internal->smbc_type;
282         smbw_strlcpy(dirent_external.d_name,
283                      dirent_internal->name,
284                      sizeof(dirent_external.d_name) - 1);
285         smbw_strlcpy(dirent_external.d_comment,
286                      dirent_internal->comment,
287                      sizeof(dirent_external.d_comment) - 1);
288
289         return &dirent_external;
290 }
291
292 /***************************************************** 
293 read one entry from a directory in a reentrant fashion
294 ha!  samba is not re-entrant, and neither is the
295 libsmbclient library
296 *******************************************************/
297 int smbw_readdir_r(DIR *dirp,
298                    struct SMBW_dirent *__restrict entry,
299                    struct SMBW_dirent **__restrict result)
300 {
301         SMBW_dirent *dirent;
302
303         dirent = smbw_readdir(dirp);
304
305         if (dirent != NULL) {
306                 *entry = *dirent;
307                 if (result != NULL) {
308                         *result = entry;
309                 }
310                 return 0;
311         }
312
313         if (result != NULL) {
314                 *result = NULL;
315         }
316         return EBADF;
317 }
318
319
320 /***************************************************** 
321 close a DIR*
322 *******************************************************/
323 int smbw_closedir(DIR *dirp)
324 {
325         int fd_smbw = (int *) dirp - smbw_fd_map;
326         int fd_client = smbw_fd_map[fd_smbw];
327
328         (* smbw_libc.close)(fd_smbw);
329         if (smbw_ref(fd_client, SMBW_RCT_Decrement) > 0) {
330                 return 0;
331         }
332         smbw_fd_map[fd_smbw] = -1;
333         return smbc_closedir(fd_client);
334 }
335
336 /***************************************************** 
337 seek in a directory
338 *******************************************************/
339 void smbw_seekdir(DIR *dirp, long long offset)
340 {
341         int fd_smbw = (int *) dirp - smbw_fd_map;
342         int fd_client = smbw_fd_map[fd_smbw];
343
344         smbc_lseekdir(fd_client, offset);
345 }
346
347 /***************************************************** 
348 current loc in a directory
349 *******************************************************/
350 long long smbw_telldir(DIR *dirp)
351 {
352         int fd_smbw = (int *) dirp - smbw_fd_map;
353         int fd_client = smbw_fd_map[fd_smbw];
354
355         return (long long) smbc_telldir(fd_client);
356 }