Some cleanups:
[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, pstring directory)
331 {
332         const char *dir2;
333
334         DEBUG(5,("start_dir dir=%s\n",directory));
335
336         if (!check_name(directory,conn))
337                 return(False);
338
339         /* use a const pointer from here on */
340         dir2 = directory;
341   
342         if (! *dir2)
343                 dir2 = ".";
344
345         conn->dirptr = OpenDir(conn, directory, True);
346         if (conn->dirptr) {    
347                 dptrs_open++;
348                 string_set(&conn->dirpath,directory);
349                 return(True);
350         }
351   
352         return(False);
353 }
354
355 /****************************************************************************
356  Try and close the oldest handle not marked for
357  expect close in the hope that the client has
358  finished with that one.
359 ****************************************************************************/
360
361 static void dptr_close_oldest(BOOL old)
362 {
363         dptr_struct *dptr;
364
365         /*
366          * Go to the end of the list.
367          */
368         for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
369                 ;
370
371         if(!dptr) {
372                 DEBUG(0,("No old dptrs available to close oldest ?\n"));
373                 return;
374         }
375
376         /*
377          * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
378          * does not have expect_close set. If 'old' is false, close
379          * one of the new dnum handles.
380          */
381
382         for(; dptr; dptr = dptr->prev) {
383                 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
384                         (!old && (dptr->dnum > 255))) {
385                                 dptr_close_internal(dptr);
386                                 return;
387                 }
388         }
389 }
390
391 /****************************************************************************
392  Create a new dir ptr. If the flag old_handle is true then we must allocate
393  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
394  one byte long. If old_handle is false we allocate from the range
395  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
396  a directory handle is never zero. All the above is folklore taught to
397  me at Andrew's knee.... :-) :-). JRA.
398 ****************************************************************************/
399
400 int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid)
401 {
402         dptr_struct *dptr;
403
404         if (!start_dir(conn,path))
405                 return(-2); /* Code to say use a unix error return code. */
406
407         if (dptrs_open >= MAX_OPEN_DIRECTORIES)
408                 dptr_idleoldest();
409
410         dptr = (dptr_struct *)malloc(sizeof(dptr_struct));
411         if(!dptr) {
412                 DEBUG(0,("malloc fail in dptr_create.\n"));
413                 return -1;
414         }
415
416         ZERO_STRUCTP(dptr);
417
418         if(old_handle) {
419
420                 /*
421                  * This is an old-style SMBsearch request. Ensure the
422                  * value we return will fit in the range 1-255.
423                  */
424
425                 dptr->dnum = bitmap_find(dptr_bmap, 0);
426
427                 if(dptr->dnum == -1 || dptr->dnum > 254) {
428
429                         /*
430                          * Try and close the oldest handle not marked for
431                          * expect close in the hope that the client has
432                          * finished with that one.
433                          */
434
435                         dptr_close_oldest(True);
436
437                         /* Now try again... */
438                         dptr->dnum = bitmap_find(dptr_bmap, 0);
439                         if(dptr->dnum == -1 || dptr->dnum > 254) {
440                                 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
441                                 SAFE_FREE(dptr);
442                                 return -1;
443                         }
444                 }
445         } else {
446
447                 /*
448                  * This is a new-style trans2 request. Allocate from
449                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
450                  */
451
452                 dptr->dnum = bitmap_find(dptr_bmap, 255);
453
454                 if(dptr->dnum == -1 || dptr->dnum < 255) {
455
456                         /*
457                          * Try and close the oldest handle close in the hope that
458                          * the client has finished with that one. This will only
459                          * happen in the case of the Win98 client bug where it leaks
460                          * directory handles.
461                          */
462
463                         dptr_close_oldest(False);
464
465                         /* Now try again... */
466                         dptr->dnum = bitmap_find(dptr_bmap, 255);
467
468                         if(dptr->dnum == -1 || dptr->dnum < 255) {
469                                 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
470                                 SAFE_FREE(dptr);
471                                 return -1;
472                         }
473                 }
474         }
475
476         bitmap_set(dptr_bmap, dptr->dnum);
477
478         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
479
480         dptr->ptr = conn->dirptr;
481         string_set(&dptr->path,path);
482         dptr->conn = conn;
483         dptr->spid = spid;
484         dptr->expect_close = expect_close;
485         dptr->wcard = NULL; /* Only used in lanman2 searches */
486         dptr->attr = 0; /* Only used in lanman2 searches */
487
488         DLIST_ADD(dirptrs, dptr);
489
490         DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
491                 dptr->dnum,path,expect_close));  
492
493         return(dptr->dnum);
494 }
495
496 /****************************************************************************
497  Fill the 5 byte server reserved dptr field.
498 ****************************************************************************/
499
500 BOOL dptr_fill(char *buf1,unsigned int key)
501 {
502         unsigned char *buf = (unsigned char *)buf1;
503         void *p = dptr_ptr(key);
504         uint32 offset;
505         if (!p) {
506                 DEBUG(1,("filling null dirptr %d\n",key));
507                 return(False);
508         }
509         offset = TellDir(p);
510         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
511                 (long)p,(int)offset));
512         buf[0] = key;
513         SIVAL(buf,1,offset | DPTR_MASK);
514         return(True);
515 }
516
517 /****************************************************************************
518  Fetch the dir ptr and seek it given the 5 byte server field.
519 ****************************************************************************/
520
521 void *dptr_fetch(char *buf,int *num)
522 {
523         unsigned int key = *(unsigned char *)buf;
524         void *p = dptr_ptr(key);
525         uint32 offset;
526
527         if (!p) {
528                 DEBUG(3,("fetched null dirptr %d\n",key));
529                 return(NULL);
530         }
531         *num = key;
532         offset = IVAL(buf,1)&~DPTR_MASK;
533         SeekDir(p,offset);
534         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
535                 key,dptr_path(key),offset));
536         return(p);
537 }
538
539 /****************************************************************************
540  Fetch the dir ptr.
541 ****************************************************************************/
542
543 void *dptr_fetch_lanman2(int dptr_num)
544 {
545         void *p = dptr_ptr(dptr_num);
546
547         if (!p) {
548                 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
549                 return(NULL);
550         }
551         DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
552         return(p);
553 }
554
555 /****************************************************************************
556  Check a filetype for being valid.
557 ****************************************************************************/
558
559 BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
560 {
561         int mask;
562
563         /* Check the "may have" search bits. */
564         if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
565                 return False;
566
567         /* Check the "must have" bits, which are the may have bits shifted eight */
568         /* If must have bit is set, the file/dir can not be returned in search unless the matching
569                 file attribute is set */
570         mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
571         if(mask) {
572                 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask)   /* check if matching attribute present */
573                         return True;
574                 else
575                         return False;
576         }
577
578         return True;
579 }
580
581 static BOOL mangle_mask_match(connection_struct *conn, char *filename, char *mask)
582 {
583         mangle_map(filename,True,False,SNUM(conn));
584         return mask_match(filename,mask,False);
585 }
586
587 /****************************************************************************
588  Get an 8.3 directory entry.
589 ****************************************************************************/
590
591 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
592                    SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
593 {
594         char *dname;
595         BOOL found = False;
596         SMB_STRUCT_STAT sbuf;
597         pstring path;
598         pstring pathreal;
599         BOOL isrootdir;
600         pstring filename;
601         BOOL needslash;
602
603         *path = *pathreal = *filename = 0;
604
605         isrootdir = (strequal(conn->dirpath,"./") ||
606                         strequal(conn->dirpath,".") ||
607                         strequal(conn->dirpath,"/"));
608   
609         needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
610
611         if (!conn->dirptr)
612                 return(False);
613
614         while (!found) {
615                 dname = ReadDirName(conn->dirptr);
616
617                 DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
618                         (long)conn->dirptr,TellDir(conn->dirptr)));
619       
620                 if (dname == NULL) 
621                         return(False);
622       
623                 pstrcpy(filename,dname);      
624
625                 /* notice the special *.* handling. This appears to be the only difference
626                         between the wildcard handling in this routine and in the trans2 routines.
627                         see masktest for a demo
628                 */
629                 if ((strcmp(mask,"*.*") == 0) ||
630                                 mask_match(filename,mask,False) ||
631                                 mangle_mask_match(conn,filename,mask)) {
632                         if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
633                                 continue;
634
635                         if (!mangle_is_8_3(filename, False))
636                                 mangle_map(filename,True,False,SNUM(conn));
637
638                         pstrcpy(fname,filename);
639                         *path = 0;
640                         pstrcpy(path,conn->dirpath);
641                         if(needslash)
642                                 pstrcat(path,"/");
643                         pstrcpy(pathreal,path);
644                         pstrcat(path,fname);
645                         pstrcat(pathreal,dname);
646                         if (conn->vfs_ops.stat(conn, pathreal, &sbuf) != 0) {
647                                 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
648                                 continue;
649                         }
650           
651                         *mode = dos_mode(conn,pathreal,&sbuf);
652
653                         if (!dir_check_ftype(conn,*mode,&sbuf,dirtype)) {
654                                 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
655                                 continue;
656                         }
657
658                         *size = sbuf.st_size;
659                         *date = sbuf.st_mtime;
660
661                         DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
662
663                         found = True;
664                 }
665         }
666
667         return(found);
668 }
669
670 typedef struct {
671         int pos;
672         int numentries;
673         int mallocsize;
674         char *data;
675         char *current;
676 } Dir;
677
678 /*******************************************************************
679  Check to see if a user can read a file. This is only approximate,
680  it is used as part of the "hide unreadable" option. Don't
681  use it for anything security sensitive.
682 ********************************************************************/
683
684 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
685 {
686         extern struct current_user current_user;
687         SEC_DESC *psd = NULL;
688         size_t sd_size;
689         files_struct *fsp;
690         int smb_action;
691         NTSTATUS status;
692         uint32 access_granted;
693
694         /*
695          * If user is a member of the Admin group
696          * we never hide files from them.
697          */
698
699         if (conn->admin_user)
700                 return True;
701
702         /* If we can't stat it does not show it */
703         if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0))
704                 return False;
705
706         /* Pseudo-open the file (note - no fd's created). */
707
708         if(S_ISDIR(pst->st_mode))       
709                  fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
710                         unix_mode(conn,aRONLY|aDIR, name), &smb_action);
711         else
712                 fsp = open_file_stat(conn, name, pst);
713
714         if (!fsp)
715                 return False;
716
717         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
718         sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
719         close_file(fsp, True);
720
721         /* No access if SD get failed. */
722         if (!sd_size)
723                 return False;
724
725         return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
726                                  &access_granted, &status);
727 }
728
729 /*******************************************************************
730  Check to see if a user can write a file (and only files, we do not
731  check dirs on this one). This is only approximate,
732  it is used as part of the "hide unwriteable" option. Don't
733  use it for anything security sensitive.
734 ********************************************************************/
735
736 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
737 {
738         extern struct current_user current_user;
739         SEC_DESC *psd = NULL;
740         size_t sd_size;
741         files_struct *fsp;
742         int smb_action;
743         int access_mode;
744         NTSTATUS status;
745         uint32 access_granted;
746
747         /*
748          * If user is a member of the Admin group
749          * we never hide files from them.
750          */
751
752         if (conn->admin_user)
753                 return True;
754
755         /* If we can't stat it does not show it */
756         if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0))
757                 return False;
758
759         /* Pseudo-open the file (note - no fd's created). */
760
761         if(S_ISDIR(pst->st_mode))       
762                 return True;
763         else
764                 fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
765                         (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
766
767         if (!fsp)
768                 return False;
769
770         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
771         sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
772         close_file(fsp, False);
773
774         /* No access if SD get failed. */
775         if (!sd_size)
776                 return False;
777
778         return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
779                                  &access_granted, &status);
780 }
781
782 /*******************************************************************
783   Is a file a "special" type ?
784 ********************************************************************/
785
786 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
787 {
788         /*
789          * If user is a member of the Admin group
790          * we never hide files from them.
791          */
792
793         if (conn->admin_user)
794                 return True;
795
796         /* If we can't stat it does not show it */
797         if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0))
798                 return True;
799
800         if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
801                 return False;
802
803         return True;
804 }
805
806 /*******************************************************************
807  Open a directory.
808 ********************************************************************/
809
810 void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto)
811 {
812         Dir *dirp;
813         const char *n;
814         DIR *p = conn->vfs_ops.opendir(conn,name);
815         int used=0;
816
817         if (!p)
818                 return(NULL);
819         dirp = (Dir *)malloc(sizeof(Dir));
820         if (!dirp) {
821                 DEBUG(0,("Out of memory in OpenDir\n"));
822                 conn->vfs_ops.closedir(conn,p);
823                 return(NULL);
824         }
825         dirp->pos = dirp->numentries = dirp->mallocsize = 0;
826         dirp->data = dirp->current = NULL;
827
828         while (True) {
829                 int l;
830                 BOOL normal_entry = True;
831                 SMB_STRUCT_STAT st;
832                 char *entry = NULL;
833
834                 if (used == 0) {
835                         n = ".";
836                         normal_entry = False;
837                 } else if (used == 2) {
838                         n = "..";
839                         normal_entry = False;
840                 } else {
841                         n = vfs_readdirname(conn, p);
842                         if (n == NULL)
843                                 break;
844                         if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0))
845                                 continue;
846                         normal_entry = True;
847                 }
848
849                 ZERO_STRUCT(st);
850                 l = strlen(n)+1;
851
852                 /* If it's a vetoed file, pretend it doesn't even exist */
853                 if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n))
854                         continue;
855
856                 /* Honour _hide unreadable_ option */
857                 if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) {
858                         int ret=0;
859       
860                         if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
861                                 ret = user_can_read_file(conn, entry, &st);
862                         }
863                         if (!ret) {
864                                 SAFE_FREE(entry);
865                                 continue;
866                         }
867                 }
868
869                 /* Honour _hide unwriteable_ option */
870                 if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) {
871                         int ret=0;
872       
873                         if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
874                                 ret = user_can_write_file(conn, entry, &st);
875                         }
876                         if (!ret) {
877                                 SAFE_FREE(entry);
878                                 continue;
879                         }
880                 }
881
882                 /* Honour _hide_special_ option */
883                 if (normal_entry && conn && lp_hide_special_files(SNUM(conn))) {
884                         int ret=0;
885       
886                         if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
887                                 ret = file_is_special(conn, entry, &st);
888                         }
889                         if (ret) {
890                                 SAFE_FREE(entry);
891                                 continue;
892                         }
893                 }
894
895                 SAFE_FREE(entry);
896
897                 if (used + l > dirp->mallocsize) {
898                         int s = MAX(used+l,used+2000);
899                         char *r;
900                         r = (char *)Realloc(dirp->data,s);
901                         if (!r) {
902                                 DEBUG(0,("Out of memory in OpenDir\n"));
903                                         break;
904                         }
905                         dirp->data = r;
906                         dirp->mallocsize = s;
907                         dirp->current = dirp->data;
908                 }
909
910                 safe_strcpy(dirp->data+used,n, dirp->mallocsize - used - 1);
911                 used += l;
912                 dirp->numentries++;
913         }
914
915         conn->vfs_ops.closedir(conn,p);
916         return((void *)dirp);
917 }
918
919
920 /*******************************************************************
921  Close a directory.
922 ********************************************************************/
923
924 void CloseDir(void *p)
925 {
926         if (!p)
927                 return;    
928         SAFE_FREE(((Dir *)p)->data);
929         SAFE_FREE(p);
930 }
931
932 /*******************************************************************
933  Read from a directory.
934 ********************************************************************/
935
936 char *ReadDirName(void *p)
937 {
938         char *ret;
939         Dir *dirp = (Dir *)p;
940
941         if (!dirp || !dirp->current || dirp->pos >= dirp->numentries)
942                 return(NULL);
943
944         ret = dirp->current;
945         dirp->current = skip_string(dirp->current,1);
946         dirp->pos++;
947
948         return(ret);
949 }
950
951 /*******************************************************************
952  Seek a dir.
953 ********************************************************************/
954
955 BOOL SeekDir(void *p,int pos)
956 {
957         Dir *dirp = (Dir *)p;
958
959         if (!dirp)
960                 return(False);
961
962         if (pos < dirp->pos) {
963                 dirp->current = dirp->data;
964                 dirp->pos = 0;
965         }
966
967         while (dirp->pos < pos && ReadDirName(p))
968                 ;
969
970         return (dirp->pos == pos);
971 }
972
973 /*******************************************************************
974  Tell a dir position.
975 ********************************************************************/
976
977 int TellDir(void *p)
978 {
979         Dir *dirp = (Dir *)p;
980
981         if (!dirp)
982                 return(-1);
983   
984         return(dirp->pos);
985 }
986
987 /*******************************************************************************
988  This section manages a global directory cache.
989  (It should probably be split into a separate module.  crh)
990 ********************************************************************************/
991
992 typedef struct {
993         ubi_dlNode node;
994         char *path;
995         char *name;
996         char *dname;
997         int snum;
998 } dir_cache_entry;
999
1000 static ubi_dlNewList( dir_cache );
1001
1002 /*****************************************************************************
1003  Add an entry to the directory cache.
1004  Input:  path  -
1005          name  -
1006          dname -
1007          snum  -
1008  Output: None.
1009 *****************************************************************************/
1010
1011 void DirCacheAdd( const char *path, char *name, char *dname, int snum )
1012 {
1013         int pathlen;
1014         int namelen;
1015         dir_cache_entry  *entry;
1016
1017         /*
1018          * Allocate the structure & string space in one go so that it can be freed
1019          * in one call to free().
1020          */
1021         pathlen = strlen(path) + 1;  /* Bytes required to store path (with nul). */
1022         namelen = strlen(name) + 1;  /* Bytes required to store name (with nul). */
1023         entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
1024                                         + pathlen
1025                                         + namelen
1026                                         + strlen( dname ) +1 );
1027         if( NULL == entry )   /* Not adding to the cache is not fatal,  */
1028                 return;             /* so just return as if nothing happened. */
1029
1030         /* Set pointers correctly and load values. */
1031         entry->path  = pstrcpy( (char *)&entry[1], path);
1032         entry->name  = pstrcpy( &(entry->path[pathlen]), name);
1033         entry->dname = pstrcpy( &(entry->name[namelen]), dname);
1034         entry->snum  = snum;
1035
1036         /* Add the new entry to the linked list. */
1037         (void)ubi_dlAddHead( dir_cache, entry );
1038         DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
1039
1040         /* Free excess cache entries. */
1041         while( DIRCACHESIZE < dir_cache->count )
1042                 safe_free( ubi_dlRemTail( dir_cache ) );
1043 }
1044
1045 /*****************************************************************************
1046  Search for an entry to the directory cache.
1047  Input:  path  -
1048          name  -
1049          snum  -
1050  Output: The dname string of the located entry, or NULL if the entry was
1051          not found.
1052
1053  Notes:  This uses a linear search, which is is okay because of
1054          the small size of the cache.  Use a splay tree or hash
1055          for large caches.
1056 *****************************************************************************/
1057
1058 char *DirCacheCheck( const char *path, const char *name, int snum )
1059 {
1060         dir_cache_entry *entry;
1061
1062         for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
1063                         NULL != entry;
1064                         entry = (dir_cache_entry *)ubi_dlNext( entry ) ) {
1065                 if( entry->snum == snum
1066                                 && 0 == strcmp( name, entry->name )
1067                                 && 0 == strcmp( path, entry->path ) ) {
1068                         DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
1069                         return( entry->dname );
1070                 }
1071         }
1072
1073         return(NULL);
1074 }
1075
1076 /*****************************************************************************
1077  Remove all cache entries which have an snum that matches the input.
1078  Input:  snum  -
1079  Output: None.
1080 *****************************************************************************/
1081
1082 void DirCacheFlush(int snum)
1083 {
1084         dir_cache_entry *entry;
1085         ubi_dlNodePtr    next;
1086
1087         for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); 
1088             NULL != entry; )  {
1089                 next = ubi_dlNext( entry );
1090                 if( entry->snum == snum )
1091                         safe_free( ubi_dlRemThis( dir_cache, entry ) );
1092                 entry = (dir_cache_entry *)next;
1093         }
1094 }