r20844: Somewhat radical change - this may break the build (I will
[samba.git] / source3 / smbd / dir.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Directory handling routines
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /*
24    This module implements directory related functions for Samba.
25 */
26
27 extern struct current_user current_user;
28
29 /* "Special" directory offsets. */
30 #define END_OF_DIRECTORY_OFFSET ((long)-1)
31 #define START_OF_DIRECTORY_OFFSET ((long)0)
32 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
33
34 /* Make directory handle internals available. */
35
36 #define NAME_CACHE_SIZE 100
37
38 struct name_cache_entry {
39         char *name;
40         long offset;
41 };
42
43 struct smb_Dir {
44         connection_struct *conn;
45         SMB_STRUCT_DIR *dir;
46         long offset;
47         char *dir_path;
48         struct name_cache_entry *name_cache;
49         unsigned int name_cache_index;
50         unsigned int file_number;
51 };
52
53 struct dptr_struct {
54         struct dptr_struct *next, *prev;
55         int dnum;
56         uint16 spid;
57         struct connection_struct *conn;
58         struct smb_Dir *dir_hnd;
59         BOOL expect_close;
60         char *wcard;
61         uint32 attr;
62         char *path;
63         BOOL has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
64         BOOL did_stat; /* Optimisation for non-wcard searches. */
65 };
66
67 static struct bitmap *dptr_bmap;
68 static struct dptr_struct *dirptrs;
69 static int dirhandles_open = 0;
70
71 #define INVALID_DPTR_KEY (-3)
72
73 /****************************************************************************
74  Make a dir struct.
75 ****************************************************************************/
76
77 void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,uint32 mode,time_t date, BOOL uc)
78 {  
79         char *p;
80         pstring mask2;
81
82         pstrcpy(mask2,mask);
83
84         if ((mode & aDIR) != 0)
85                 size = 0;
86
87         memset(buf+1,' ',11);
88         if ((p = strchr_m(mask2,'.')) != NULL) {
89                 *p = 0;
90                 push_ascii(buf+1,mask2,8, 0);
91                 push_ascii(buf+9,p+1,3, 0);
92                 *p = '.';
93         } else
94                 push_ascii(buf+1,mask2,11, 0);
95
96         memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
97         SCVAL(buf,21,mode);
98         srv_put_dos_date(buf,22,date);
99         SSVAL(buf,26,size & 0xFFFF);
100         SSVAL(buf,28,(size >> 16)&0xFFFF);
101         /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
102            Strange, but verified on W2K3. Needed for OS/2. JRA. */
103         push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
104         DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
105 }
106
107 /****************************************************************************
108  Initialise the dir bitmap.
109 ****************************************************************************/
110
111 void init_dptrs(void)
112 {
113         static BOOL dptrs_init=False;
114
115         if (dptrs_init)
116                 return;
117
118         dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
119
120         if (!dptr_bmap)
121                 exit_server("out of memory in init_dptrs");
122
123         dptrs_init = True;
124 }
125
126 /****************************************************************************
127  Idle a dptr - the directory is closed but the control info is kept.
128 ****************************************************************************/
129
130 static void dptr_idle(struct dptr_struct *dptr)
131 {
132         if (dptr->dir_hnd) {
133                 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
134                 CloseDir(dptr->dir_hnd);
135                 dptr->dir_hnd = NULL;
136         }
137 }
138
139 /****************************************************************************
140  Idle the oldest dptr.
141 ****************************************************************************/
142
143 static void dptr_idleoldest(void)
144 {
145         struct dptr_struct *dptr;
146
147         /*
148          * Go to the end of the list.
149          */
150         for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
151                 ;
152
153         if(!dptr) {
154                 DEBUG(0,("No dptrs available to idle ?\n"));
155                 return;
156         }
157
158         /*
159          * Idle the oldest pointer.
160          */
161
162         for(; dptr; dptr = dptr->prev) {
163                 if (dptr->dir_hnd) {
164                         dptr_idle(dptr);
165                         return;
166                 }
167         }
168 }
169
170 /****************************************************************************
171  Get the struct dptr_struct for a dir index.
172 ****************************************************************************/
173
174 static struct dptr_struct *dptr_get(int key, BOOL forclose)
175 {
176         struct dptr_struct *dptr;
177
178         for(dptr = dirptrs; dptr; dptr = dptr->next) {
179                 if(dptr->dnum == key) {
180                         if (!forclose && !dptr->dir_hnd) {
181                                 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
182                                         dptr_idleoldest();
183                                 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
184                                 if (!(dptr->dir_hnd = OpenDir(dptr->conn, dptr->path, dptr->wcard, dptr->attr))) {
185                                         DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
186                                                 strerror(errno)));
187                                         return False;
188                                 }
189                         }
190                         DLIST_PROMOTE(dirptrs,dptr);
191                         return dptr;
192                 }
193         }
194         return(NULL);
195 }
196
197 /****************************************************************************
198  Get the dir path for a dir index.
199 ****************************************************************************/
200
201 char *dptr_path(int key)
202 {
203         struct dptr_struct *dptr = dptr_get(key, False);
204         if (dptr)
205                 return(dptr->path);
206         return(NULL);
207 }
208
209 /****************************************************************************
210  Get the dir wcard for a dir index.
211 ****************************************************************************/
212
213 char *dptr_wcard(int key)
214 {
215         struct dptr_struct *dptr = dptr_get(key, False);
216         if (dptr)
217                 return(dptr->wcard);
218         return(NULL);
219 }
220
221 /****************************************************************************
222  Get the dir attrib for a dir index.
223 ****************************************************************************/
224
225 uint16 dptr_attr(int key)
226 {
227         struct dptr_struct *dptr = dptr_get(key, False);
228         if (dptr)
229                 return(dptr->attr);
230         return(0);
231 }
232
233 /****************************************************************************
234  Close a dptr (internal func).
235 ****************************************************************************/
236
237 static void dptr_close_internal(struct dptr_struct *dptr)
238 {
239         DEBUG(4,("closing dptr key %d\n",dptr->dnum));
240
241         DLIST_REMOVE(dirptrs, dptr);
242
243         /* 
244          * Free the dnum in the bitmap. Remember the dnum value is always 
245          * biased by one with respect to the bitmap.
246          */
247
248         if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
249                 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
250                         dptr->dnum ));
251         }
252
253         bitmap_clear(dptr_bmap, dptr->dnum - 1);
254
255         if (dptr->dir_hnd) {
256                 CloseDir(dptr->dir_hnd);
257         }
258
259         /* Lanman 2 specific code */
260         SAFE_FREE(dptr->wcard);
261         string_set(&dptr->path,"");
262         SAFE_FREE(dptr);
263 }
264
265 /****************************************************************************
266  Close a dptr given a key.
267 ****************************************************************************/
268
269 void dptr_close(int *key)
270 {
271         struct dptr_struct *dptr;
272
273         if(*key == INVALID_DPTR_KEY)
274                 return;
275
276         /* OS/2 seems to use -1 to indicate "close all directories" */
277         if (*key == -1) {
278                 struct dptr_struct *next;
279                 for(dptr = dirptrs; dptr; dptr = next) {
280                         next = dptr->next;
281                         dptr_close_internal(dptr);
282                 }
283                 *key = INVALID_DPTR_KEY;
284                 return;
285         }
286
287         dptr = dptr_get(*key, True);
288
289         if (!dptr) {
290                 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
291                 return;
292         }
293
294         dptr_close_internal(dptr);
295
296         *key = INVALID_DPTR_KEY;
297 }
298
299 /****************************************************************************
300  Close all dptrs for a cnum.
301 ****************************************************************************/
302
303 void dptr_closecnum(connection_struct *conn)
304 {
305         struct dptr_struct *dptr, *next;
306         for(dptr = dirptrs; dptr; dptr = next) {
307                 next = dptr->next;
308                 if (dptr->conn == conn)
309                         dptr_close_internal(dptr);
310         }
311 }
312
313 /****************************************************************************
314  Idle all dptrs for a cnum.
315 ****************************************************************************/
316
317 void dptr_idlecnum(connection_struct *conn)
318 {
319         struct dptr_struct *dptr;
320         for(dptr = dirptrs; dptr; dptr = dptr->next) {
321                 if (dptr->conn == conn && dptr->dir_hnd)
322                         dptr_idle(dptr);
323         }
324 }
325
326 /****************************************************************************
327  Close a dptr that matches a given path, only if it matches the spid also.
328 ****************************************************************************/
329
330 void dptr_closepath(char *path,uint16 spid)
331 {
332         struct dptr_struct *dptr, *next;
333         for(dptr = dirptrs; dptr; dptr = next) {
334                 next = dptr->next;
335                 if (spid == dptr->spid && strequal(dptr->path,path))
336                         dptr_close_internal(dptr);
337         }
338 }
339
340 /****************************************************************************
341  Try and close the oldest handle not marked for
342  expect close in the hope that the client has
343  finished with that one.
344 ****************************************************************************/
345
346 static void dptr_close_oldest(BOOL old)
347 {
348         struct dptr_struct *dptr;
349
350         /*
351          * Go to the end of the list.
352          */
353         for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
354                 ;
355
356         if(!dptr) {
357                 DEBUG(0,("No old dptrs available to close oldest ?\n"));
358                 return;
359         }
360
361         /*
362          * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
363          * does not have expect_close set. If 'old' is false, close
364          * one of the new dnum handles.
365          */
366
367         for(; dptr; dptr = dptr->prev) {
368                 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
369                         (!old && (dptr->dnum > 255))) {
370                                 dptr_close_internal(dptr);
371                                 return;
372                 }
373         }
374 }
375
376 /****************************************************************************
377  Create a new dir ptr. If the flag old_handle is true then we must allocate
378  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
379  one byte long. If old_handle is false we allocate from the range
380  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
381  a directory handle is never zero.
382  wcard must not be zero.
383 ****************************************************************************/
384
385 NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid,
386                 const char *wcard, BOOL wcard_has_wild, uint32 attr, int *dptr_hnd_ret)
387 {
388         struct dptr_struct *dptr = NULL;
389         struct smb_Dir *dir_hnd;
390         const char *dir2;
391         NTSTATUS status;
392
393         DEBUG(5,("dptr_create dir=%s\n", path));
394
395         *dptr_hnd_ret = -1;
396
397         if (!wcard) {
398                 return NT_STATUS_INVALID_PARAMETER;
399         }
400
401         status = check_name(conn,path);
402         if (!NT_STATUS_IS_OK(status)) {
403                 return status;
404         }
405
406         /* use a const pointer from here on */
407         dir2 = path;
408         if (!*dir2)
409                 dir2 = ".";
410
411         dir_hnd = OpenDir(conn, dir2, wcard, attr);
412         if (!dir_hnd) {
413                 return map_nt_error_from_unix(errno);
414         }
415
416         string_set(&conn->dirpath,dir2);
417
418         if (dirhandles_open >= MAX_OPEN_DIRECTORIES) {
419                 dptr_idleoldest();
420         }
421
422         dptr = SMB_MALLOC_P(struct dptr_struct);
423         if(!dptr) {
424                 DEBUG(0,("malloc fail in dptr_create.\n"));
425                 CloseDir(dir_hnd);
426                 return NT_STATUS_NO_MEMORY;
427         }
428
429         ZERO_STRUCTP(dptr);
430
431         if(old_handle) {
432
433                 /*
434                  * This is an old-style SMBsearch request. Ensure the
435                  * value we return will fit in the range 1-255.
436                  */
437
438                 dptr->dnum = bitmap_find(dptr_bmap, 0);
439
440                 if(dptr->dnum == -1 || dptr->dnum > 254) {
441
442                         /*
443                          * Try and close the oldest handle not marked for
444                          * expect close in the hope that the client has
445                          * finished with that one.
446                          */
447
448                         dptr_close_oldest(True);
449
450                         /* Now try again... */
451                         dptr->dnum = bitmap_find(dptr_bmap, 0);
452                         if(dptr->dnum == -1 || dptr->dnum > 254) {
453                                 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
454                                 SAFE_FREE(dptr);
455                                 CloseDir(dir_hnd);
456                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
457                         }
458                 }
459         } else {
460
461                 /*
462                  * This is a new-style trans2 request. Allocate from
463                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
464                  */
465
466                 dptr->dnum = bitmap_find(dptr_bmap, 255);
467
468                 if(dptr->dnum == -1 || dptr->dnum < 255) {
469
470                         /*
471                          * Try and close the oldest handle close in the hope that
472                          * the client has finished with that one. This will only
473                          * happen in the case of the Win98 client bug where it leaks
474                          * directory handles.
475                          */
476
477                         dptr_close_oldest(False);
478
479                         /* Now try again... */
480                         dptr->dnum = bitmap_find(dptr_bmap, 255);
481
482                         if(dptr->dnum == -1 || dptr->dnum < 255) {
483                                 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
484                                 SAFE_FREE(dptr);
485                                 CloseDir(dir_hnd);
486                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
487                         }
488                 }
489         }
490
491         bitmap_set(dptr_bmap, dptr->dnum);
492
493         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
494
495         string_set(&dptr->path,dir2);
496         dptr->conn = conn;
497         dptr->dir_hnd = dir_hnd;
498         dptr->spid = spid;
499         dptr->expect_close = expect_close;
500         dptr->wcard = SMB_STRDUP(wcard);
501         if (!dptr->wcard) {
502                 bitmap_clear(dptr_bmap, dptr->dnum - 1);
503                 SAFE_FREE(dptr);
504                 CloseDir(dir_hnd);
505                 return NT_STATUS_NO_MEMORY;
506         }
507         if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
508                 dptr->has_wild = True;
509         } else {
510                 dptr->has_wild = wcard_has_wild;
511         }
512
513         dptr->attr = attr;
514
515         DLIST_ADD(dirptrs, dptr);
516
517         DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
518                 dptr->dnum,path,expect_close));  
519
520         conn->dirptr = dptr;
521
522         *dptr_hnd_ret = dptr->dnum;
523         return NT_STATUS_OK;
524 }
525
526
527 /****************************************************************************
528  Wrapper functions to access the lower level directory handles.
529 ****************************************************************************/
530
531 int dptr_CloseDir(struct dptr_struct *dptr)
532 {
533         return CloseDir(dptr->dir_hnd);
534 }
535
536 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
537 {
538         SeekDir(dptr->dir_hnd, offset);
539 }
540
541 long dptr_TellDir(struct dptr_struct *dptr)
542 {
543         return TellDir(dptr->dir_hnd);
544 }
545
546 BOOL dptr_has_wild(struct dptr_struct *dptr)
547 {
548         return dptr->has_wild;
549 }
550
551 /****************************************************************************
552  Return the next visible file name, skipping veto'd and invisible files.
553 ****************************************************************************/
554
555 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
556 {
557         /* Normal search for the next file. */
558         const char *name;
559         while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
560                 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
561                         return name;
562                 }
563         }
564         return NULL;
565 }
566
567 /****************************************************************************
568  Return the next visible file name, skipping veto'd and invisible files.
569 ****************************************************************************/
570
571 const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
572 {
573         SET_STAT_INVALID(*pst);
574
575         if (dptr->has_wild) {
576                 return dptr_normal_ReadDirName(dptr, poffset, pst);
577         }
578
579         /* If poffset is -1 then we know we returned this name before and we have
580            no wildcards. We're at the end of the directory. */
581         if (*poffset == END_OF_DIRECTORY_OFFSET) {
582                 return NULL;
583         }
584
585         if (!dptr->did_stat) {
586                 pstring pathreal;
587
588                 /* We know the stored wcard contains no wildcard characters. See if we can match
589                    with a stat call. If we can't, then set did_stat to true to
590                    ensure we only do this once and keep searching. */
591
592                 dptr->did_stat = True;
593
594                 /* First check if it should be visible. */
595                 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
596                         /* This only returns False if the file was found, but
597                            is explicitly not visible. Set us to end of directory,
598                            but return NULL as we know we can't ever find it. */
599                         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
600                         return NULL;
601                 }
602
603                 if (VALID_STAT(*pst)) {
604                         /* We need to set the underlying dir_hnd offset to -1 also as
605                            this function is usually called with the output from TellDir. */
606                         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
607                         return dptr->wcard;
608                 }
609
610                 pstrcpy(pathreal,dptr->path);
611                 pstrcat(pathreal,"/");
612                 pstrcat(pathreal,dptr->wcard);
613
614                 if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
615                         /* We need to set the underlying dir_hnd offset to -1 also as
616                            this function is usually called with the output from TellDir. */
617                         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
618                         return dptr->wcard;
619                 } else {
620                         /* If we get any other error than ENOENT or ENOTDIR
621                            then the file exists we just can't stat it. */
622                         if (errno != ENOENT && errno != ENOTDIR) {
623                                 /* We need to set the underlying dir_hdn offset to -1 also as
624                                    this function is usually called with the output from TellDir. */
625                                 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
626                                 return dptr->wcard;
627                         }
628                 }
629
630                 /* In case sensitive mode we don't search - we know if it doesn't exist 
631                    with a stat we will fail. */
632
633                 if (dptr->conn->case_sensitive) {
634                         /* We need to set the underlying dir_hnd offset to -1 also as
635                            this function is usually called with the output from TellDir. */
636                         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
637                         return NULL;
638                 }
639         }
640         return dptr_normal_ReadDirName(dptr, poffset, pst);
641 }
642
643 /****************************************************************************
644  Search for a file by name, skipping veto'ed and not visible files.
645 ****************************************************************************/
646
647 BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
648 {
649         SET_STAT_INVALID(*pst);
650
651         if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
652                 /* This is a singleton directory and we're already at the end. */
653                 *poffset = END_OF_DIRECTORY_OFFSET;
654                 return False;
655         }
656
657         return SearchDir(dptr->dir_hnd, name, poffset);
658 }
659
660 /****************************************************************************
661  Add the name we're returning into the underlying cache.
662 ****************************************************************************/
663
664 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
665 {
666         DirCacheAdd(dptr->dir_hnd, name, offset);
667 }
668
669 /****************************************************************************
670  Fill the 5 byte server reserved dptr field.
671 ****************************************************************************/
672
673 BOOL dptr_fill(char *buf1,unsigned int key)
674 {
675         unsigned char *buf = (unsigned char *)buf1;
676         struct dptr_struct *dptr = dptr_get(key, False);
677         uint32 offset;
678         if (!dptr) {
679                 DEBUG(1,("filling null dirptr %d\n",key));
680                 return(False);
681         }
682         offset = (uint32)TellDir(dptr->dir_hnd);
683         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
684                 (long)dptr->dir_hnd,(int)offset));
685         buf[0] = key;
686         SIVAL(buf,1,offset);
687         return(True);
688 }
689
690 /****************************************************************************
691  Fetch the dir ptr and seek it given the 5 byte server field.
692 ****************************************************************************/
693
694 struct dptr_struct *dptr_fetch(char *buf,int *num)
695 {
696         unsigned int key = *(unsigned char *)buf;
697         struct dptr_struct *dptr = dptr_get(key, False);
698         uint32 offset;
699         long seekoff;
700
701         if (!dptr) {
702                 DEBUG(3,("fetched null dirptr %d\n",key));
703                 return(NULL);
704         }
705         *num = key;
706         offset = IVAL(buf,1);
707         if (offset == (uint32)-1) {
708                 seekoff = END_OF_DIRECTORY_OFFSET;
709         } else {
710                 seekoff = (long)offset;
711         }
712         SeekDir(dptr->dir_hnd,seekoff);
713         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
714                 key,dptr_path(key),(int)seekoff));
715         return(dptr);
716 }
717
718 /****************************************************************************
719  Fetch the dir ptr.
720 ****************************************************************************/
721
722 struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
723 {
724         struct dptr_struct *dptr  = dptr_get(dptr_num, False);
725
726         if (!dptr) {
727                 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
728                 return(NULL);
729         }
730         DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
731         return(dptr);
732 }
733
734 /****************************************************************************
735  Check that a file matches a particular file type.
736 ****************************************************************************/
737
738 BOOL dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
739 {
740         uint32 mask;
741
742         /* Check the "may have" search bits. */
743         if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
744                 return False;
745
746         /* Check the "must have" bits, which are the may have bits shifted eight */
747         /* If must have bit is set, the file/dir can not be returned in search unless the matching
748                 file attribute is set */
749         mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
750         if(mask) {
751                 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask)   /* check if matching attribute present */
752                         return True;
753                 else
754                         return False;
755         }
756
757         return True;
758 }
759
760 static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
761 {
762         mangle_map(filename,True,False,conn->params);
763         return mask_match_search(filename,mask,False);
764 }
765
766 /****************************************************************************
767  Get an 8.3 directory entry.
768 ****************************************************************************/
769
770 BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fname,
771                    SMB_OFF_T *size,uint32 *mode,time_t *date,BOOL check_descend)
772 {
773         const char *dname;
774         BOOL found = False;
775         SMB_STRUCT_STAT sbuf;
776         pstring path;
777         pstring pathreal;
778         pstring filename;
779         BOOL needslash;
780
781         *path = *pathreal = *filename = 0;
782
783         needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
784
785         if (!conn->dirptr)
786                 return(False);
787
788         while (!found) {
789                 long curoff = dptr_TellDir(conn->dirptr);
790                 dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
791
792                 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
793                         (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
794       
795                 if (dname == NULL) 
796                         return(False);
797       
798                 pstrcpy(filename,dname);      
799
800                 /* notice the special *.* handling. This appears to be the only difference
801                         between the wildcard handling in this routine and in the trans2 routines.
802                         see masktest for a demo
803                 */
804                 if ((strcmp(mask,"*.*") == 0) ||
805                     mask_match_search(filename,mask,False) ||
806                     mangle_mask_match(conn,filename,mask)) {
807
808                         if (!mangle_is_8_3(filename, False, conn->params))
809                                 mangle_map(filename,True,False,
810                                            conn->params);
811
812                         pstrcpy(fname,filename);
813                         *path = 0;
814                         pstrcpy(path,conn->dirpath);
815                         if(needslash)
816                                 pstrcat(path,"/");
817                         pstrcpy(pathreal,path);
818                         pstrcat(path,fname);
819                         pstrcat(pathreal,dname);
820                         if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
821                                 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
822                                 continue;
823                         }
824           
825                         *mode = dos_mode(conn,pathreal,&sbuf);
826
827                         if (!dir_check_ftype(conn,*mode,dirtype)) {
828                                 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",filename,(unsigned int)*mode,(unsigned int)dirtype));
829                                 continue;
830                         }
831
832                         *size = sbuf.st_size;
833                         *date = sbuf.st_mtime;
834
835                         DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
836
837                         found = True;
838
839                         DirCacheAdd(conn->dirptr->dir_hnd, dname, curoff);
840                 }
841         }
842
843         return(found);
844 }
845
846 /*******************************************************************
847  Check to see if a user can read a file. This is only approximate,
848  it is used as part of the "hide unreadable" option. Don't
849  use it for anything security sensitive.
850 ********************************************************************/
851
852 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
853 {
854         SEC_DESC *psd = NULL;
855         size_t sd_size;
856         files_struct *fsp;
857         NTSTATUS status;
858         uint32 access_granted;
859
860         /*
861          * If user is a member of the Admin group
862          * we never hide files from them.
863          */
864
865         if (conn->admin_user) {
866                 return True;
867         }
868
869         /* If we can't stat it does not show it */
870         if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) {
871                 DEBUG(10,("user_can_read_file: SMB_VFS_STAT failed for file %s with error %s\n",
872                         name, strerror(errno) ));
873                 return False;
874         }
875
876         /* Pseudo-open the file (note - no fd's created). */
877
878         if(S_ISDIR(pst->st_mode)) {
879                  status = open_directory(conn, name, pst,
880                         READ_CONTROL_ACCESS,
881                         FILE_SHARE_READ|FILE_SHARE_WRITE,
882                         FILE_OPEN,
883                         0, /* no create options. */
884                         NULL, &fsp);
885         } else {
886                 status = open_file_stat(conn, name, pst, &fsp);
887         }
888
889         if (!NT_STATUS_IS_OK(status)) {
890                 return False;
891         }
892
893         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
894         sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd,
895                         (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
896         close_file(fsp, NORMAL_CLOSE);
897
898         /* No access if SD get failed. */
899         if (!sd_size) {
900                 return False;
901         }
902
903         return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
904                                  &access_granted, &status);
905 }
906
907 /*******************************************************************
908  Check to see if a user can write a file (and only files, we do not
909  check dirs on this one). This is only approximate,
910  it is used as part of the "hide unwriteable" option. Don't
911  use it for anything security sensitive.
912 ********************************************************************/
913
914 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
915 {
916         SEC_DESC *psd = NULL;
917         size_t sd_size;
918         files_struct *fsp;
919         int info;
920         NTSTATUS status;
921         uint32 access_granted;
922
923         /*
924          * If user is a member of the Admin group
925          * we never hide files from them.
926          */
927
928         if (conn->admin_user) {
929                 return True;
930         }
931
932         /* If we can't stat it does not show it */
933         if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) {
934                 return False;
935         }
936
937         /* Pseudo-open the file */
938
939         if(S_ISDIR(pst->st_mode)) {
940                 return True;
941         } else {
942                 status = open_file_ntcreate(conn, name, pst,
943                         FILE_WRITE_ATTRIBUTES,
944                         FILE_SHARE_READ|FILE_SHARE_WRITE,
945                         FILE_OPEN,
946                         0,
947                         FILE_ATTRIBUTE_NORMAL,
948                         INTERNAL_OPEN_ONLY,
949                         &info, &fsp);
950         }
951
952         if (!NT_STATUS_IS_OK(status)) {
953                 return False;
954         }
955
956         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
957         sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd,
958                         (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
959         close_file(fsp, NORMAL_CLOSE);
960
961         /* No access if SD get failed. */
962         if (!sd_size)
963                 return False;
964
965         return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
966                                  &access_granted, &status);
967 }
968
969 /*******************************************************************
970   Is a file a "special" type ?
971 ********************************************************************/
972
973 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
974 {
975         /*
976          * If user is a member of the Admin group
977          * we never hide files from them.
978          */
979
980         if (conn->admin_user)
981                 return False;
982
983         /* If we can't stat it does not show it */
984         if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
985                 return True;
986
987         if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
988                 return False;
989
990         return True;
991 }
992
993 /*******************************************************************
994  Should the file be seen by the client ?
995 ********************************************************************/
996
997 BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
998 {
999         BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
1000         BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1001         BOOL hide_special = lp_hide_special_files(SNUM(conn));
1002
1003         SET_STAT_INVALID(*pst);
1004
1005         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1006                 return True; /* . and .. are always visible. */
1007         }
1008
1009         /* If it's a vetoed file, pretend it doesn't even exist */
1010         if (use_veto && IS_VETO_PATH(conn, name)) {
1011                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1012                 return False;
1013         }
1014
1015         if (hide_unreadable || hide_unwriteable || hide_special) {
1016                 char *entry = NULL;
1017
1018                 if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
1019                         return False;
1020                 }
1021
1022                 /* If it's a dfs symlink, ignore _hide xxxx_ options */
1023                 if (lp_host_msdfs() &&
1024                                 lp_msdfs_root(SNUM(conn)) &&
1025                                         /* We get away with NULL talloc ctx here as
1026                                            we're not interested in the link contents
1027                                            so we have nothing to free. */
1028                                 is_msdfs_link(NULL, conn, entry, NULL, NULL, NULL)) {
1029                         SAFE_FREE(entry);
1030                         return True;
1031                 }
1032
1033                 /* Honour _hide unreadable_ option */
1034                 if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
1035                         DEBUG(10,("is_visible_file: file %s is unreadable.\n", entry ));
1036                         SAFE_FREE(entry);
1037                         return False;
1038                 }
1039                 /* Honour _hide unwriteable_ option */
1040                 if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
1041                         DEBUG(10,("is_visible_file: file %s is unwritable.\n", entry ));
1042                         SAFE_FREE(entry);
1043                         return False;
1044                 }
1045                 /* Honour _hide_special_ option */
1046                 if (hide_special && file_is_special(conn, entry, pst)) {
1047                         DEBUG(10,("is_visible_file: file %s is special.\n", entry ));
1048                         SAFE_FREE(entry);
1049                         return False;
1050                 }
1051                 SAFE_FREE(entry);
1052         }
1053         return True;
1054 }
1055
1056 /*******************************************************************
1057  Open a directory.
1058 ********************************************************************/
1059
1060 struct smb_Dir *OpenDir(connection_struct *conn, const char *name, const char *mask, uint32 attr)
1061 {
1062         struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
1063         if (!dirp) {
1064                 return NULL;
1065         }
1066         ZERO_STRUCTP(dirp);
1067
1068         dirp->conn = conn;
1069
1070         dirp->dir_path = SMB_STRDUP(name);
1071         if (!dirp->dir_path) {
1072                 goto fail;
1073         }
1074         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1075         if (!dirp->dir) {
1076                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
1077                 goto fail;
1078         }
1079
1080         dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
1081         if (!dirp->name_cache) {
1082                 goto fail;
1083         }
1084
1085         dirhandles_open++;
1086         return dirp;
1087
1088   fail:
1089
1090         if (dirp) {
1091                 if (dirp->dir) {
1092                         SMB_VFS_CLOSEDIR(conn,dirp->dir);
1093                 }
1094                 SAFE_FREE(dirp->dir_path);
1095                 SAFE_FREE(dirp->name_cache);
1096                 SAFE_FREE(dirp);
1097         }
1098         return NULL;
1099 }
1100
1101
1102 /*******************************************************************
1103  Close a directory.
1104 ********************************************************************/
1105
1106 int CloseDir(struct smb_Dir *dirp)
1107 {
1108         int i, ret = 0;
1109
1110         if (dirp->dir) {
1111                 ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1112         }
1113         SAFE_FREE(dirp->dir_path);
1114         if (dirp->name_cache) {
1115                 for (i = 0; i < NAME_CACHE_SIZE; i++) {
1116                         SAFE_FREE(dirp->name_cache[i].name);
1117                 }
1118         }
1119         SAFE_FREE(dirp->name_cache);
1120         SAFE_FREE(dirp);
1121         dirhandles_open--;
1122         return ret;
1123 }
1124
1125 /*******************************************************************
1126  Read from a directory. Also return current offset.
1127  Don't check for veto or invisible files.
1128 ********************************************************************/
1129
1130 const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
1131 {
1132         const char *n;
1133         connection_struct *conn = dirp->conn;
1134
1135         /* Cheat to allow . and .. to be the first entries returned. */
1136         if (((*poffset == START_OF_DIRECTORY_OFFSET) || (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2)) {
1137                 if (dirp->file_number == 0) {
1138                         n = ".";
1139                         *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1140                 } else {
1141                         *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1142                         n = "..";
1143                 }
1144                 dirp->file_number++;
1145                 return n;
1146         } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1147                 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1148                 return NULL;
1149         } else {
1150                 /* A real offset, seek to it. */
1151                 SeekDir(dirp, *poffset);
1152         }
1153
1154         while ((n = vfs_readdirname(conn, dirp->dir))) {
1155                 /* Ignore . and .. - we've already returned them. */
1156                 if (*n == '.') {
1157                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1158                                 continue;
1159                         }
1160                 }
1161                 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1162                 dirp->file_number++;
1163                 return n;
1164         }
1165         *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1166         return NULL;
1167 }
1168
1169 /*******************************************************************
1170  Rewind to the start.
1171 ********************************************************************/
1172
1173 void RewindDir(struct smb_Dir *dirp, long *poffset)
1174 {
1175         SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1176         dirp->file_number = 0;
1177         dirp->offset = START_OF_DIRECTORY_OFFSET;
1178         *poffset = START_OF_DIRECTORY_OFFSET;
1179 }
1180
1181 /*******************************************************************
1182  Seek a dir.
1183 ********************************************************************/
1184
1185 void SeekDir(struct smb_Dir *dirp, long offset)
1186 {
1187         if (offset != dirp->offset) {
1188                 if (offset == START_OF_DIRECTORY_OFFSET) {
1189                         RewindDir(dirp, &offset);
1190                         /* 
1191                          * Ok we should really set the file number here
1192                          * to 1 to enable ".." to be returned next. Trouble
1193                          * is I'm worried about callers using SeekDir(dirp,0)
1194                          * as equivalent to RewindDir(). So leave this alone
1195                          * for now.
1196                          */
1197                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
1198                         RewindDir(dirp, &offset);
1199                         /*
1200                          * Set the file number to 2 - we want to get the first
1201                          * real file entry (the one we return after "..")
1202                          * on the next ReadDir.
1203                          */
1204                         dirp->file_number = 2;
1205                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1206                         ; /* Don't seek in this case. */
1207                 } else {
1208                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1209                 }
1210                 dirp->offset = offset;
1211         }
1212 }
1213
1214 /*******************************************************************
1215  Tell a dir position.
1216 ********************************************************************/
1217
1218 long TellDir(struct smb_Dir *dirp)
1219 {
1220         return(dirp->offset);
1221 }
1222
1223 /*******************************************************************
1224  Add an entry into the dcache.
1225 ********************************************************************/
1226
1227 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1228 {
1229         struct name_cache_entry *e;
1230
1231         dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
1232         e = &dirp->name_cache[dirp->name_cache_index];
1233         SAFE_FREE(e->name);
1234         e->name = SMB_STRDUP(name);
1235         e->offset = offset;
1236 }
1237
1238 /*******************************************************************
1239  Find an entry by name. Leave us at the offset after it.
1240  Don't check for veto or invisible files.
1241 ********************************************************************/
1242
1243 BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1244 {
1245         int i;
1246         const char *entry;
1247         connection_struct *conn = dirp->conn;
1248
1249         /* Search back in the name cache. */
1250         for (i = dirp->name_cache_index; i >= 0; i--) {
1251                 struct name_cache_entry *e = &dirp->name_cache[i];
1252                 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1253                         *poffset = e->offset;
1254                         SeekDir(dirp, e->offset);
1255                         return True;
1256                 }
1257         }
1258         for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
1259                 struct name_cache_entry *e = &dirp->name_cache[i];
1260                 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1261                         *poffset = e->offset;
1262                         SeekDir(dirp, e->offset);
1263                         return True;
1264                 }
1265         }
1266
1267         /* Not found in the name cache. Rewind directory and start from scratch. */
1268         SMB_VFS_REWINDDIR(conn, dirp->dir);
1269         dirp->file_number = 0;
1270         *poffset = START_OF_DIRECTORY_OFFSET;
1271         while ((entry = ReadDirName(dirp, poffset))) {
1272                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1273                         return True;
1274                 }
1275         }
1276         return False;
1277 }