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.
24 This module implements directory related functions for Samba.
27 extern struct current_user current_user;
29 /* Make directory handle internals available. */
31 #define NAME_CACHE_SIZE 100
33 struct name_cache_entry {
39 connection_struct *conn;
43 struct name_cache_entry *name_cache;
44 unsigned int name_cache_index;
45 unsigned int file_number;
49 struct dptr_struct *next, *prev;
52 struct connection_struct *conn;
53 struct smb_Dir *dir_hnd;
58 BOOL has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
61 static struct bitmap *dptr_bmap;
62 static struct dptr_struct *dirptrs;
63 static int dirhandles_open = 0;
65 #define INVALID_DPTR_KEY (-3)
67 /****************************************************************************
69 ****************************************************************************/
71 void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,uint32 mode,time_t date, BOOL uc)
78 if ((mode & aDIR) != 0)
82 if ((p = strchr_m(mask2,'.')) != NULL) {
84 push_ascii(buf+1,mask2,8, 0);
85 push_ascii(buf+9,p+1,3, 0);
88 push_ascii(buf+1,mask2,11, 0);
90 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
92 put_dos_date(buf,22,date);
93 SSVAL(buf,26,size & 0xFFFF);
94 SSVAL(buf,28,(size >> 16)&0xFFFF);
95 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
96 Strange, but verified on W2K3. Needed for OS/2. JRA. */
97 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
98 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
101 /****************************************************************************
102 Initialise the dir bitmap.
103 ****************************************************************************/
105 void init_dptrs(void)
107 static BOOL dptrs_init=False;
112 dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
115 exit_server("out of memory in init_dptrs");
120 /****************************************************************************
121 Idle a dptr - the directory is closed but the control info is kept.
122 ****************************************************************************/
124 static void dptr_idle(struct dptr_struct *dptr)
127 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
128 CloseDir(dptr->dir_hnd);
129 dptr->dir_hnd = NULL;
133 /****************************************************************************
134 Idle the oldest dptr.
135 ****************************************************************************/
137 static void dptr_idleoldest(void)
139 struct dptr_struct *dptr;
142 * Go to the end of the list.
144 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
148 DEBUG(0,("No dptrs available to idle ?\n"));
153 * Idle the oldest pointer.
156 for(; dptr; dptr = dptr->prev) {
164 /****************************************************************************
165 Get the struct dptr_struct for a dir index.
166 ****************************************************************************/
168 static struct dptr_struct *dptr_get(int key, BOOL forclose)
170 struct dptr_struct *dptr;
172 for(dptr = dirptrs; dptr; dptr = dptr->next) {
173 if(dptr->dnum == key) {
174 if (!forclose && !dptr->dir_hnd) {
175 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
177 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
178 if (!(dptr->dir_hnd = OpenDir(dptr->conn, dptr->path, dptr->wcard, dptr->attr))) {
179 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
184 DLIST_PROMOTE(dirptrs,dptr);
191 /****************************************************************************
192 Get the dir path for a dir index.
193 ****************************************************************************/
195 char *dptr_path(int key)
197 struct dptr_struct *dptr = dptr_get(key, False);
203 /****************************************************************************
204 Get the dir wcard for a dir index.
205 ****************************************************************************/
207 char *dptr_wcard(int key)
209 struct dptr_struct *dptr = dptr_get(key, False);
215 /****************************************************************************
216 Get the dir attrib for a dir index.
217 ****************************************************************************/
219 uint16 dptr_attr(int key)
221 struct dptr_struct *dptr = dptr_get(key, False);
227 /****************************************************************************
228 Close a dptr (internal func).
229 ****************************************************************************/
231 static void dptr_close_internal(struct dptr_struct *dptr)
233 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
235 DLIST_REMOVE(dirptrs, dptr);
238 * Free the dnum in the bitmap. Remember the dnum value is always
239 * biased by one with respect to the bitmap.
242 if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
243 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
247 bitmap_clear(dptr_bmap, dptr->dnum - 1);
250 CloseDir(dptr->dir_hnd);
253 /* Lanman 2 specific code */
254 SAFE_FREE(dptr->wcard);
255 string_set(&dptr->path,"");
259 /****************************************************************************
260 Close a dptr given a key.
261 ****************************************************************************/
263 void dptr_close(int *key)
265 struct dptr_struct *dptr;
267 if(*key == INVALID_DPTR_KEY)
270 /* OS/2 seems to use -1 to indicate "close all directories" */
272 struct dptr_struct *next;
273 for(dptr = dirptrs; dptr; dptr = next) {
275 dptr_close_internal(dptr);
277 *key = INVALID_DPTR_KEY;
281 dptr = dptr_get(*key, True);
284 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
288 dptr_close_internal(dptr);
290 *key = INVALID_DPTR_KEY;
293 /****************************************************************************
294 Close all dptrs for a cnum.
295 ****************************************************************************/
297 void dptr_closecnum(connection_struct *conn)
299 struct dptr_struct *dptr, *next;
300 for(dptr = dirptrs; dptr; dptr = next) {
302 if (dptr->conn == conn)
303 dptr_close_internal(dptr);
307 /****************************************************************************
308 Idle all dptrs for a cnum.
309 ****************************************************************************/
311 void dptr_idlecnum(connection_struct *conn)
313 struct dptr_struct *dptr;
314 for(dptr = dirptrs; dptr; dptr = dptr->next) {
315 if (dptr->conn == conn && dptr->dir_hnd)
320 /****************************************************************************
321 Close a dptr that matches a given path, only if it matches the spid also.
322 ****************************************************************************/
324 void dptr_closepath(char *path,uint16 spid)
326 struct dptr_struct *dptr, *next;
327 for(dptr = dirptrs; dptr; dptr = next) {
329 if (spid == dptr->spid && strequal(dptr->path,path))
330 dptr_close_internal(dptr);
334 /****************************************************************************
335 Try and close the oldest handle not marked for
336 expect close in the hope that the client has
337 finished with that one.
338 ****************************************************************************/
340 static void dptr_close_oldest(BOOL old)
342 struct dptr_struct *dptr;
345 * Go to the end of the list.
347 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
351 DEBUG(0,("No old dptrs available to close oldest ?\n"));
356 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
357 * does not have expect_close set. If 'old' is false, close
358 * one of the new dnum handles.
361 for(; dptr; dptr = dptr->prev) {
362 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
363 (!old && (dptr->dnum > 255))) {
364 dptr_close_internal(dptr);
370 /****************************************************************************
371 Create a new dir ptr. If the flag old_handle is true then we must allocate
372 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
373 one byte long. If old_handle is false we allocate from the range
374 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
375 a directory handle is never zero.
376 ****************************************************************************/
378 int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid,
379 const char *wcard, uint32 attr)
381 struct dptr_struct *dptr = NULL;
382 struct smb_Dir *dir_hnd;
385 DEBUG(5,("dptr_create dir=%s\n", path));
387 if (!check_name(path,conn))
388 return(-2); /* Code to say use a unix error return code. */
390 /* use a const pointer from here on */
395 dir_hnd = OpenDir(conn, dir2, wcard, attr);
400 string_set(&conn->dirpath,dir2);
402 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
405 dptr = SMB_MALLOC_P(struct dptr_struct);
407 DEBUG(0,("malloc fail in dptr_create.\n"));
417 * This is an old-style SMBsearch request. Ensure the
418 * value we return will fit in the range 1-255.
421 dptr->dnum = bitmap_find(dptr_bmap, 0);
423 if(dptr->dnum == -1 || dptr->dnum > 254) {
426 * Try and close the oldest handle not marked for
427 * expect close in the hope that the client has
428 * finished with that one.
431 dptr_close_oldest(True);
433 /* Now try again... */
434 dptr->dnum = bitmap_find(dptr_bmap, 0);
435 if(dptr->dnum == -1 || dptr->dnum > 254) {
436 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
445 * This is a new-style trans2 request. Allocate from
446 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
449 dptr->dnum = bitmap_find(dptr_bmap, 255);
451 if(dptr->dnum == -1 || dptr->dnum < 255) {
454 * Try and close the oldest handle close in the hope that
455 * the client has finished with that one. This will only
456 * happen in the case of the Win98 client bug where it leaks
460 dptr_close_oldest(False);
462 /* Now try again... */
463 dptr->dnum = bitmap_find(dptr_bmap, 255);
465 if(dptr->dnum == -1 || dptr->dnum < 255) {
466 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
474 bitmap_set(dptr_bmap, dptr->dnum);
476 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
478 string_set(&dptr->path,dir2);
480 dptr->dir_hnd = dir_hnd;
482 dptr->expect_close = expect_close;
484 dptr->wcard = SMB_STRDUP(wcard);
486 bitmap_clear(dptr_bmap, dptr->dnum - 1);
495 if (lp_posix_pathnames() || (wcard && (wcard[0] == '.' && wcard[1] == 0))) {
496 dptr->has_wild = True;
498 dptr->has_wild = ms_has_wild(wcard);
501 DLIST_ADD(dirptrs, dptr);
503 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
504 dptr->dnum,path,expect_close));
512 /****************************************************************************
513 Wrapper functions to access the lower level directory handles.
514 ****************************************************************************/
516 int dptr_CloseDir(struct dptr_struct *dptr)
518 return CloseDir(dptr->dir_hnd);
521 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
523 SeekDir(dptr->dir_hnd, offset);
526 long dptr_TellDir(struct dptr_struct *dptr)
528 return TellDir(dptr->dir_hnd);
531 /****************************************************************************
532 Return the next visible file name, skipping veto'd and invisible files.
533 ****************************************************************************/
535 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
537 /* Normal search for the next file. */
539 while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
540 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
547 /****************************************************************************
548 Return the next visible file name, skipping veto'd and invisible files.
549 ****************************************************************************/
551 const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
555 SET_STAT_INVALID(*pst);
557 if (dptr->has_wild) {
558 return dptr_normal_ReadDirName(dptr, poffset, pst);
561 /* If poffset is -1 then we know we returned this name before and we have
562 no wildcards. We're at the end of the directory. */
563 if (*poffset == -1) {
567 /* We know the stored wcard contains no wildcard characters. See if we can match
568 with a stat call. If we can't, then set has_wild to true to
569 prevent us from doing this on every call. */
571 /* First check if it should be visible. */
572 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
573 dptr->has_wild = True;
574 return dptr_normal_ReadDirName(dptr, poffset, pst);
577 if (VALID_STAT(*pst)) {
578 /* We need to set the underlying dir_hdn offset to -1 also as
579 this function is usually called with the output from TellDir. */
580 dptr->dir_hnd->offset = *poffset = -1;
584 pstrcpy(pathreal,dptr->path);
585 pstrcat(pathreal,"/");
586 pstrcat(pathreal,dptr->wcard);
588 if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
589 /* We need to set the underlying dir_hdn offset to -1 also as
590 this function is usually called with the output from TellDir. */
591 dptr->dir_hnd->offset = *poffset = -1;
594 /* If we get any other error than ENOENT or ENOTDIR
595 then the file exists we just can't stat it. */
596 if (errno != ENOENT && errno != ENOTDIR) {
597 /* We need to set the underlying dir_hdn offset to -1 also as
598 this function is usually called with the output from TellDir. */
599 dptr->dir_hnd->offset = *poffset = -1;
604 /* In case sensitive mode we don't search - we know if it doesn't exist
605 with a stat we will fail. */
607 if (dptr->conn->case_sensitive) {
608 /* We need to set the underlying dir_hdn offset to -1 also as
609 this function is usually called with the output from TellDir. */
610 dptr->dir_hnd->offset = *poffset = -1;
613 dptr->has_wild = True;
614 return dptr_normal_ReadDirName(dptr, poffset, pst);
618 /****************************************************************************
619 Search for a file by name, skipping veto'ed and not visible files.
620 ****************************************************************************/
622 BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
624 SET_STAT_INVALID(*pst);
626 if (!dptr->has_wild && (dptr->dir_hnd->offset == -1)) {
627 /* This is a singleton directory and we're already at the end. */
632 if (SearchDir(dptr->dir_hnd, name, poffset)) {
633 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
640 /****************************************************************************
641 Fill the 5 byte server reserved dptr field.
642 ****************************************************************************/
644 BOOL dptr_fill(char *buf1,unsigned int key)
646 unsigned char *buf = (unsigned char *)buf1;
647 struct dptr_struct *dptr = dptr_get(key, False);
650 DEBUG(1,("filling null dirptr %d\n",key));
653 offset = (uint32)TellDir(dptr->dir_hnd);
654 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
655 (long)dptr->dir_hnd,(int)offset));
661 /****************************************************************************
662 Fetch the dir ptr and seek it given the 5 byte server field.
663 ****************************************************************************/
665 struct dptr_struct *dptr_fetch(char *buf,int *num)
667 unsigned int key = *(unsigned char *)buf;
668 struct dptr_struct *dptr = dptr_get(key, False);
673 DEBUG(3,("fetched null dirptr %d\n",key));
677 offset = IVAL(buf,1);
678 if (offset == (uint32)-1) {
681 seekoff = (long)offset;
683 SeekDir(dptr->dir_hnd,seekoff);
684 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
685 key,dptr_path(key),(int)seekoff));
689 /****************************************************************************
691 ****************************************************************************/
693 struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
695 struct dptr_struct *dptr = dptr_get(dptr_num, False);
698 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
701 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
705 /****************************************************************************
706 Check a filetype for being valid.
707 ****************************************************************************/
709 BOOL dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
713 /* Check the "may have" search bits. */
714 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
717 /* Check the "must have" bits, which are the may have bits shifted eight */
718 /* If must have bit is set, the file/dir can not be returned in search unless the matching
719 file attribute is set */
720 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
722 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
731 static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
733 mangle_map(filename,True,False,SNUM(conn));
734 return mask_match_search(filename,mask,False);
737 /****************************************************************************
738 Get an 8.3 directory entry.
739 ****************************************************************************/
741 BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fname,
742 SMB_OFF_T *size,uint32 *mode,time_t *date,BOOL check_descend)
746 SMB_STRUCT_STAT sbuf;
752 *path = *pathreal = *filename = 0;
754 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
760 long curoff = dptr_TellDir(conn->dirptr);
761 dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
763 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
764 (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
769 pstrcpy(filename,dname);
771 /* notice the special *.* handling. This appears to be the only difference
772 between the wildcard handling in this routine and in the trans2 routines.
773 see masktest for a demo
775 if ((strcmp(mask,"*.*") == 0) ||
776 mask_match_search(filename,mask,False) ||
777 mangle_mask_match(conn,filename,mask)) {
779 if (!mangle_is_8_3(filename, False, SNUM(conn)))
780 mangle_map(filename,True,False,SNUM(conn));
782 pstrcpy(fname,filename);
784 pstrcpy(path,conn->dirpath);
787 pstrcpy(pathreal,path);
789 pstrcat(pathreal,dname);
790 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
791 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
795 *mode = dos_mode(conn,pathreal,&sbuf);
797 if (!dir_check_ftype(conn,*mode,dirtype)) {
798 DEBUG(5,("[%s] attribs didn't match %x\n",filename,(unsigned int)dirtype));
802 *size = sbuf.st_size;
803 *date = sbuf.st_mtime;
805 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
814 /*******************************************************************
815 Check to see if a user can read a file. This is only approximate,
816 it is used as part of the "hide unreadable" option. Don't
817 use it for anything security sensitive.
818 ********************************************************************/
820 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
822 SEC_DESC *psd = NULL;
827 uint32 access_granted;
830 * If user is a member of the Admin group
831 * we never hide files from them.
834 if (conn->admin_user)
837 /* If we can't stat it does not show it */
838 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
841 /* Pseudo-open the file (note - no fd's created). */
843 if(S_ISDIR(pst->st_mode))
844 fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
847 fsp = open_file_stat(conn, name, pst);
852 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
853 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
854 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
855 close_file(fsp, True);
857 /* No access if SD get failed. */
861 return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
862 &access_granted, &status);
865 /*******************************************************************
866 Check to see if a user can write a file (and only files, we do not
867 check dirs on this one). This is only approximate,
868 it is used as part of the "hide unwriteable" option. Don't
869 use it for anything security sensitive.
870 ********************************************************************/
872 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
874 SEC_DESC *psd = NULL;
880 uint32 access_granted;
883 * If user is a member of the Admin group
884 * we never hide files from them.
887 if (conn->admin_user)
890 /* If we can't stat it does not show it */
891 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
894 /* Pseudo-open the file (note - no fd's created). */
896 if(S_ISDIR(pst->st_mode))
899 fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
900 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
901 &access_mode, &smb_action);
906 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
907 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
908 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
909 close_file(fsp, False);
911 /* No access if SD get failed. */
915 return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
916 &access_granted, &status);
919 /*******************************************************************
920 Is a file a "special" type ?
921 ********************************************************************/
923 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
926 * If user is a member of the Admin group
927 * we never hide files from them.
930 if (conn->admin_user)
933 /* If we can't stat it does not show it */
934 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
937 if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
943 /*******************************************************************
944 Should the file be seen by the client ?
945 ********************************************************************/
947 BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
949 BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
950 BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
951 BOOL hide_special = lp_hide_special_files(SNUM(conn));
953 SET_STAT_INVALID(*pst);
955 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
956 return True; /* . and .. are always visible. */
959 /* If it's a vetoed file, pretend it doesn't even exist */
960 if (use_veto && IS_VETO_PATH(conn, name)) {
964 if (hide_unreadable || hide_unwriteable || hide_special) {
967 if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
970 /* Honour _hide unreadable_ option */
971 if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
975 /* Honour _hide unwriteable_ option */
976 if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
980 /* Honour _hide_special_ option */
981 if (hide_special && file_is_special(conn, entry, pst)) {
990 /*******************************************************************
992 ********************************************************************/
994 struct smb_Dir *OpenDir(connection_struct *conn, const char *name, const char *mask, uint32 attr)
996 struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
1004 dirp->dir_path = SMB_STRDUP(name);
1005 if (!dirp->dir_path) {
1008 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1010 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
1014 dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
1015 if (!dirp->name_cache) {
1026 SMB_VFS_CLOSEDIR(conn,dirp->dir);
1028 SAFE_FREE(dirp->dir_path);
1029 SAFE_FREE(dirp->name_cache);
1036 /*******************************************************************
1038 ********************************************************************/
1040 int CloseDir(struct smb_Dir *dirp)
1045 ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1047 SAFE_FREE(dirp->dir_path);
1048 if (dirp->name_cache) {
1049 for (i = 0; i < NAME_CACHE_SIZE; i++) {
1050 SAFE_FREE(dirp->name_cache[i].name);
1053 SAFE_FREE(dirp->name_cache);
1059 /*******************************************************************
1060 Read from a directory. Also return current offset.
1061 Don't check for veto or invisible files.
1062 ********************************************************************/
1064 const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
1067 connection_struct *conn = dirp->conn;
1069 /* Cheat to allow . and .. to be the first entries returned. */
1070 if ((*poffset == 0) && (dirp->file_number < 2)) {
1071 if (dirp->file_number == 0) {
1076 dirp->file_number++;
1079 /* A real offset, seek to it. */
1080 SeekDir(dirp, *poffset);
1083 while ((n = vfs_readdirname(conn, dirp->dir))) {
1084 struct name_cache_entry *e;
1085 /* Ignore . and .. - we've already returned them. */
1087 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1091 dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1092 dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
1093 e = &dirp->name_cache[dirp->name_cache_index];
1095 e->name = SMB_STRDUP(n);
1096 *poffset = e->offset= dirp->offset;
1097 dirp->file_number++;
1104 /*******************************************************************
1105 Rewind to the start.
1106 ********************************************************************/
1108 void RewindDir(struct smb_Dir *dirp, long *poffset)
1110 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1111 dirp->file_number = 0;
1116 /*******************************************************************
1118 ********************************************************************/
1120 void SeekDir(struct smb_Dir *dirp, long offset)
1122 if (offset != dirp->offset) {
1124 RewindDir(dirp, &offset);
1126 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1128 dirp->offset = offset;
1132 /*******************************************************************
1133 Tell a dir position.
1134 ********************************************************************/
1136 long TellDir(struct smb_Dir *dirp)
1138 return(dirp->offset);
1141 /*******************************************************************
1142 Find an entry by name. Leave us at the offset after it.
1143 Don't check for veto or invisible files.
1144 ********************************************************************/
1146 BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1150 connection_struct *conn = dirp->conn;
1152 /* Search back in the name cache. */
1153 for (i = dirp->name_cache_index; i >= 0; i--) {
1154 struct name_cache_entry *e = &dirp->name_cache[i];
1155 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1156 *poffset = e->offset;
1157 SeekDir(dirp, e->offset);
1161 for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
1162 struct name_cache_entry *e = &dirp->name_cache[i];
1163 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1164 *poffset = e->offset;
1165 SeekDir(dirp, e->offset);
1170 /* Not found in the name cache. Rewind directory and start from scratch. */
1171 SMB_VFS_REWINDDIR(conn, dirp->dir);
1172 dirp->file_number = 0;
1174 while ((entry = ReadDirName(dirp, poffset))) {
1175 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {