r8689: Fixes bugid #2889 for sure. Turns out the OS/2 dos box doesn't like two offsets
[Samba/nascimento.git] / source3 / smbd / dir.c
bloba0df924dc7ce9796f3656642b452de901abc1eeb
1 /*
2 Unix SMB/CIFS implementation.
3 Directory handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
21 #include "includes.h"
24 This module implements directory related functions for Samba.
27 extern struct current_user current_user;
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)
34 /* Make directory handle internals available. */
36 #define NAME_CACHE_SIZE 100
38 struct name_cache_entry {
39 char *name;
40 long offset;
43 struct smb_Dir {
44 connection_struct *conn;
45 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;
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. */
66 static struct bitmap *dptr_bmap;
67 static struct dptr_struct *dirptrs;
68 static int dirhandles_open = 0;
70 #define INVALID_DPTR_KEY (-3)
72 /****************************************************************************
73 Make a dir struct.
74 ****************************************************************************/
76 void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,uint32 mode,time_t date, BOOL uc)
78 char *p;
79 pstring mask2;
81 pstrcpy(mask2,mask);
83 if ((mode & aDIR) != 0)
84 size = 0;
86 memset(buf+1,' ',11);
87 if ((p = strchr_m(mask2,'.')) != NULL) {
88 *p = 0;
89 push_ascii(buf+1,mask2,8, 0);
90 push_ascii(buf+9,p+1,3, 0);
91 *p = '.';
92 } else
93 push_ascii(buf+1,mask2,11, 0);
95 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
96 SCVAL(buf,21,mode);
97 put_dos_date(buf,22,date);
98 SSVAL(buf,26,size & 0xFFFF);
99 SSVAL(buf,28,(size >> 16)&0xFFFF);
100 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
101 Strange, but verified on W2K3. Needed for OS/2. JRA. */
102 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
103 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
106 /****************************************************************************
107 Initialise the dir bitmap.
108 ****************************************************************************/
110 void init_dptrs(void)
112 static BOOL dptrs_init=False;
114 if (dptrs_init)
115 return;
117 dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
119 if (!dptr_bmap)
120 exit_server("out of memory in init_dptrs");
122 dptrs_init = True;
125 /****************************************************************************
126 Idle a dptr - the directory is closed but the control info is kept.
127 ****************************************************************************/
129 static void dptr_idle(struct dptr_struct *dptr)
131 if (dptr->dir_hnd) {
132 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
133 CloseDir(dptr->dir_hnd);
134 dptr->dir_hnd = NULL;
138 /****************************************************************************
139 Idle the oldest dptr.
140 ****************************************************************************/
142 static void dptr_idleoldest(void)
144 struct dptr_struct *dptr;
147 * Go to the end of the list.
149 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
152 if(!dptr) {
153 DEBUG(0,("No dptrs available to idle ?\n"));
154 return;
158 * Idle the oldest pointer.
161 for(; dptr; dptr = dptr->prev) {
162 if (dptr->dir_hnd) {
163 dptr_idle(dptr);
164 return;
169 /****************************************************************************
170 Get the struct dptr_struct for a dir index.
171 ****************************************************************************/
173 static struct dptr_struct *dptr_get(int key, BOOL forclose)
175 struct dptr_struct *dptr;
177 for(dptr = dirptrs; dptr; dptr = dptr->next) {
178 if(dptr->dnum == key) {
179 if (!forclose && !dptr->dir_hnd) {
180 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
181 dptr_idleoldest();
182 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
183 if (!(dptr->dir_hnd = OpenDir(dptr->conn, dptr->path, dptr->wcard, dptr->attr))) {
184 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
185 strerror(errno)));
186 return False;
189 DLIST_PROMOTE(dirptrs,dptr);
190 return dptr;
193 return(NULL);
196 /****************************************************************************
197 Get the dir path for a dir index.
198 ****************************************************************************/
200 char *dptr_path(int key)
202 struct dptr_struct *dptr = dptr_get(key, False);
203 if (dptr)
204 return(dptr->path);
205 return(NULL);
208 /****************************************************************************
209 Get the dir wcard for a dir index.
210 ****************************************************************************/
212 char *dptr_wcard(int key)
214 struct dptr_struct *dptr = dptr_get(key, False);
215 if (dptr)
216 return(dptr->wcard);
217 return(NULL);
220 /****************************************************************************
221 Get the dir attrib for a dir index.
222 ****************************************************************************/
224 uint16 dptr_attr(int key)
226 struct dptr_struct *dptr = dptr_get(key, False);
227 if (dptr)
228 return(dptr->attr);
229 return(0);
232 /****************************************************************************
233 Close a dptr (internal func).
234 ****************************************************************************/
236 static void dptr_close_internal(struct dptr_struct *dptr)
238 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
240 DLIST_REMOVE(dirptrs, dptr);
243 * Free the dnum in the bitmap. Remember the dnum value is always
244 * biased by one with respect to the bitmap.
247 if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
248 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
249 dptr->dnum ));
252 bitmap_clear(dptr_bmap, dptr->dnum - 1);
254 if (dptr->dir_hnd) {
255 CloseDir(dptr->dir_hnd);
258 /* Lanman 2 specific code */
259 SAFE_FREE(dptr->wcard);
260 string_set(&dptr->path,"");
261 SAFE_FREE(dptr);
264 /****************************************************************************
265 Close a dptr given a key.
266 ****************************************************************************/
268 void dptr_close(int *key)
270 struct dptr_struct *dptr;
272 if(*key == INVALID_DPTR_KEY)
273 return;
275 /* OS/2 seems to use -1 to indicate "close all directories" */
276 if (*key == -1) {
277 struct dptr_struct *next;
278 for(dptr = dirptrs; dptr; dptr = next) {
279 next = dptr->next;
280 dptr_close_internal(dptr);
282 *key = INVALID_DPTR_KEY;
283 return;
286 dptr = dptr_get(*key, True);
288 if (!dptr) {
289 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
290 return;
293 dptr_close_internal(dptr);
295 *key = INVALID_DPTR_KEY;
298 /****************************************************************************
299 Close all dptrs for a cnum.
300 ****************************************************************************/
302 void dptr_closecnum(connection_struct *conn)
304 struct dptr_struct *dptr, *next;
305 for(dptr = dirptrs; dptr; dptr = next) {
306 next = dptr->next;
307 if (dptr->conn == conn)
308 dptr_close_internal(dptr);
312 /****************************************************************************
313 Idle all dptrs for a cnum.
314 ****************************************************************************/
316 void dptr_idlecnum(connection_struct *conn)
318 struct dptr_struct *dptr;
319 for(dptr = dirptrs; dptr; dptr = dptr->next) {
320 if (dptr->conn == conn && dptr->dir_hnd)
321 dptr_idle(dptr);
325 /****************************************************************************
326 Close a dptr that matches a given path, only if it matches the spid also.
327 ****************************************************************************/
329 void dptr_closepath(char *path,uint16 spid)
331 struct dptr_struct *dptr, *next;
332 for(dptr = dirptrs; dptr; dptr = next) {
333 next = dptr->next;
334 if (spid == dptr->spid && strequal(dptr->path,path))
335 dptr_close_internal(dptr);
339 /****************************************************************************
340 Try and close the oldest handle not marked for
341 expect close in the hope that the client has
342 finished with that one.
343 ****************************************************************************/
345 static void dptr_close_oldest(BOOL old)
347 struct dptr_struct *dptr;
350 * Go to the end of the list.
352 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
355 if(!dptr) {
356 DEBUG(0,("No old dptrs available to close oldest ?\n"));
357 return;
361 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
362 * does not have expect_close set. If 'old' is false, close
363 * one of the new dnum handles.
366 for(; dptr; dptr = dptr->prev) {
367 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
368 (!old && (dptr->dnum > 255))) {
369 dptr_close_internal(dptr);
370 return;
375 /****************************************************************************
376 Create a new dir ptr. If the flag old_handle is true then we must allocate
377 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
378 one byte long. If old_handle is false we allocate from the range
379 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
380 a directory handle is never zero.
381 ****************************************************************************/
383 int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid,
384 const char *wcard, uint32 attr)
386 struct dptr_struct *dptr = NULL;
387 struct smb_Dir *dir_hnd;
388 const char *dir2;
390 DEBUG(5,("dptr_create dir=%s\n", path));
392 if (!check_name(path,conn))
393 return(-2); /* Code to say use a unix error return code. */
395 /* use a const pointer from here on */
396 dir2 = path;
397 if (!*dir2)
398 dir2 = ".";
400 dir_hnd = OpenDir(conn, dir2, wcard, attr);
401 if (!dir_hnd) {
402 return (-2);
405 string_set(&conn->dirpath,dir2);
407 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
408 dptr_idleoldest();
410 dptr = SMB_MALLOC_P(struct dptr_struct);
411 if(!dptr) {
412 DEBUG(0,("malloc fail in dptr_create.\n"));
413 CloseDir(dir_hnd);
414 return -1;
417 ZERO_STRUCTP(dptr);
419 if(old_handle) {
422 * This is an old-style SMBsearch request. Ensure the
423 * value we return will fit in the range 1-255.
426 dptr->dnum = bitmap_find(dptr_bmap, 0);
428 if(dptr->dnum == -1 || dptr->dnum > 254) {
431 * Try and close the oldest handle not marked for
432 * expect close in the hope that the client has
433 * finished with that one.
436 dptr_close_oldest(True);
438 /* Now try again... */
439 dptr->dnum = bitmap_find(dptr_bmap, 0);
440 if(dptr->dnum == -1 || dptr->dnum > 254) {
441 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
442 SAFE_FREE(dptr);
443 CloseDir(dir_hnd);
444 return -1;
447 } else {
450 * This is a new-style trans2 request. Allocate from
451 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
454 dptr->dnum = bitmap_find(dptr_bmap, 255);
456 if(dptr->dnum == -1 || dptr->dnum < 255) {
459 * Try and close the oldest handle close in the hope that
460 * the client has finished with that one. This will only
461 * happen in the case of the Win98 client bug where it leaks
462 * directory handles.
465 dptr_close_oldest(False);
467 /* Now try again... */
468 dptr->dnum = bitmap_find(dptr_bmap, 255);
470 if(dptr->dnum == -1 || dptr->dnum < 255) {
471 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
472 SAFE_FREE(dptr);
473 CloseDir(dir_hnd);
474 return -1;
479 bitmap_set(dptr_bmap, dptr->dnum);
481 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
483 string_set(&dptr->path,dir2);
484 dptr->conn = conn;
485 dptr->dir_hnd = dir_hnd;
486 dptr->spid = spid;
487 dptr->expect_close = expect_close;
488 if (wcard) {
489 dptr->wcard = SMB_STRDUP(wcard);
490 if (!dptr->wcard) {
491 bitmap_clear(dptr_bmap, dptr->dnum - 1);
492 SAFE_FREE(dptr);
493 CloseDir(dir_hnd);
494 return -1;
496 } else {
497 dptr->wcard = NULL;
499 dptr->attr = attr;
500 if (lp_posix_pathnames() || (wcard && (wcard[0] == '.' && wcard[1] == 0))) {
501 dptr->has_wild = True;
502 } else {
503 dptr->has_wild = ms_has_wild(wcard);
506 DLIST_ADD(dirptrs, dptr);
508 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
509 dptr->dnum,path,expect_close));
511 conn->dirptr = dptr;
513 return(dptr->dnum);
517 /****************************************************************************
518 Wrapper functions to access the lower level directory handles.
519 ****************************************************************************/
521 int dptr_CloseDir(struct dptr_struct *dptr)
523 return CloseDir(dptr->dir_hnd);
526 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
528 SeekDir(dptr->dir_hnd, offset);
531 long dptr_TellDir(struct dptr_struct *dptr)
533 return TellDir(dptr->dir_hnd);
536 /****************************************************************************
537 Return the next visible file name, skipping veto'd and invisible files.
538 ****************************************************************************/
540 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
542 /* Normal search for the next file. */
543 const char *name;
544 while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
545 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
546 return name;
549 return NULL;
552 /****************************************************************************
553 Return the next visible file name, skipping veto'd and invisible files.
554 ****************************************************************************/
556 const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
558 pstring pathreal;
560 SET_STAT_INVALID(*pst);
562 if (dptr->has_wild) {
563 return dptr_normal_ReadDirName(dptr, poffset, pst);
566 /* If poffset is -1 then we know we returned this name before and we have
567 no wildcards. We're at the end of the directory. */
568 if (*poffset == END_OF_DIRECTORY_OFFSET) {
569 return NULL;
572 /* We know the stored wcard contains no wildcard characters. See if we can match
573 with a stat call. If we can't, then set has_wild to true to
574 prevent us from doing this on every call. */
576 /* First check if it should be visible. */
577 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
578 dptr->has_wild = True;
579 return dptr_normal_ReadDirName(dptr, poffset, pst);
582 if (VALID_STAT(*pst)) {
583 /* We need to set the underlying dir_hdn offset to -1 also as
584 this function is usually called with the output from TellDir. */
585 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
586 return dptr->wcard;
589 pstrcpy(pathreal,dptr->path);
590 pstrcat(pathreal,"/");
591 pstrcat(pathreal,dptr->wcard);
593 if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
594 /* We need to set the underlying dir_hdn offset to -1 also as
595 this function is usually called with the output from TellDir. */
596 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
597 return dptr->wcard;
598 } else {
599 /* If we get any other error than ENOENT or ENOTDIR
600 then the file exists we just can't stat it. */
601 if (errno != ENOENT && errno != ENOTDIR) {
602 /* We need to set the underlying dir_hdn offset to -1 also as
603 this function is usually called with the output from TellDir. */
604 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
605 return dptr->wcard;
609 /* In case sensitive mode we don't search - we know if it doesn't exist
610 with a stat we will fail. */
612 if (dptr->conn->case_sensitive) {
613 /* We need to set the underlying dir_hdn offset to -1 also as
614 this function is usually called with the output from TellDir. */
615 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
616 return NULL;
617 } else {
618 dptr->has_wild = True;
619 return dptr_normal_ReadDirName(dptr, poffset, pst);
623 /****************************************************************************
624 Search for a file by name, skipping veto'ed and not visible files.
625 ****************************************************************************/
627 BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
629 SET_STAT_INVALID(*pst);
631 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
632 /* This is a singleton directory and we're already at the end. */
633 *poffset = END_OF_DIRECTORY_OFFSET;
634 return False;
637 if (SearchDir(dptr->dir_hnd, name, poffset)) {
638 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
639 return True;
642 return False;
645 /****************************************************************************
646 Fill the 5 byte server reserved dptr field.
647 ****************************************************************************/
649 BOOL dptr_fill(char *buf1,unsigned int key)
651 unsigned char *buf = (unsigned char *)buf1;
652 struct dptr_struct *dptr = dptr_get(key, False);
653 uint32 offset;
654 if (!dptr) {
655 DEBUG(1,("filling null dirptr %d\n",key));
656 return(False);
658 offset = (uint32)TellDir(dptr->dir_hnd);
659 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
660 (long)dptr->dir_hnd,(int)offset));
661 buf[0] = key;
662 SIVAL(buf,1,offset);
663 return(True);
666 /****************************************************************************
667 Fetch the dir ptr and seek it given the 5 byte server field.
668 ****************************************************************************/
670 struct dptr_struct *dptr_fetch(char *buf,int *num)
672 unsigned int key = *(unsigned char *)buf;
673 struct dptr_struct *dptr = dptr_get(key, False);
674 uint32 offset;
675 long seekoff;
677 if (!dptr) {
678 DEBUG(3,("fetched null dirptr %d\n",key));
679 return(NULL);
681 *num = key;
682 offset = IVAL(buf,1);
683 if (offset == (uint32)-1) {
684 seekoff = END_OF_DIRECTORY_OFFSET;
685 } else {
686 seekoff = (long)offset;
688 SeekDir(dptr->dir_hnd,seekoff);
689 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
690 key,dptr_path(key),(int)seekoff));
691 return(dptr);
694 /****************************************************************************
695 Fetch the dir ptr.
696 ****************************************************************************/
698 struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
700 struct dptr_struct *dptr = dptr_get(dptr_num, False);
702 if (!dptr) {
703 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
704 return(NULL);
706 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
707 return(dptr);
710 /****************************************************************************
711 Check a filetype for being valid.
712 ****************************************************************************/
714 BOOL dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
716 uint32 mask;
718 /* Check the "may have" search bits. */
719 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
720 return False;
722 /* Check the "must have" bits, which are the may have bits shifted eight */
723 /* If must have bit is set, the file/dir can not be returned in search unless the matching
724 file attribute is set */
725 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
726 if(mask) {
727 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
728 return True;
729 else
730 return False;
733 return True;
736 static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
738 mangle_map(filename,True,False,SNUM(conn));
739 return mask_match_search(filename,mask,False);
742 /****************************************************************************
743 Get an 8.3 directory entry.
744 ****************************************************************************/
746 BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fname,
747 SMB_OFF_T *size,uint32 *mode,time_t *date,BOOL check_descend)
749 const char *dname;
750 BOOL found = False;
751 SMB_STRUCT_STAT sbuf;
752 pstring path;
753 pstring pathreal;
754 pstring filename;
755 BOOL needslash;
757 *path = *pathreal = *filename = 0;
759 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
761 if (!conn->dirptr)
762 return(False);
764 while (!found) {
765 long curoff = dptr_TellDir(conn->dirptr);
766 dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
768 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
769 (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
771 if (dname == NULL)
772 return(False);
774 pstrcpy(filename,dname);
776 /* notice the special *.* handling. This appears to be the only difference
777 between the wildcard handling in this routine and in the trans2 routines.
778 see masktest for a demo
780 if ((strcmp(mask,"*.*") == 0) ||
781 mask_match_search(filename,mask,False) ||
782 mangle_mask_match(conn,filename,mask)) {
784 if (!mangle_is_8_3(filename, False, SNUM(conn)))
785 mangle_map(filename,True,False,SNUM(conn));
787 pstrcpy(fname,filename);
788 *path = 0;
789 pstrcpy(path,conn->dirpath);
790 if(needslash)
791 pstrcat(path,"/");
792 pstrcpy(pathreal,path);
793 pstrcat(path,fname);
794 pstrcat(pathreal,dname);
795 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
796 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
797 continue;
800 *mode = dos_mode(conn,pathreal,&sbuf);
802 if (!dir_check_ftype(conn,*mode,dirtype)) {
803 DEBUG(5,("[%s] attribs didn't match %x\n",filename,(unsigned int)dirtype));
804 continue;
807 *size = sbuf.st_size;
808 *date = sbuf.st_mtime;
810 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
812 found = True;
816 return(found);
819 /*******************************************************************
820 Check to see if a user can read a file. This is only approximate,
821 it is used as part of the "hide unreadable" option. Don't
822 use it for anything security sensitive.
823 ********************************************************************/
825 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
827 SEC_DESC *psd = NULL;
828 size_t sd_size;
829 files_struct *fsp;
830 NTSTATUS status;
831 uint32 access_granted;
834 * If user is a member of the Admin group
835 * we never hide files from them.
838 if (conn->admin_user) {
839 return True;
842 /* If we can't stat it does not show it */
843 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) {
844 return False;
847 /* Pseudo-open the file (note - no fd's created). */
849 if(S_ISDIR(pst->st_mode)) {
850 fsp = open_directory(conn, name, pst,
851 READ_CONTROL_ACCESS,
852 FILE_SHARE_READ|FILE_SHARE_WRITE,
853 FILE_OPEN,
854 0, /* no create options. */
855 NULL);
856 } else {
857 fsp = open_file_stat(conn, name, pst);
860 if (!fsp) {
861 return False;
864 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
865 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd,
866 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
867 close_file(fsp, True);
869 /* No access if SD get failed. */
870 if (!sd_size) {
871 return False;
874 return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
875 &access_granted, &status);
878 /*******************************************************************
879 Check to see if a user can write a file (and only files, we do not
880 check dirs on this one). This is only approximate,
881 it is used as part of the "hide unwriteable" option. Don't
882 use it for anything security sensitive.
883 ********************************************************************/
885 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
887 SEC_DESC *psd = NULL;
888 size_t sd_size;
889 files_struct *fsp;
890 int info;
891 NTSTATUS status;
892 uint32 access_granted;
895 * If user is a member of the Admin group
896 * we never hide files from them.
899 if (conn->admin_user) {
900 return True;
903 /* If we can't stat it does not show it */
904 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) {
905 return False;
908 /* Pseudo-open the file */
910 if(S_ISDIR(pst->st_mode)) {
911 return True;
912 } else {
913 fsp = open_file_ntcreate(conn, name, pst,
914 FILE_WRITE_ATTRIBUTES,
915 FILE_SHARE_READ|FILE_SHARE_WRITE,
916 FILE_OPEN,
918 FILE_ATTRIBUTE_NORMAL,
919 INTERNAL_OPEN_ONLY,
920 &info);
923 if (!fsp) {
924 return False;
927 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
928 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd,
929 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
930 close_file(fsp, False);
932 /* No access if SD get failed. */
933 if (!sd_size)
934 return False;
936 return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
937 &access_granted, &status);
940 /*******************************************************************
941 Is a file a "special" type ?
942 ********************************************************************/
944 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
947 * If user is a member of the Admin group
948 * we never hide files from them.
951 if (conn->admin_user)
952 return False;
954 /* If we can't stat it does not show it */
955 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
956 return True;
958 if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
959 return False;
961 return True;
964 /*******************************************************************
965 Should the file be seen by the client ?
966 ********************************************************************/
968 BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
970 BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
971 BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
972 BOOL hide_special = lp_hide_special_files(SNUM(conn));
974 SET_STAT_INVALID(*pst);
976 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
977 return True; /* . and .. are always visible. */
980 /* If it's a vetoed file, pretend it doesn't even exist */
981 if (use_veto && IS_VETO_PATH(conn, name)) {
982 return False;
985 if (hide_unreadable || hide_unwriteable || hide_special) {
986 char *entry = NULL;
988 if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
989 return False;
991 /* Honour _hide unreadable_ option */
992 if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
993 SAFE_FREE(entry);
994 return False;
996 /* Honour _hide unwriteable_ option */
997 if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
998 SAFE_FREE(entry);
999 return False;
1001 /* Honour _hide_special_ option */
1002 if (hide_special && file_is_special(conn, entry, pst)) {
1003 SAFE_FREE(entry);
1004 return False;
1006 SAFE_FREE(entry);
1008 return True;
1011 /*******************************************************************
1012 Open a directory.
1013 ********************************************************************/
1015 struct smb_Dir *OpenDir(connection_struct *conn, const char *name, const char *mask, uint32 attr)
1017 struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
1018 if (!dirp) {
1019 return NULL;
1021 ZERO_STRUCTP(dirp);
1023 dirp->conn = conn;
1025 dirp->dir_path = SMB_STRDUP(name);
1026 if (!dirp->dir_path) {
1027 goto fail;
1029 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1030 if (!dirp->dir) {
1031 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
1032 goto fail;
1035 dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
1036 if (!dirp->name_cache) {
1037 goto fail;
1040 dirhandles_open++;
1041 return dirp;
1043 fail:
1045 if (dirp) {
1046 if (dirp->dir) {
1047 SMB_VFS_CLOSEDIR(conn,dirp->dir);
1049 SAFE_FREE(dirp->dir_path);
1050 SAFE_FREE(dirp->name_cache);
1051 SAFE_FREE(dirp);
1053 return NULL;
1057 /*******************************************************************
1058 Close a directory.
1059 ********************************************************************/
1061 int CloseDir(struct smb_Dir *dirp)
1063 int i, ret = 0;
1065 if (dirp->dir) {
1066 ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1068 SAFE_FREE(dirp->dir_path);
1069 if (dirp->name_cache) {
1070 for (i = 0; i < NAME_CACHE_SIZE; i++) {
1071 SAFE_FREE(dirp->name_cache[i].name);
1074 SAFE_FREE(dirp->name_cache);
1075 SAFE_FREE(dirp);
1076 dirhandles_open--;
1077 return ret;
1080 /*******************************************************************
1081 Read from a directory. Also return current offset.
1082 Don't check for veto or invisible files.
1083 ********************************************************************/
1085 const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
1087 const char *n;
1088 connection_struct *conn = dirp->conn;
1090 /* Cheat to allow . and .. to be the first entries returned. */
1091 if (((*poffset == START_OF_DIRECTORY_OFFSET) || (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2)) {
1092 if (dirp->file_number == 0) {
1093 n = ".";
1094 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1095 } else {
1096 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1097 n = "..";
1099 dirp->file_number++;
1100 return n;
1101 } else {
1102 /* A real offset, seek to it. */
1103 SeekDir(dirp, *poffset);
1106 while ((n = vfs_readdirname(conn, dirp->dir))) {
1107 struct name_cache_entry *e;
1108 /* Ignore . and .. - we've already returned them. */
1109 if (*n == '.') {
1110 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1111 continue;
1114 dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1115 dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
1116 e = &dirp->name_cache[dirp->name_cache_index];
1117 SAFE_FREE(e->name);
1118 e->name = SMB_STRDUP(n);
1119 *poffset = e->offset= dirp->offset;
1120 dirp->file_number++;
1121 return e->name;
1123 dirp->offset = END_OF_DIRECTORY_OFFSET;
1124 return NULL;
1127 /*******************************************************************
1128 Rewind to the start.
1129 ********************************************************************/
1131 void RewindDir(struct smb_Dir *dirp, long *poffset)
1133 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1134 dirp->file_number = 0;
1135 dirp->offset = START_OF_DIRECTORY_OFFSET;
1136 *poffset = START_OF_DIRECTORY_OFFSET;
1139 /*******************************************************************
1140 Seek a dir.
1141 ********************************************************************/
1143 void SeekDir(struct smb_Dir *dirp, long offset)
1145 if (offset != dirp->offset) {
1146 if (offset == START_OF_DIRECTORY_OFFSET || offset == DOT_DOT_DIRECTORY_OFFSET) {
1147 RewindDir(dirp, &offset);
1148 } else {
1149 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1151 dirp->offset = offset;
1155 /*******************************************************************
1156 Tell a dir position.
1157 ********************************************************************/
1159 long TellDir(struct smb_Dir *dirp)
1161 return(dirp->offset);
1164 /*******************************************************************
1165 Find an entry by name. Leave us at the offset after it.
1166 Don't check for veto or invisible files.
1167 ********************************************************************/
1169 BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1171 int i;
1172 const char *entry;
1173 connection_struct *conn = dirp->conn;
1175 /* Search back in the name cache. */
1176 for (i = dirp->name_cache_index; i >= 0; i--) {
1177 struct name_cache_entry *e = &dirp->name_cache[i];
1178 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1179 *poffset = e->offset;
1180 SeekDir(dirp, e->offset);
1181 return True;
1184 for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
1185 struct name_cache_entry *e = &dirp->name_cache[i];
1186 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1187 *poffset = e->offset;
1188 SeekDir(dirp, e->offset);
1189 return True;
1193 /* Not found in the name cache. Rewind directory and start from scratch. */
1194 SMB_VFS_REWINDDIR(conn, dirp->dir);
1195 dirp->file_number = 0;
1196 *poffset = START_OF_DIRECTORY_OFFSET;
1197 while ((entry = ReadDirName(dirp, poffset))) {
1198 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1199 return True;
1202 return False;