support NetServerEnum in smbwrapper. You can now do a ls in /smb/ and
[samba.git] / source3 / 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    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "wrapper.h"
24
25 extern pstring smb_cwd;
26
27 static struct smbw_dir *smbw_dirs;
28
29 extern struct bitmap *smbw_file_bmap;
30 extern int DEBUGLEVEL;
31
32 extern int smbw_busy;
33
34 /***************************************************** 
35 map a fd to a smbw_dir structure
36 *******************************************************/
37 struct smbw_dir *smbw_dir(int fd)
38 {
39         struct smbw_dir *dir;
40
41         for (dir=smbw_dirs;dir;dir=dir->next) {
42                 if (dir->fd == fd) return dir;
43         }
44         return NULL;
45 }
46
47 /***************************************************** 
48 check if a DIR* is one of ours
49 *******************************************************/
50 int smbw_dirp(DIR *dirp)
51 {
52         struct smbw_dir *d = (struct smbw_dir *)dirp;
53         struct smbw_dir *dir;
54
55         for (dir=smbw_dirs;dir;dir=dir->next) {
56                 if (dir == d) return 1;
57         }
58         return 0;
59 }
60
61 /***************************************************** 
62 free a smbw_dir structure and all entries
63 *******************************************************/
64 static void free_dir(struct smbw_dir *dir)
65 {
66         if (dir->list) {
67                 free(dir->list);
68         }
69         if (dir->path) free(dir->path);
70         ZERO_STRUCTP(dir);
71         free(dir);
72 }
73
74
75 static struct smbw_dir *cur_dir;
76
77 /***************************************************** 
78 add a entry to a directory listing
79 *******************************************************/
80 static void smbw_dir_add(struct file_info *finfo)
81 {
82         DEBUG(5,("%s\n", finfo->name));
83
84         if (cur_dir->malloced == cur_dir->count) {
85                 cur_dir->list = (struct file_info *)Realloc(cur_dir->list, 
86                                                             sizeof(cur_dir->list[0])*
87                                                             (cur_dir->count+100));
88                 if (!cur_dir->list) {
89                         /* oops */
90                         return;
91                 }
92                 cur_dir->malloced += 100;
93         }
94
95         cur_dir->list[cur_dir->count] = *finfo;
96         cur_dir->count++;
97 }
98
99 /***************************************************** 
100 add a entry to a directory listing
101 *******************************************************/
102 static void smbw_share_add(const char *share, uint32 type, const char *comment)
103 {
104         struct file_info finfo;
105
106         ZERO_STRUCT(finfo);
107
108         pstrcpy(finfo.name, share);
109         finfo.mode = aRONLY | aDIR;     
110
111         smbw_dir_add(&finfo);
112 }
113
114
115 /***************************************************** 
116 add a server to a directory listing
117 *******************************************************/
118 static void smbw_server_add(const char *name, uint32 type, 
119                             const char *comment)
120 {
121         struct file_info finfo;
122
123         ZERO_STRUCT(finfo);
124
125         pstrcpy(finfo.name, name);
126         finfo.mode = aRONLY | aDIR;     
127
128         smbw_dir_add(&finfo);
129 }
130
131
132 /***************************************************** 
133 add a entry to a directory listing
134 *******************************************************/
135 static void smbw_printjob_add(struct print_job_info *job)
136 {
137         struct file_info finfo;
138
139         ZERO_STRUCT(finfo);
140
141         pstrcpy(finfo.name, job->name);
142         finfo.mode = aRONLY | aDIR;     
143         finfo.mtime = job->t;
144         finfo.atime = job->t;
145         finfo.ctime = job->t;
146         finfo.uid = nametouid(job->user);
147         finfo.mode = aRONLY;
148         finfo.size = job->size;
149
150         smbw_dir_add(&finfo);
151 }
152
153
154 /***************************************************** 
155 open a directory on the server
156 *******************************************************/
157 int smbw_dir_open(const char *fname)
158 {
159         fstring server, share;
160         pstring path;
161         struct smbw_server *srv=NULL;
162         struct smbw_dir *dir=NULL;
163         pstring mask;
164         int fd;
165         char *s, *p;
166
167         DEBUG(4,("%s\n", __FUNCTION__));
168
169         if (!fname) {
170                 errno = EINVAL;
171                 return -1;
172         }
173
174         smbw_init();
175
176         /* work out what server they are after */
177         s = smbw_parse_path(fname, server, share, path);
178
179         DEBUG(4,("dir_open share=%s\n", share));
180
181         /* get a connection to the server */
182         srv = smbw_server(server, share);
183         if (!srv) {
184                 /* smbw_server sets errno */
185                 goto failed;
186         }
187
188         dir = (struct smbw_dir *)malloc(sizeof(*dir));
189         if (!dir) {
190                 errno = ENOMEM;
191                 goto failed;
192         }
193
194         ZERO_STRUCTP(dir);
195
196         cur_dir = dir;
197
198         slprintf(mask, sizeof(mask)-1, "%s\\*", path);
199         string_sub(mask,"\\\\","\\");
200
201         if ((p=strstr(srv->server_name,"#1D"))) {
202                 DEBUG(4,("doing NetServerEnum\n"));
203                 *p = 0;
204                 cli_NetServerEnum(&srv->cli, srv->server_name, SV_TYPE_ALL,
205                                   smbw_server_add);
206                 *p = '#';
207         } else if (strcmp(srv->cli.dev,"IPC") == 0) {
208                 DEBUG(4,("doing NetShareEnum\n"));
209                 if (cli_RNetShareEnum(&srv->cli, smbw_share_add) < 0) {
210                         errno = smbw_errno(&srv->cli);
211                         goto failed;
212                 }
213         } else if (strncmp(srv->cli.dev,"LPT",3) == 0) {
214                 if (cli_print_queue(&srv->cli, smbw_printjob_add) < 0) {
215                         errno = smbw_errno(&srv->cli);
216                         goto failed;
217                 }
218         } else {
219                 if (cli_list(&srv->cli, mask, aHIDDEN|aSYSTEM|aDIR, 
220                              smbw_dir_add) < 0) {
221                         errno = smbw_errno(&srv->cli);
222                         goto failed;
223                 }
224         }
225
226         cur_dir = NULL;
227         
228         fd = open(SMBW_DUMMY, O_WRONLY);
229         if (fd == -1) {
230                 errno = EMFILE;
231                 goto failed;
232         }
233
234         if (bitmap_query(smbw_file_bmap, fd)) {
235                 DEBUG(0,("ERROR: fd used in smbw_dir_open\n"));
236                 errno = EIO;
237                 goto failed;
238         }
239
240         DLIST_ADD(smbw_dirs, dir);
241         
242         bitmap_set(smbw_file_bmap, fd);
243
244         dir->fd = fd;
245         dir->srv = srv;
246         dir->path = strdup(s);
247
248         DEBUG(4,("  -> %d\n", dir->count));
249
250         return dir->fd;
251
252  failed:
253         if (dir) {
254                 free_dir(dir);
255         }
256
257         return -1;
258 }
259
260 /***************************************************** 
261 a wrapper for fstat() on a directory
262 *******************************************************/
263 int smbw_dir_fstat(int fd, struct stat *st)
264 {
265         struct smbw_dir *dir;
266
267         DEBUG(4,("%s\n", __FUNCTION__));
268
269         dir = smbw_dir(fd);
270         if (!dir) {
271                 errno = EBADF;
272                 return -1;
273         }
274
275         ZERO_STRUCTP(st);
276
277         smbw_setup_stat(st, "", dir->count*sizeof(struct dirent), aDIR);
278
279         st->st_dev = dir->srv->dev;
280
281         return 0;
282 }
283
284 /***************************************************** 
285 close a directory handle
286 *******************************************************/
287 int smbw_dir_close(int fd)
288 {
289         struct smbw_dir *dir;
290
291         DEBUG(4,("%s\n", __FUNCTION__));
292
293         dir = smbw_dir(fd);
294         if (!dir) {
295                 DEBUG(4,("%s(%d)\n", __FUNCTION__, __LINE__));
296                 errno = EBADF;
297                 return -1;
298         }
299
300         bitmap_clear(smbw_file_bmap, dir->fd);
301         close(dir->fd);
302         
303         DLIST_REMOVE(smbw_dirs, dir);
304
305         free_dir(dir);
306
307         return 0;
308 }
309
310
311 /***************************************************** 
312 a wrapper for getdents()
313 *******************************************************/
314 int smbw_getdents(unsigned int fd, struct dirent *dirp, int count)
315 {
316         struct smbw_dir *dir;
317         int n=0;
318
319         DEBUG(4,("%s\n", __FUNCTION__));
320
321         smbw_busy++;
322
323         dir = smbw_dir(fd);
324         if (!dir) {
325                 errno = EBADF;
326                 smbw_busy--;
327                 return -1;
328         }
329         
330         while (count>=sizeof(*dirp) && (dir->offset < dir->count)) {
331                 dirp->d_off = (dir->offset+1)*sizeof(*dirp);
332                 dirp->d_reclen = sizeof(*dirp);
333                 safe_strcpy(&dirp->d_name[0], dir->list[dir->offset].name, 
334                             sizeof(dirp->d_name)-1);
335                 dirp->d_ino = smbw_inode(dir->list[dir->offset].name);
336                 dir->offset++;
337                 count -= dirp->d_reclen;
338                 if (dir->offset == dir->count) {
339                         dirp->d_off = -1;
340                 }
341                 dirp++;
342                 n++;
343         }
344
345         smbw_busy--;
346         return n*sizeof(*dirp);
347 }
348
349
350 /***************************************************** 
351 a wrapper for chdir()
352 *******************************************************/
353 int smbw_chdir(const char *name)
354 {
355         struct smbw_server *srv;
356         fstring server, share;
357         pstring path;
358         uint32 mode = aDIR;
359         char *cwd;
360
361         smbw_init();
362
363         if (smbw_busy) return real_chdir(cwd);
364
365         smbw_busy++;
366
367         if (!name) {
368                 errno = EINVAL;
369                 goto failed;
370         }
371
372         DEBUG(4,("%s (%s)\n", __FUNCTION__, name));
373
374         /* work out what server they are after */
375         cwd = smbw_parse_path(name, server, share, path);
376
377         if (strncmp(cwd,SMBW_PREFIX,strlen(SMBW_PREFIX))) {
378                 if (real_chdir(cwd) == 0) {
379                         DEBUG(4,("set SMBW_CWD to %s\n", cwd));
380                         pstrcpy(smb_cwd, cwd);
381                         if (setenv(SMBW_PWD_ENV, smb_cwd, 1)) {
382                                 DEBUG(4,("setenv failed\n"));
383                         }
384                         goto success;
385                 }
386                 errno = ENOENT;
387                 goto failed;
388         }
389
390         /* get a connection to the server */
391         srv = smbw_server(server, share);
392         if (!srv) {
393                 /* smbw_server sets errno */
394                 goto failed;
395         }
396
397         if (strncmp(srv->cli.dev,"IPC",3) &&
398             strncmp(srv->cli.dev,"LPT",3) &&
399             !smbw_getatr(srv, path, 
400                          &mode, NULL, NULL, NULL, NULL)) {
401                 errno = smbw_errno(&srv->cli);
402                 goto failed;
403         }
404
405         if (!(mode & aDIR)) {
406                 errno = ENOTDIR;
407                 goto failed;
408         }
409
410         DEBUG(4,("set SMBW_CWD2 to %s\n", cwd));
411         pstrcpy(smb_cwd, cwd);
412         if (setenv(SMBW_PWD_ENV, smb_cwd, 1)) {
413                 DEBUG(4,("setenv failed\n"));
414         }
415
416         /* we don't want the old directory to be busy */
417         real_chdir("/");
418
419  success:
420         smbw_busy--;
421         return 0;
422
423  failed:
424         smbw_busy--;
425         return -1;
426 }
427
428
429 /***************************************************** 
430 a wrapper for lseek() on directories
431 *******************************************************/
432 off_t smbw_dir_lseek(int fd, off_t offset, int whence)
433 {
434         struct smbw_dir *dir;
435         off_t ret;
436
437         DEBUG(4,("%s offset=%d whence=%d\n", __FUNCTION__, 
438                  (int)offset, whence));
439
440         dir = smbw_dir(fd);
441         if (!dir) {
442                 errno = EBADF;
443                 return -1;
444         }
445
446         switch (whence) {
447         case SEEK_SET:
448                 dir->offset = offset/sizeof(struct dirent);
449                 break;
450         case SEEK_CUR:
451                 dir->offset += offset/sizeof(struct dirent);
452                 break;
453         case SEEK_END:
454                 dir->offset = (dir->count * sizeof(struct dirent)) + offset;
455                 dir->offset /= sizeof(struct dirent);
456                 break;
457         }
458
459         ret = dir->offset * sizeof(struct dirent);
460
461         DEBUG(4,("   -> %d\n", (int)ret));
462
463         return ret;
464 }
465
466
467 /***************************************************** 
468 a wrapper for mkdir()
469 *******************************************************/
470 int smbw_mkdir(const char *fname, mode_t mode)
471 {
472         struct smbw_server *srv;
473         fstring server, share;
474         pstring path;
475
476         DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
477
478         if (!fname) {
479                 errno = EINVAL;
480                 return -1;
481         }
482
483         smbw_init();
484
485         smbw_busy++;
486
487         /* work out what server they are after */
488         smbw_parse_path(fname, server, share, path);
489
490         /* get a connection to the server */
491         srv = smbw_server(server, share);
492         if (!srv) {
493                 /* smbw_server sets errno */
494                 goto failed;
495         }
496
497         if (!cli_mkdir(&srv->cli, path)) {
498                 errno = smbw_errno(&srv->cli);
499                 goto failed;
500         }
501
502         smbw_busy--;
503         return 0;
504
505  failed:
506         smbw_busy--;
507         return -1;
508 }
509
510 /***************************************************** 
511 a wrapper for rmdir()
512 *******************************************************/
513 int smbw_rmdir(const char *fname)
514 {
515         struct smbw_server *srv;
516         fstring server, share;
517         pstring path;
518
519         DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
520
521         if (!fname) {
522                 errno = EINVAL;
523                 return -1;
524         }
525
526         smbw_init();
527
528         smbw_busy++;
529
530         /* work out what server they are after */
531         smbw_parse_path(fname, server, share, path);
532
533         /* get a connection to the server */
534         srv = smbw_server(server, share);
535         if (!srv) {
536                 /* smbw_server sets errno */
537                 goto failed;
538         }
539
540         if (!cli_rmdir(&srv->cli, path)) {
541                 errno = smbw_errno(&srv->cli);
542                 goto failed;
543         }
544
545         smbw_busy--;
546         return 0;
547
548  failed:
549         smbw_busy--;
550         return -1;
551 }
552
553
554 /***************************************************** 
555 a wrapper for getcwd()
556 *******************************************************/
557 char *smbw_getcwd(char *buf, size_t size)
558 {
559         smbw_init();
560
561         if (smbw_busy) {
562                 return __getcwd(buf, size);
563         }
564
565         smbw_busy++;
566
567         if (!buf) {
568                 if (size <= 0) size = strlen(smb_cwd)+1;
569                 buf = (char *)malloc(size);
570                 if (!buf) {
571                         errno = ENOMEM;
572                         smbw_busy--;
573                         return NULL;
574                 }
575         }
576
577         if (strlen(smb_cwd) > size-1) {
578                 errno = ERANGE;
579                 smbw_busy--;
580                 return NULL;
581         }
582
583         safe_strcpy(buf, smb_cwd, size);
584
585         smbw_busy--;
586         return buf;
587 }
588
589 /***************************************************** 
590 a wrapper for fchdir()
591 *******************************************************/
592 int smbw_fchdir(unsigned int fd)
593 {
594         struct smbw_dir *dir;
595
596         DEBUG(4,("%s\n", __FUNCTION__));
597
598         smbw_busy++;
599
600         dir = smbw_dir(fd);
601         if (!dir) {
602                 errno = EBADF;
603                 smbw_busy--;
604                 return -1;
605         }       
606
607         smbw_busy--;
608         
609         return chdir(dir->path);
610 }
611
612 /***************************************************** 
613 open a directory on the server
614 *******************************************************/
615 DIR *smbw_opendir(const char *fname)
616 {
617         int fd;
618
619         smbw_busy++;
620
621         fd = smbw_dir_open(fname);
622
623         if (fd == -1) {
624                 smbw_busy--;
625                 return NULL;
626         }
627
628         smbw_busy--;
629
630         return (DIR *)smbw_dir(fd);
631 }
632
633 /***************************************************** 
634 read one entry from a directory
635 *******************************************************/
636 struct dirent *smbw_readdir(DIR *dirp)
637 {
638         struct smbw_dir *d = (struct smbw_dir *)dirp;
639         static struct dirent de;
640
641         if (smbw_getdents(d->fd, &de, sizeof(struct dirent)) > 0) 
642                 return &de;
643
644         return NULL;
645 }
646
647 /***************************************************** 
648 close a DIR*
649 *******************************************************/
650 int smbw_closedir(DIR *dirp)
651 {
652         struct smbw_dir *d = (struct smbw_dir *)dirp;
653         return smbw_close(d->fd);
654 }
655
656 /***************************************************** 
657 seek in a directory
658 *******************************************************/
659 void smbw_seekdir(DIR *dirp, off_t offset)
660 {
661         struct smbw_dir *d = (struct smbw_dir *)dirp;
662         smbw_dir_lseek(d->fd,offset, SEEK_SET);
663 }
664
665 /***************************************************** 
666 current loc in a directory
667 *******************************************************/
668 off_t smbw_telldir(DIR *dirp)
669 {
670         struct smbw_dir *d = (struct smbw_dir *)dirp;
671         return smbw_dir_lseek(d->fd,0,SEEK_CUR);
672 }