fix file_is_special test, was wrong.
[vlendec/samba-autobuild/.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  Check to see if a user can read a file. This is only approximate,
668  it is used as part of the "hide unreadable" option. Don't
669  use it for anything security sensitive.
670 ********************************************************************/
671
672 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
673 {
674         extern struct current_user current_user;
675         SEC_DESC *psd = NULL;
676         size_t sd_size;
677         files_struct *fsp;
678         int smb_action;
679         int access_mode;
680         NTSTATUS status;
681         uint32 access_granted;
682
683         /*
684          * If user is a member of the Admin group
685          * we never hide files from them.
686          */
687
688         if (conn->admin_user)
689                 return True;
690
691         /* If we can't stat it does not show it */
692         if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0))
693                 return False;
694
695         /* Pseudo-open the file (note - no fd's created). */
696
697         if(S_ISDIR(pst->st_mode))       
698                  fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
699                         unix_mode(conn,aRONLY|aDIR, name), &smb_action);
700         else
701                 fsp = open_file_shared1(conn, name, pst, FILE_READ_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
702                         (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
703
704         if (!fsp)
705                 return False;
706
707         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
708         sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
709         close_file(fsp, False);
710
711         /* No access if SD get failed. */
712         if (!sd_size)
713                 return False;
714
715         return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
716                                  &access_granted, &status);
717 }
718
719 /*******************************************************************
720  Check to see if a user can write a file (and only files, we do not
721  check dirs on this one). This is only approximate,
722  it is used as part of the "hide unwriteable" option. Don't
723  use it for anything security sensitive.
724 ********************************************************************/
725
726 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
727 {
728         extern struct current_user current_user;
729         SEC_DESC *psd = NULL;
730         size_t sd_size;
731         files_struct *fsp;
732         int smb_action;
733         int access_mode;
734         NTSTATUS status;
735         uint32 access_granted;
736
737         /*
738          * If user is a member of the Admin group
739          * we never hide files from them.
740          */
741
742         if (conn->admin_user)
743                 return True;
744
745         /* If we can't stat it does not show it */
746         if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0))
747                 return False;
748
749         /* Pseudo-open the file (note - no fd's created). */
750
751         if(S_ISDIR(pst->st_mode))       
752                 return True;
753         else
754                 fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
755                         (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
756
757         if (!fsp)
758                 return False;
759
760         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
761         sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
762         close_file(fsp, False);
763
764         /* No access if SD get failed. */
765         if (!sd_size)
766                 return False;
767
768         return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
769                                  &access_granted, &status);
770 }
771
772 /*******************************************************************
773   Is a file a "special" type ?
774 ********************************************************************/
775
776 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
777 {
778         /*
779          * If user is a member of the Admin group
780          * we never hide files from them.
781          */
782
783         if (conn->admin_user)
784                 return True;
785
786         /* If we can't stat it does not show it */
787         if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0))
788                 return True;
789
790         if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
791                 return False;
792
793         return True;
794 }
795
796 /*******************************************************************
797  Open a directory.
798 ********************************************************************/
799
800 void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
801 {
802         Dir *dirp;
803         char *n;
804         DIR *p = conn->vfs_ops.opendir(conn,name);
805         int used=0;
806
807         if (!p)
808                 return(NULL);
809         dirp = (Dir *)malloc(sizeof(Dir));
810         if (!dirp) {
811                 DEBUG(0,("Out of memory in OpenDir\n"));
812                 conn->vfs_ops.closedir(conn,p);
813                 return(NULL);
814         }
815         dirp->pos = dirp->numentries = dirp->mallocsize = 0;
816         dirp->data = dirp->current = NULL;
817
818         while (True) {
819                 int l;
820                 BOOL normal_entry = True;
821                 SMB_STRUCT_STAT st;
822                 char *entry = NULL;
823
824                 if (used == 0) {
825                         n = ".";
826                         normal_entry = False;
827                 } else if (used == 2) {
828                         n = "..";
829                         normal_entry = False;
830                 } else {
831                         n = vfs_readdirname(conn, p);
832                         if (n == NULL)
833                                 break;
834                         if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0))
835                                 continue;
836                         normal_entry = True;
837                 }
838
839                 ZERO_STRUCT(st);
840                 l = strlen(n)+1;
841
842                 /* If it's a vetoed file, pretend it doesn't even exist */
843                 if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n))
844                         continue;
845
846                 /* Honour _hide unreadable_ option */
847                 if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) {
848                         int ret=0;
849       
850                         if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
851                                 ret = user_can_read_file(conn, entry, &st);
852                         }
853                         if (!ret) {
854                                 SAFE_FREE(entry);
855                                 continue;
856                         }
857                 }
858
859                 /* Honour _hide unwriteable_ option */
860                 if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) {
861                         int ret=0;
862       
863                         if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
864                                 ret = user_can_write_file(conn, entry, &st);
865                         }
866                         if (!ret) {
867                                 SAFE_FREE(entry);
868                                 continue;
869                         }
870                 }
871
872                 /* Honour _hide_special_ option */
873                 if (normal_entry && conn && lp_hide_special_files(SNUM(conn))) {
874                         int ret=0;
875       
876                         if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
877                                 ret = file_is_special(conn, entry, &st);
878                         }
879                         if (ret) {
880                                 SAFE_FREE(entry);
881                                 continue;
882                         }
883                 }
884
885                 SAFE_FREE(entry);
886
887                 if (used + l > dirp->mallocsize) {
888                         int s = MAX(used+l,used+2000);
889                         char *r;
890                         r = (char *)Realloc(dirp->data,s);
891                         if (!r) {
892                                 DEBUG(0,("Out of memory in OpenDir\n"));
893                                         break;
894                         }
895                         dirp->data = r;
896                         dirp->mallocsize = s;
897                         dirp->current = dirp->data;
898                 }
899
900                 pstrcpy(dirp->data+used,n);
901                 used += l;
902                 dirp->numentries++;
903         }
904
905         conn->vfs_ops.closedir(conn,p);
906         return((void *)dirp);
907 }
908
909
910 /*******************************************************************
911  Close a directory.
912 ********************************************************************/
913
914 void CloseDir(void *p)
915 {
916   if (!p) return;    
917   SAFE_FREE(((Dir *)p)->data);
918   SAFE_FREE(p);
919 }
920
921 /*******************************************************************
922  Read from a directory.
923 ********************************************************************/
924
925 char *ReadDirName(void *p)
926 {
927   char *ret;
928   Dir *dirp = (Dir *)p;
929
930   if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
931
932   ret = dirp->current;
933   dirp->current = skip_string(dirp->current,1);
934   dirp->pos++;
935
936   return(ret);
937 }
938
939
940 /*******************************************************************
941  Seek a dir.
942 ********************************************************************/
943
944 BOOL SeekDir(void *p,int pos)
945 {
946   Dir *dirp = (Dir *)p;
947
948   if (!dirp) return(False);
949
950   if (pos < dirp->pos) {
951     dirp->current = dirp->data;
952     dirp->pos = 0;
953   }
954
955   while (dirp->pos < pos && ReadDirName(p)) ;
956
957   return(dirp->pos == pos);
958 }
959
960 /*******************************************************************
961  Tell a dir position.
962 ********************************************************************/
963
964 int TellDir(void *p)
965 {
966   Dir *dirp = (Dir *)p;
967
968   if (!dirp) return(-1);
969   
970   return(dirp->pos);
971 }
972
973 /*******************************************************************************
974  This section manages a global directory cache.
975  (It should probably be split into a separate module.  crh)
976 ********************************************************************************/
977
978 typedef struct {
979   ubi_dlNode  node;
980   char       *path;
981   char       *name;
982   char       *dname;
983   int         snum;
984 } dir_cache_entry;
985
986 static ubi_dlNewList( dir_cache );
987
988 /*****************************************************************************
989  Add an entry to the directory cache.
990  Input:  path  -
991          name  -
992          dname -
993          snum  -
994  Output: None.
995 *****************************************************************************/
996
997 void DirCacheAdd( char *path, char *name, char *dname, int snum )
998 {
999   int               pathlen;
1000   int               namelen;
1001   dir_cache_entry  *entry;
1002
1003   /* Allocate the structure & string space in one go so that it can be freed
1004    * in one call to free().
1005    */
1006   pathlen = strlen( path ) +1;  /* Bytes required to store path (with nul). */
1007   namelen = strlen( name ) +1;  /* Bytes required to store name (with nul). */
1008   entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
1009                                    + pathlen
1010                                    + namelen
1011                                    + strlen( dname ) +1 );
1012   if( NULL == entry )   /* Not adding to the cache is not fatal,  */
1013     return;             /* so just return as if nothing happened. */
1014
1015   /* Set pointers correctly and load values. */
1016   entry->path  = pstrcpy( (char *)&entry[1],       path);
1017   entry->name  = pstrcpy( &(entry->path[pathlen]), name);
1018   entry->dname = pstrcpy( &(entry->name[namelen]), dname);
1019   entry->snum  = snum;
1020
1021   /* Add the new entry to the linked list. */
1022   (void)ubi_dlAddHead( dir_cache, entry );
1023   DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
1024
1025   /* Free excess cache entries. */
1026   while( DIRCACHESIZE < dir_cache->count )
1027     safe_free( ubi_dlRemTail( dir_cache ) );
1028
1029 }
1030
1031 /*****************************************************************************
1032  Search for an entry to the directory cache.
1033  Input:  path  -
1034          name  -
1035          snum  -
1036  Output: The dname string of the located entry, or NULL if the entry was
1037          not found.
1038
1039  Notes:  This uses a linear search, which is is okay because of
1040          the small size of the cache.  Use a splay tree or hash
1041          for large caches.
1042 *****************************************************************************/
1043
1044 char *DirCacheCheck( char *path, char *name, int snum )
1045 {
1046   dir_cache_entry *entry;
1047
1048   for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
1049        NULL != entry;
1050        entry = (dir_cache_entry *)ubi_dlNext( entry ) )
1051     {
1052     if( entry->snum == snum
1053         && 0 == strcmp( name, entry->name )
1054         && 0 == strcmp( path, entry->path ) )
1055       {
1056       DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
1057       return( entry->dname );
1058       }
1059     }
1060
1061   return(NULL);
1062 }
1063
1064 /*****************************************************************************
1065  Remove all cache entries which have an snum that matches the input.
1066  Input:  snum  -
1067  Output: None.
1068 *****************************************************************************/
1069
1070 void DirCacheFlush(int snum)
1071 {
1072         dir_cache_entry *entry;
1073         ubi_dlNodePtr    next;
1074
1075         for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); 
1076             NULL != entry; )  {
1077                 next = ubi_dlNext( entry );
1078                 if( entry->snum == snum )
1079                         safe_free( ubi_dlRemThis( dir_cache, entry ) );
1080                 entry = (dir_cache_entry *)next;
1081         }
1082 }