This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[kai/samba.git] / source3 / smbd / dir.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Directory handling routines
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /*
24    This module implements directory related functions for Samba.
25 */
26
27 typedef struct _dptr_struct {
28         struct _dptr_struct *next, *prev;
29         int dnum;
30         uint16 spid;
31         connection_struct *conn;
32         void *ptr;
33         BOOL expect_close;
34         char *wcard; /* Field only used for trans2_ searches */
35         uint16 attr; /* Field only used for trans2_ searches */
36         char *path;
37 } dptr_struct;
38
39 static struct bitmap *dptr_bmap;
40 static dptr_struct *dirptrs;
41
42 static int dptrs_open = 0;
43
44 #define INVALID_DPTR_KEY (-3)
45
46 /****************************************************************************
47  Initialise the dir bitmap.
48 ****************************************************************************/
49
50 void init_dptrs(void)
51 {
52   static BOOL dptrs_init=False;
53
54   if (dptrs_init)
55     return;
56
57   dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
58
59   if (!dptr_bmap)
60     exit_server("out of memory in init_dptrs");
61
62   dptrs_init = True;
63 }
64
65 /****************************************************************************
66  Idle a dptr - the directory is closed but the control info is kept.
67 ****************************************************************************/
68
69 static void dptr_idle(dptr_struct *dptr)
70 {
71   if (dptr->ptr) {
72     DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
73     dptrs_open--;
74     CloseDir(dptr->ptr);
75     dptr->ptr = NULL;
76   }
77 }
78
79 /****************************************************************************
80  Idle the oldest dptr.
81 ****************************************************************************/
82
83 static void dptr_idleoldest(void)
84 {
85   dptr_struct *dptr;
86
87   /*
88    * Go to the end of the list.
89    */
90   for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
91     ;
92
93   if(!dptr) {
94     DEBUG(0,("No dptrs available to idle ?\n"));
95     return;
96   }
97
98   /*
99    * Idle the oldest pointer.
100    */
101
102   for(; dptr; dptr = dptr->prev) {
103     if (dptr->ptr) {
104       dptr_idle(dptr);
105       return;
106     }
107   }
108 }
109
110 /****************************************************************************
111  Get the dptr_struct for a dir index.
112 ****************************************************************************/
113
114 static dptr_struct *dptr_get(int key, BOOL forclose)
115 {
116   dptr_struct *dptr;
117
118   for(dptr = dirptrs; dptr; dptr = dptr->next) {
119     if(dptr->dnum == key) {
120       if (!forclose && !dptr->ptr) {
121         if (dptrs_open >= MAX_OPEN_DIRECTORIES)
122           dptr_idleoldest();
123         DEBUG(4,("Reopening dptr key %d\n",key));
124         if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True)))
125           dptrs_open++;
126       }
127       DLIST_PROMOTE(dirptrs,dptr);
128       return dptr;
129     }
130   }
131   return(NULL);
132 }
133
134 /****************************************************************************
135  Get the dptr ptr for a dir index.
136 ****************************************************************************/
137
138 static void *dptr_ptr(int key)
139 {
140   dptr_struct *dptr = dptr_get(key, False);
141
142   if (dptr)
143     return(dptr->ptr);
144   return(NULL);
145 }
146
147 /****************************************************************************
148  Get the dir path for a dir index.
149 ****************************************************************************/
150
151 char *dptr_path(int key)
152 {
153   dptr_struct *dptr = dptr_get(key, False);
154
155   if (dptr)
156     return(dptr->path);
157   return(NULL);
158 }
159
160 /****************************************************************************
161  Get the dir wcard for a dir index (lanman2 specific).
162 ****************************************************************************/
163
164 char *dptr_wcard(int key)
165 {
166   dptr_struct *dptr = dptr_get(key, False);
167
168   if (dptr)
169     return(dptr->wcard);
170   return(NULL);
171 }
172
173 /****************************************************************************
174  Set the dir wcard for a dir index (lanman2 specific).
175  Returns 0 on ok, 1 on fail.
176 ****************************************************************************/
177
178 BOOL dptr_set_wcard(int key, char *wcard)
179 {
180   dptr_struct *dptr = dptr_get(key, False);
181
182   if (dptr) {
183     dptr->wcard = wcard;
184     return True;
185   }
186   return False;
187 }
188
189 /****************************************************************************
190  Set the dir attrib for a dir index (lanman2 specific).
191  Returns 0 on ok, 1 on fail.
192 ****************************************************************************/
193
194 BOOL dptr_set_attr(int key, uint16 attr)
195 {
196   dptr_struct *dptr = dptr_get(key, False);
197
198   if (dptr) {
199     dptr->attr = attr;
200     return True;
201   }
202   return False;
203 }
204
205 /****************************************************************************
206  Get the dir attrib for a dir index (lanman2 specific)
207 ****************************************************************************/
208
209 uint16 dptr_attr(int key)
210 {
211   dptr_struct *dptr = dptr_get(key, False);
212
213   if (dptr)
214     return(dptr->attr);
215   return(0);
216 }
217
218 /****************************************************************************
219  Close a dptr (internal func).
220 ****************************************************************************/
221
222 static void dptr_close_internal(dptr_struct *dptr)
223 {
224   DEBUG(4,("closing dptr key %d\n",dptr->dnum));
225
226   DLIST_REMOVE(dirptrs, dptr);
227
228   /* 
229    * Free the dnum in the bitmap. Remember the dnum value is always 
230    * biased by one with respect to the bitmap.
231    */
232
233   if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
234     DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
235                         dptr->dnum ));
236   }
237
238   bitmap_clear(dptr_bmap, dptr->dnum - 1);
239
240   if (dptr->ptr) {
241     CloseDir(dptr->ptr);
242     dptrs_open--;
243   }
244
245   /* Lanman 2 specific code */
246   SAFE_FREE(dptr->wcard);
247   string_set(&dptr->path,"");
248   SAFE_FREE(dptr);
249 }
250
251 /****************************************************************************
252  Close a dptr given a key.
253 ****************************************************************************/
254
255 void dptr_close(int *key)
256 {
257   dptr_struct *dptr;
258
259   if(*key == INVALID_DPTR_KEY)
260     return;
261
262   /* OS/2 seems to use -1 to indicate "close all directories" */
263   if (*key == -1) {
264     dptr_struct *next;
265     for(dptr = dirptrs; dptr; dptr = next) {
266       next = dptr->next;
267       dptr_close_internal(dptr);
268     }
269     *key = INVALID_DPTR_KEY;
270     return;
271   }
272
273   dptr = dptr_get(*key, True);
274
275   if (!dptr) {
276     DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
277     return;
278   }
279
280   dptr_close_internal(dptr);
281
282   *key = INVALID_DPTR_KEY;
283 }
284
285 /****************************************************************************
286  Close all dptrs for a cnum.
287 ****************************************************************************/
288
289 void dptr_closecnum(connection_struct *conn)
290 {
291   dptr_struct *dptr, *next;
292   for(dptr = dirptrs; dptr; dptr = next) {
293     next = dptr->next;
294     if (dptr->conn == conn)
295       dptr_close_internal(dptr);
296   }
297 }
298
299 /****************************************************************************
300  Idle all dptrs for a cnum.
301 ****************************************************************************/
302
303 void dptr_idlecnum(connection_struct *conn)
304 {
305   dptr_struct *dptr;
306   for(dptr = dirptrs; dptr; dptr = dptr->next) {
307     if (dptr->conn == conn && dptr->ptr)
308       dptr_idle(dptr);
309   }
310 }
311
312 /****************************************************************************
313  Close a dptr that matches a given path, only if it matches the spid also.
314 ****************************************************************************/
315
316 void dptr_closepath(char *path,uint16 spid)
317 {
318   dptr_struct *dptr, *next;
319   for(dptr = dirptrs; dptr; dptr = next) {
320     next = dptr->next;
321     if (spid == dptr->spid && strequal(dptr->path,path))
322       dptr_close_internal(dptr);
323   }
324 }
325
326 /****************************************************************************
327  Start a directory listing.
328 ****************************************************************************/
329
330 static BOOL start_dir(connection_struct *conn,char *directory)
331 {
332   DEBUG(5,("start_dir dir=%s\n",directory));
333
334   if (!check_name(directory,conn))
335     return(False);
336   
337   if (! *directory)
338     directory = ".";
339
340   conn->dirptr = OpenDir(conn, directory, True);
341   if (conn->dirptr) {    
342     dptrs_open++;
343     string_set(&conn->dirpath,directory);
344     return(True);
345   }
346   
347   return(False);
348 }
349
350 /****************************************************************************
351  Try and close the oldest handle not marked for
352  expect close in the hope that the client has
353  finished with that one.
354 ****************************************************************************/
355
356 static void dptr_close_oldest(BOOL old)
357 {
358   dptr_struct *dptr;
359
360   /*
361    * Go to the end of the list.
362    */
363   for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
364     ;
365
366   if(!dptr) {
367     DEBUG(0,("No old dptrs available to close oldest ?\n"));
368     return;
369   }
370
371   /*
372    * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
373    * does not have expect_close set. If 'old' is false, close
374    * one of the new dnum handles.
375    */
376
377   for(; dptr; dptr = dptr->prev) {
378     if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
379         (!old && (dptr->dnum > 255))) {
380       dptr_close_internal(dptr);
381       return;
382     }
383   }
384 }
385
386 /****************************************************************************
387  Create a new dir ptr. If the flag old_handle is true then we must allocate
388  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
389  one byte long. If old_handle is false we allocate from the range
390  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
391  a directory handle is never zero. All the above is folklore taught to
392  me at Andrew's knee.... :-) :-). JRA.
393 ****************************************************************************/
394
395 int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,uint16 spid)
396 {
397   dptr_struct *dptr;
398
399   if (!start_dir(conn,path))
400     return(-2); /* Code to say use a unix error return code. */
401
402   if (dptrs_open >= MAX_OPEN_DIRECTORIES)
403     dptr_idleoldest();
404
405   dptr = (dptr_struct *)malloc(sizeof(dptr_struct));
406   if(!dptr) {
407     DEBUG(0,("malloc fail in dptr_create.\n"));
408     return -1;
409   }
410
411   ZERO_STRUCTP(dptr);
412
413   if(old_handle) {
414
415     /*
416      * This is an old-style SMBsearch request. Ensure the
417      * value we return will fit in the range 1-255.
418      */
419
420     dptr->dnum = bitmap_find(dptr_bmap, 0);
421
422     if(dptr->dnum == -1 || dptr->dnum > 254) {
423
424       /*
425        * Try and close the oldest handle not marked for
426        * expect close in the hope that the client has
427        * finished with that one.
428        */
429
430       dptr_close_oldest(True);
431
432       /* Now try again... */
433       dptr->dnum = bitmap_find(dptr_bmap, 0);
434
435       if(dptr->dnum == -1 || dptr->dnum > 254) {
436         DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
437         SAFE_FREE(dptr);
438         return -1;
439       }
440     }
441   } else {
442
443     /*
444      * This is a new-style trans2 request. Allocate from
445      * a range that will return 256 - MAX_DIRECTORY_HANDLES.
446      */
447
448     dptr->dnum = bitmap_find(dptr_bmap, 255);
449
450     if(dptr->dnum == -1 || dptr->dnum < 255) {
451
452       /*
453        * Try and close the oldest handle close in the hope that
454        * the client has finished with that one. This will only
455        * happen in the case of the Win98 client bug where it leaks
456        * directory handles.
457        */
458
459       dptr_close_oldest(False);
460
461       /* Now try again... */
462       dptr->dnum = bitmap_find(dptr_bmap, 255);
463
464       if(dptr->dnum == -1 || dptr->dnum < 255) {
465         DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
466         SAFE_FREE(dptr);
467         return -1;
468       }
469     }
470   }
471
472   bitmap_set(dptr_bmap, dptr->dnum);
473
474   dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
475
476   dptr->ptr = conn->dirptr;
477   string_set(&dptr->path,path);
478   dptr->conn = conn;
479   dptr->spid = spid;
480   dptr->expect_close = expect_close;
481   dptr->wcard = NULL; /* Only used in lanman2 searches */
482   dptr->attr = 0; /* Only used in lanman2 searches */
483
484   DLIST_ADD(dirptrs, dptr);
485
486   DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
487            dptr->dnum,path,expect_close));  
488
489   return(dptr->dnum);
490 }
491
492 /****************************************************************************
493  Fill the 5 byte server reserved dptr field.
494 ****************************************************************************/
495
496 BOOL dptr_fill(char *buf1,unsigned int key)
497 {
498   unsigned char *buf = (unsigned char *)buf1;
499   void *p = dptr_ptr(key);
500   uint32 offset;
501   if (!p) {
502     DEBUG(1,("filling null dirptr %d\n",key));
503     return(False);
504   }
505   offset = TellDir(p);
506   DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
507            (long)p,(int)offset));
508   buf[0] = key;
509   SIVAL(buf,1,offset | DPTR_MASK);
510   return(True);
511 }
512
513 /****************************************************************************
514  Fetch the dir ptr and seek it given the 5 byte server field.
515 ****************************************************************************/
516
517 void *dptr_fetch(char *buf,int *num)
518 {
519   unsigned int key = *(unsigned char *)buf;
520   void *p = dptr_ptr(key);
521   uint32 offset;
522   if (!p) {
523     DEBUG(3,("fetched null dirptr %d\n",key));
524     return(NULL);
525   }
526   *num = key;
527   offset = IVAL(buf,1)&~DPTR_MASK;
528   SeekDir(p,offset);
529   DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
530            key,dptr_path(key),offset));
531   return(p);
532 }
533
534 /****************************************************************************
535  Fetch the dir ptr.
536 ****************************************************************************/
537
538 void *dptr_fetch_lanman2(int dptr_num)
539 {
540   void *p = dptr_ptr(dptr_num);
541
542   if (!p) {
543     DEBUG(3,("fetched null dirptr %d\n",dptr_num));
544     return(NULL);
545   }
546   DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
547   return(p);
548 }
549
550 /****************************************************************************
551  Check a filetype for being valid.
552 ****************************************************************************/
553
554 BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
555 {
556   if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
557     return False;
558   return True;
559 }
560
561 static BOOL mangle_mask_match(connection_struct *conn, char *filename, char *mask)
562 {
563         mangle_map(filename,True,False,SNUM(conn));
564         return mask_match(filename,mask,False);
565 }
566
567 /****************************************************************************
568  Get an 8.3 directory entry.
569 ****************************************************************************/
570
571 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
572                    SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
573 {
574   char *dname;
575   BOOL found = False;
576   SMB_STRUCT_STAT sbuf;
577   pstring path;
578   pstring pathreal;
579   BOOL isrootdir;
580   pstring filename;
581   BOOL needslash;
582
583   *path = *pathreal = *filename = 0;
584
585   isrootdir = (strequal(conn->dirpath,"./") ||
586                strequal(conn->dirpath,".") ||
587                strequal(conn->dirpath,"/"));
588   
589   needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
590
591   if (!conn->dirptr)
592     return(False);
593
594   while (!found)
595   {
596     dname = ReadDirName(conn->dirptr);
597
598     DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
599           (long)conn->dirptr,TellDir(conn->dirptr)));
600       
601     if (dname == NULL) 
602       return(False);
603       
604     pstrcpy(filename,dname);      
605
606     /* notice the special *.* handling. This appears to be the only difference
607        between the wildcard handling in this routine and in the trans2 routines.
608        see masktest for a demo
609     */
610     if ((strcmp(mask,"*.*") == 0) ||
611         mask_match(filename,mask,False) ||
612         mangle_mask_match(conn,filename,mask))
613     {
614       if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
615         continue;
616
617       if (!mangle_is_8_3(filename, False)) {
618               mangle_map(filename,True,False,SNUM(conn));
619       }
620
621       pstrcpy(fname,filename);
622       *path = 0;
623       pstrcpy(path,conn->dirpath);
624       if(needslash)
625         pstrcat(path,"/");
626       pstrcpy(pathreal,path);
627       pstrcat(path,fname);
628       pstrcat(pathreal,dname);
629       if (conn->vfs_ops.stat(conn, pathreal, &sbuf) != 0)
630       {
631         DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
632         continue;
633       }
634           
635       *mode = dos_mode(conn,pathreal,&sbuf);
636
637       if (!dir_check_ftype(conn,*mode,&sbuf,dirtype)) 
638       {
639         DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
640         continue;
641       }
642
643       *size = sbuf.st_size;
644       *date = sbuf.st_mtime;
645
646       DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
647           
648       found = True;
649     }
650   }
651
652   return(found);
653 }
654
655
656
657 typedef struct
658 {
659   int pos;
660   int numentries;
661   int mallocsize;
662   char *data;
663   char *current;
664 } Dir;
665
666
667
668 /*******************************************************************
669 check to see if a user can read a file. This is only approximate,
670 it is used as part of the "hide unreadable" option. Don't
671 use it for anything security sensitive
672 ********************************************************************/
673
674 static BOOL user_can_read_file(connection_struct *conn, char *name)
675 {
676         extern struct current_user current_user;
677         SMB_STRUCT_STAT ste;
678         SEC_DESC *psd = NULL;
679         size_t sd_size;
680         files_struct *fsp;
681         int smb_action;
682         int access_mode;
683         NTSTATUS status;
684         uint32 access_granted;
685
686         ZERO_STRUCT(ste);
687
688         /*
689          * If user is a member of the Admin group
690          * we never hide files from them.
691          */
692
693         if (conn->admin_user)
694                 return True;
695
696         /* If we can't stat it does not show it */
697         if (vfs_stat(conn, name, &ste) != 0)
698                 return False;
699
700         /* Pseudo-open the file (note - no fd's created). */
701
702         if(S_ISDIR(ste.st_mode))        
703                  fsp = open_directory(conn, name, &ste, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
704                         unix_mode(conn,aRONLY|aDIR, name), &smb_action);
705         else
706                 fsp = open_file_shared1(conn, name, &ste, FILE_READ_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
707                         (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
708
709         if (!fsp)
710                 return False;
711
712         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
713         sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
714         close_file(fsp, False);
715
716         /* No access if SD get failed. */
717         if (!sd_size)
718                 return False;
719
720         return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
721                                  &access_granted, &status);
722 }
723
724 /*******************************************************************
725 check to see if a user can write a file (and only files, we do not
726 check dirs on this one). This is only approximate,
727 it is used as part of the "hide unwriteable" option. Don't
728 use it for anything security sensitive
729 ********************************************************************/
730
731 static BOOL user_can_write_file(connection_struct *conn, char *name)
732 {
733         extern struct current_user current_user;
734         SMB_STRUCT_STAT ste;
735         SEC_DESC *psd = NULL;
736         size_t sd_size;
737         files_struct *fsp;
738         int smb_action;
739         int access_mode;
740         NTSTATUS status;
741         uint32 access_granted;
742
743         ZERO_STRUCT(ste);
744
745         /*
746          * If user is a member of the Admin group
747          * we never hide files from them.
748          */
749
750         if (conn->admin_user)
751                 return True;
752
753         /* If we can't stat it does not show it */
754         if (vfs_stat(conn, name, &ste) != 0)
755                 return False;
756
757         /* Pseudo-open the file (note - no fd's created). */
758
759         if(S_ISDIR(ste.st_mode))        
760                 return True;
761         else
762                 fsp = open_file_shared1(conn, name, &ste, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
763                         (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
764
765         if (!fsp)
766                 return False;
767
768         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
769         sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
770         close_file(fsp, False);
771
772         /* No access if SD get failed. */
773         if (!sd_size)
774                 return False;
775
776         return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
777                                  &access_granted, &status);
778 }
779
780 /*******************************************************************
781  Open a directory.
782 ********************************************************************/
783
784 void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
785 {
786         Dir *dirp;
787         char *n;
788         DIR *p = conn->vfs_ops.opendir(conn,name);
789         int used=0;
790
791         if (!p)
792                 return(NULL);
793         dirp = (Dir *)malloc(sizeof(Dir));
794         if (!dirp) {
795                 DEBUG(0,("Out of memory in OpenDir\n"));
796                 conn->vfs_ops.closedir(conn,p);
797                 return(NULL);
798         }
799         dirp->pos = dirp->numentries = dirp->mallocsize = 0;
800         dirp->data = dirp->current = NULL;
801
802         while (True) {
803                 int l;
804                 BOOL normal_entry = True;
805
806                 if (used == 0) {
807                         n = ".";
808                         normal_entry = False;
809                 } else if (used == 2) {
810                         n = "..";
811                         normal_entry = False;
812                 } else {
813                         n = vfs_readdirname(conn, p);
814                         if (n == NULL)
815                                 break;
816                         if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0))
817                                 continue;
818                         normal_entry = True;
819                 }
820
821                 l = strlen(n)+1;
822
823                 /* If it's a vetoed file, pretend it doesn't even exist */
824                 if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n))
825                         continue;
826
827                 /* Honour _hide unreadable_ option */
828                 if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) {
829                         char *entry;
830                         int ret=0;
831       
832                         if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
833                                 ret = user_can_read_file(conn, entry);
834                                 SAFE_FREE(entry);
835                         }
836                         if (!ret)
837                                 continue;
838                 }
839
840                 /* Honour _hide unwriteable_ option */
841                 if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) {
842                         char *entry;
843                         int ret=0;
844       
845                         if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
846                                 ret = user_can_write_file(conn, entry);
847                                 SAFE_FREE(entry);
848                         }
849                         if (!ret)
850                                 continue;
851                 }
852
853                 if (used + l > dirp->mallocsize) {
854                         int s = MAX(used+l,used+2000);
855                         char *r;
856                         r = (char *)Realloc(dirp->data,s);
857                         if (!r) {
858                                 DEBUG(0,("Out of memory in OpenDir\n"));
859                                         break;
860                         }
861                         dirp->data = r;
862                         dirp->mallocsize = s;
863                         dirp->current = dirp->data;
864                 }
865
866                 pstrcpy(dirp->data+used,n);
867                 used += l;
868                 dirp->numentries++;
869         }
870
871         conn->vfs_ops.closedir(conn,p);
872         return((void *)dirp);
873 }
874
875
876 /*******************************************************************
877  Close a directory.
878 ********************************************************************/
879
880 void CloseDir(void *p)
881 {
882   if (!p) return;    
883   SAFE_FREE(((Dir *)p)->data);
884   SAFE_FREE(p);
885 }
886
887 /*******************************************************************
888  Read from a directory.
889 ********************************************************************/
890
891 char *ReadDirName(void *p)
892 {
893   char *ret;
894   Dir *dirp = (Dir *)p;
895
896   if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
897
898   ret = dirp->current;
899   dirp->current = skip_string(dirp->current,1);
900   dirp->pos++;
901
902   return(ret);
903 }
904
905
906 /*******************************************************************
907  Seek a dir.
908 ********************************************************************/
909
910 BOOL SeekDir(void *p,int pos)
911 {
912   Dir *dirp = (Dir *)p;
913
914   if (!dirp) return(False);
915
916   if (pos < dirp->pos) {
917     dirp->current = dirp->data;
918     dirp->pos = 0;
919   }
920
921   while (dirp->pos < pos && ReadDirName(p)) ;
922
923   return(dirp->pos == pos);
924 }
925
926 /*******************************************************************
927  Tell a dir position.
928 ********************************************************************/
929
930 int TellDir(void *p)
931 {
932   Dir *dirp = (Dir *)p;
933
934   if (!dirp) return(-1);
935   
936   return(dirp->pos);
937 }
938
939 /*******************************************************************************
940  This section manages a global directory cache.
941  (It should probably be split into a separate module.  crh)
942 ********************************************************************************/
943
944 typedef struct {
945   ubi_dlNode  node;
946   char       *path;
947   char       *name;
948   char       *dname;
949   int         snum;
950 } dir_cache_entry;
951
952 static ubi_dlNewList( dir_cache );
953
954 /*****************************************************************************
955  Add an entry to the directory cache.
956  Input:  path  -
957          name  -
958          dname -
959          snum  -
960  Output: None.
961 *****************************************************************************/
962
963 void DirCacheAdd( char *path, char *name, char *dname, int snum )
964 {
965   int               pathlen;
966   int               namelen;
967   dir_cache_entry  *entry;
968
969   /* Allocate the structure & string space in one go so that it can be freed
970    * in one call to free().
971    */
972   pathlen = strlen( path ) +1;  /* Bytes required to store path (with nul). */
973   namelen = strlen( name ) +1;  /* Bytes required to store name (with nul). */
974   entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
975                                    + pathlen
976                                    + namelen
977                                    + strlen( dname ) +1 );
978   if( NULL == entry )   /* Not adding to the cache is not fatal,  */
979     return;             /* so just return as if nothing happened. */
980
981   /* Set pointers correctly and load values. */
982   entry->path  = pstrcpy( (char *)&entry[1],       path);
983   entry->name  = pstrcpy( &(entry->path[pathlen]), name);
984   entry->dname = pstrcpy( &(entry->name[namelen]), dname);
985   entry->snum  = snum;
986
987   /* Add the new entry to the linked list. */
988   (void)ubi_dlAddHead( dir_cache, entry );
989   DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
990
991   /* Free excess cache entries. */
992   while( DIRCACHESIZE < dir_cache->count )
993     safe_free( ubi_dlRemTail( dir_cache ) );
994
995 }
996
997 /*****************************************************************************
998  Search for an entry to the directory cache.
999  Input:  path  -
1000          name  -
1001          snum  -
1002  Output: The dname string of the located entry, or NULL if the entry was
1003          not found.
1004
1005  Notes:  This uses a linear search, which is is okay because of
1006          the small size of the cache.  Use a splay tree or hash
1007          for large caches.
1008 *****************************************************************************/
1009
1010 char *DirCacheCheck( char *path, char *name, int snum )
1011 {
1012   dir_cache_entry *entry;
1013
1014   for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
1015        NULL != entry;
1016        entry = (dir_cache_entry *)ubi_dlNext( entry ) )
1017     {
1018     if( entry->snum == snum
1019         && 0 == strcmp( name, entry->name )
1020         && 0 == strcmp( path, entry->path ) )
1021       {
1022       DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
1023       return( entry->dname );
1024       }
1025     }
1026
1027   return(NULL);
1028 }
1029
1030 /*****************************************************************************
1031  Remove all cache entries which have an snum that matches the input.
1032  Input:  snum  -
1033  Output: None.
1034 *****************************************************************************/
1035
1036 void DirCacheFlush(int snum)
1037 {
1038         dir_cache_entry *entry;
1039         ubi_dlNodePtr    next;
1040
1041         for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); 
1042             NULL != entry; )  {
1043                 next = ubi_dlNext( entry );
1044                 if( entry->snum == snum )
1045                         safe_free( ubi_dlRemThis( dir_cache, entry ) );
1046                 entry = (dir_cache_entry *)next;
1047         }
1048 }