r5096: Attempt to fix the build
[sfrench/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 = SMB_MALLOC_P(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, fstring 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, pstring fname,
592                    SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
593 {
594         const 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                 long curoff = TellDir(conn->dirptr);
616                 dname = ReadDirName(conn->dirptr, &curoff);
617
618                 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
619                         (long)conn->dirptr,TellDir(conn->dirptr)));
620       
621                 if (dname == NULL) 
622                         return(False);
623       
624                 pstrcpy(filename,dname);      
625
626                 /* notice the special *.* handling. This appears to be the only difference
627                         between the wildcard handling in this routine and in the trans2 routines.
628                         see masktest for a demo
629                 */
630                 if ((strcmp(mask,"*.*") == 0) ||
631                     mask_match(filename,mask,False) ||
632                     mangle_mask_match(conn,filename,mask)) {
633                         if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
634                                 continue;
635
636                         if (!mangle_is_8_3(filename, False))
637                                 mangle_map(filename,True,False,SNUM(conn));
638
639                         pstrcpy(fname,filename);
640                         *path = 0;
641                         pstrcpy(path,conn->dirpath);
642                         if(needslash)
643                                 pstrcat(path,"/");
644                         pstrcpy(pathreal,path);
645                         pstrcat(path,fname);
646                         pstrcat(pathreal,dname);
647                         if (SMB_VFS_STAT(conn, pathreal, &sbuf) != 0) {
648                                 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
649                                 continue;
650                         }
651           
652                         *mode = dos_mode(conn,pathreal,&sbuf);
653
654                         if (!dir_check_ftype(conn,*mode,&sbuf,dirtype)) {
655                                 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
656                                 continue;
657                         }
658
659                         *size = sbuf.st_size;
660                         *date = sbuf.st_mtime;
661
662                         DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
663
664                         found = True;
665                 }
666         }
667
668         return(found);
669 }
670
671 /*******************************************************************
672  Check to see if a user can read a file. This is only approximate,
673  it is used as part of the "hide unreadable" option. Don't
674  use it for anything security sensitive.
675 ********************************************************************/
676
677 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
678 {
679         extern struct current_user current_user;
680         SEC_DESC *psd = NULL;
681         size_t sd_size;
682         files_struct *fsp;
683         int smb_action;
684         NTSTATUS status;
685         uint32 access_granted;
686
687         /*
688          * If user is a member of the Admin group
689          * we never hide files from them.
690          */
691
692         if (conn->admin_user)
693                 return True;
694
695         /* If we can't stat it does not show it */
696         if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
697                 return False;
698
699         /* Pseudo-open the file (note - no fd's created). */
700
701         if(S_ISDIR(pst->st_mode))       
702                  fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
703                         &smb_action);
704         else
705                 fsp = open_file_stat(conn, name, pst);
706
707         if (!fsp)
708                 return False;
709
710         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
711         sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
712                         (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
713         close_file(fsp, True);
714
715         /* No access if SD get failed. */
716         if (!sd_size)
717                 return False;
718
719         return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
720                                  &access_granted, &status);
721 }
722
723 /*******************************************************************
724  Check to see if a user can write a file (and only files, we do not
725  check dirs on this one). This is only approximate,
726  it is used as part of the "hide unwriteable" option. Don't
727  use it for anything security sensitive.
728 ********************************************************************/
729
730 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
731 {
732         extern struct current_user current_user;
733         SEC_DESC *psd = NULL;
734         size_t sd_size;
735         files_struct *fsp;
736         int smb_action;
737         int access_mode;
738         NTSTATUS status;
739         uint32 access_granted;
740
741         /*
742          * If user is a member of the Admin group
743          * we never hide files from them.
744          */
745
746         if (conn->admin_user)
747                 return True;
748
749         /* If we can't stat it does not show it */
750         if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
751                 return False;
752
753         /* Pseudo-open the file (note - no fd's created). */
754
755         if(S_ISDIR(pst->st_mode))       
756                 return True;
757         else
758                 fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
759                         (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
760                         &access_mode, &smb_action);
761
762         if (!fsp)
763                 return False;
764
765         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
766         sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
767                         (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
768         close_file(fsp, False);
769
770         /* No access if SD get failed. */
771         if (!sd_size)
772                 return False;
773
774         return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
775                                  &access_granted, &status);
776 }
777
778 /*******************************************************************
779   Is a file a "special" type ?
780 ********************************************************************/
781
782 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
783 {
784         /*
785          * If user is a member of the Admin group
786          * we never hide files from them.
787          */
788
789         if (conn->admin_user)
790                 return False;
791
792         /* If we can't stat it does not show it */
793         if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
794                 return True;
795
796         if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
797                 return False;
798
799         return True;
800 }
801
802 #define NAME_CACHE_SIZE 100
803
804 struct name_cache_entry {
805         char *name;
806         long offset;
807 };
808
809 typedef struct {
810         connection_struct *conn;
811         DIR *dir;
812         long offset;
813         char *dir_path;
814         struct name_cache_entry *name_cache;
815         unsigned int name_cache_index;
816         BOOL hide_unreadable;
817         BOOL hide_unwriteable;
818         BOOL hide_special;
819         BOOL use_veto;
820         BOOL finished;
821 } Dir;
822
823 /*******************************************************************
824  Open a directory.
825 ********************************************************************/
826
827 void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto)
828 {
829         Dir *dirp = SMB_MALLOC_P(Dir);
830         if (!dirp) {
831                 return NULL;
832         }
833         ZERO_STRUCTP(dirp);
834
835         dirp->conn = conn;
836         dirp->use_veto = use_veto;
837
838         dirp->dir_path = SMB_STRDUP(name);
839         if (!dirp->dir_path) {
840                 goto fail;
841         }
842         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path);
843         if (!dirp->dir) {
844                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
845                 goto fail;
846         }
847
848         dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
849         if (!dirp->name_cache) {
850                 goto fail;
851         }
852
853         dirp->hide_unreadable = lp_hideunreadable(SNUM(conn));
854         dirp->hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
855         dirp->hide_special = lp_hide_special_files(SNUM(conn));
856
857         return((void *)dirp);
858
859   fail:
860
861         if (dirp) {
862                 if (dirp->dir) {
863                         SMB_VFS_CLOSEDIR(conn,dirp->dir);
864                 }
865                 SAFE_FREE(dirp->dir_path);
866                 SAFE_FREE(dirp->name_cache);
867                 SAFE_FREE(dirp);
868         }
869         return NULL;
870 }
871
872
873 /*******************************************************************
874  Close a directory.
875 ********************************************************************/
876
877 int CloseDir(void *p)
878 {
879         int i, ret = 0;
880         Dir *dirp = (Dir *)p;
881
882         if (dirp->dir) {
883                 ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
884         }
885         SAFE_FREE(dirp->dir_path);
886         if (dirp->name_cache) {
887                 for (i = 0; i < NAME_CACHE_SIZE; i++) {
888                         SAFE_FREE(dirp->name_cache[i].name);
889                 }
890         }
891         SAFE_FREE(dirp->name_cache);
892         SAFE_FREE(dirp);
893         return ret;
894 }
895
896 /*******************************************************************
897  Set a directory into an inactive state.
898 ********************************************************************/
899
900 static void SleepDir(Dir *dirp)
901 {
902         if (dirp->dir) {
903                 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
904                 dirp->dir = 0;
905         }
906         dirp->offset = 0;
907 }
908
909 /*******************************************************************
910  Wake a directory into a known state.
911 ********************************************************************/
912
913 static int WakeDir(Dir *dirp, long offset)
914 {
915         if (!dirp->dir) {
916                 dirp->dir = SMB_VFS_OPENDIR(dirp->conn, dirp->dir_path);
917                 if (!dirp->dir) {
918                         DEBUG(0,("WakeDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
919                         dirp->finished = True;
920                         return -1;
921                 }
922         }
923         if (offset != dirp->offset) {
924                 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
925                 dirp->offset = SMB_VFS_TELLDIR(dirp->conn, dirp->dir);
926                 if (dirp->offset != offset) {
927                         DEBUG(0,("WakeDir: in path %s. offset changed %ld -> %ld\n",
928                                 dirp->dir_path, offset, dirp->offset ));
929                         return -1;
930                 }
931         }
932         return 0;
933 }
934
935 /*******************************************************************
936  Read from a directory. Also return current offset.
937 ********************************************************************/
938
939 const char *ReadDirName(void *p, long *poffset)
940 {
941         const char *n;
942         Dir *dirp = (Dir *)p;
943         connection_struct *conn = dirp->conn;
944
945         if (WakeDir(dirp, *poffset) == -1) {
946                 return NULL;
947         }
948
949         while ((n = vfs_readdirname(conn, dirp->dir))) {
950                 struct name_cache_entry *e;
951
952                 if (!((strcmp(".",n) == 0) || (strcmp("..",n) == 0))) {
953                         /* If it's a vetoed file, pretend it doesn't even exist */
954                         if (dirp->use_veto && IS_VETO_PATH(conn, n)) {
955                                 continue;
956                         }
957
958                         if (dirp->hide_unreadable || dirp->hide_unwriteable || dirp->hide_special) {
959                                 SMB_STRUCT_STAT st;
960                                 char *entry = NULL;
961                                 ZERO_STRUCT(st);
962
963                                 if (asprintf(&entry, "%s/%s/%s", conn->origpath, dirp->dir_path, n) == -1) {
964                                         return NULL;
965                                 }
966                                 /* Honour _hide unreadable_ option */
967                                 if (dirp->hide_unreadable && !user_can_read_file(conn, entry, &st)) {
968                                         SAFE_FREE(entry);
969                                         continue;
970                                 }
971                                 /* Honour _hide unwriteable_ option */
972                                 if (dirp->hide_unwriteable && !user_can_write_file(conn, entry, &st)) {
973                                         SAFE_FREE(entry);
974                                         continue;
975                                 }
976                                 /* Honour _hide_special_ option */
977                                 if (dirp->hide_special && !file_is_special(conn, entry, &st)) {
978                                         SAFE_FREE(entry);
979                                         continue;
980                                 }
981                                 SAFE_FREE(entry);
982                         }
983                 }
984
985                 dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
986                 if (dirp->offset == -1) {
987                         return NULL;
988                 }
989                 dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
990
991                 e = &dirp->name_cache[dirp->name_cache_index];
992                 SAFE_FREE(e->name);
993                 e->name = SMB_STRDUP(n);
994                 *poffset = e->offset= dirp->offset;
995                 return e->name;
996         }
997
998         dirp->finished = True;
999         SleepDir(dirp);
1000         return NULL;
1001 }
1002
1003 /*******************************************************************
1004  Seek a dir.
1005 ********************************************************************/
1006
1007 BOOL SeekDir(void *p,long offset)
1008 {
1009         Dir *dirp = (Dir *)p;
1010         return (WakeDir(dirp, offset) != -1);
1011 }
1012
1013 /*******************************************************************
1014  Tell a dir position.
1015 ********************************************************************/
1016
1017 long TellDir(void *p)
1018 {
1019         Dir *dirp = (Dir *)p;
1020         return(dirp->offset);
1021 }
1022
1023 /*******************************************************************
1024  Find an entry by name. Leave us at the offset after it.
1025 ********************************************************************/
1026
1027 BOOL SearchDir(void *p, const char *name, long *poffset, BOOL case_sensitive)
1028 {
1029         int i;
1030         Dir *dirp = (Dir *)p;
1031         const char *entry;
1032         connection_struct *conn = dirp->conn;
1033
1034         /* Re-create dir but don't seek. */
1035         if (WakeDir(dirp, dirp->offset) == -1) {
1036                 return False;
1037         }
1038
1039         /* Search back in the name cache. */
1040         for (i = dirp->name_cache_index; i >= 0; i--) {
1041                 struct name_cache_entry *e = &dirp->name_cache[i];
1042                 if (e->name && (case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1043                         *poffset = e->offset;
1044                         WakeDir(dirp, e->offset);
1045                         return True;
1046                 }
1047         }
1048         for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
1049                 struct name_cache_entry *e = &dirp->name_cache[i];
1050                 if (e->name && (case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1051                         *poffset = e->offset;
1052                         WakeDir(dirp, e->offset);
1053                         return True;
1054                 }
1055         }
1056
1057         /* Not found in the name cache. Rewind directory and start from scratch. */
1058         SMB_VFS_REWINDDIR(conn, dirp->dir);
1059         *poffset = 0;
1060         while ((entry = ReadDirName(dirp, poffset))) {
1061                 if (case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1062                         return True;
1063                 }
1064         }
1065
1066         SleepDir(dirp);
1067         return False;
1068 }