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