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,int 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))) {
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 Set the dir wcard for a dir index.
229 Returns 0 on ok, 1 on fail.
230 ****************************************************************************/
232 BOOL dptr_set_wcard_and_attributes(int key, const char *wcard, uint16 attr)
234 struct dptr_struct *dptr = dptr_get(key, False);
238 dptr->wcard = SMB_STRDUP(wcard);
241 if (wcard[0] == '.' && wcard[1] == 0) {
242 dptr->has_wild = True;
244 dptr->has_wild = ms_has_wild(wcard);
251 /****************************************************************************
252 Close a dptr (internal func).
253 ****************************************************************************/
255 static void dptr_close_internal(struct dptr_struct *dptr)
257 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
259 DLIST_REMOVE(dirptrs, dptr);
262 * Free the dnum in the bitmap. Remember the dnum value is always
263 * biased by one with respect to the bitmap.
266 if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
267 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
271 bitmap_clear(dptr_bmap, dptr->dnum - 1);
274 CloseDir(dptr->dir_hnd);
277 /* Lanman 2 specific code */
278 SAFE_FREE(dptr->wcard);
279 string_set(&dptr->path,"");
283 /****************************************************************************
284 Close a dptr given a key.
285 ****************************************************************************/
287 void dptr_close(int *key)
289 struct dptr_struct *dptr;
291 if(*key == INVALID_DPTR_KEY)
294 /* OS/2 seems to use -1 to indicate "close all directories" */
296 struct dptr_struct *next;
297 for(dptr = dirptrs; dptr; dptr = next) {
299 dptr_close_internal(dptr);
301 *key = INVALID_DPTR_KEY;
305 dptr = dptr_get(*key, True);
308 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
312 dptr_close_internal(dptr);
314 *key = INVALID_DPTR_KEY;
317 /****************************************************************************
318 Close all dptrs for a cnum.
319 ****************************************************************************/
321 void dptr_closecnum(connection_struct *conn)
323 struct dptr_struct *dptr, *next;
324 for(dptr = dirptrs; dptr; dptr = next) {
326 if (dptr->conn == conn)
327 dptr_close_internal(dptr);
331 /****************************************************************************
332 Idle all dptrs for a cnum.
333 ****************************************************************************/
335 void dptr_idlecnum(connection_struct *conn)
337 struct dptr_struct *dptr;
338 for(dptr = dirptrs; dptr; dptr = dptr->next) {
339 if (dptr->conn == conn && dptr->dir_hnd)
344 /****************************************************************************
345 Close a dptr that matches a given path, only if it matches the spid also.
346 ****************************************************************************/
348 void dptr_closepath(char *path,uint16 spid)
350 struct dptr_struct *dptr, *next;
351 for(dptr = dirptrs; dptr; dptr = next) {
353 if (spid == dptr->spid && strequal(dptr->path,path))
354 dptr_close_internal(dptr);
358 /****************************************************************************
359 Try and close the oldest handle not marked for
360 expect close in the hope that the client has
361 finished with that one.
362 ****************************************************************************/
364 static void dptr_close_oldest(BOOL old)
366 struct dptr_struct *dptr;
369 * Go to the end of the list.
371 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
375 DEBUG(0,("No old dptrs available to close oldest ?\n"));
380 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
381 * does not have expect_close set. If 'old' is false, close
382 * one of the new dnum handles.
385 for(; dptr; dptr = dptr->prev) {
386 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
387 (!old && (dptr->dnum > 255))) {
388 dptr_close_internal(dptr);
394 /****************************************************************************
395 Create a new dir ptr. If the flag old_handle is true then we must allocate
396 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
397 one byte long. If old_handle is false we allocate from the range
398 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
399 a directory handle is never zero.
400 ****************************************************************************/
402 int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid)
404 struct dptr_struct *dptr = NULL;
405 struct smb_Dir *dir_hnd;
408 DEBUG(5,("dptr_create dir=%s\n", path));
410 if (!check_name(path,conn))
411 return(-2); /* Code to say use a unix error return code. */
413 /* use a const pointer from here on */
418 dir_hnd = OpenDir(conn, dir2);
423 string_set(&conn->dirpath,dir2);
425 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
428 dptr = SMB_MALLOC_P(struct dptr_struct);
430 DEBUG(0,("malloc fail in dptr_create.\n"));
440 * This is an old-style SMBsearch request. Ensure the
441 * value we return will fit in the range 1-255.
444 dptr->dnum = bitmap_find(dptr_bmap, 0);
446 if(dptr->dnum == -1 || dptr->dnum > 254) {
449 * Try and close the oldest handle not marked for
450 * expect close in the hope that the client has
451 * finished with that one.
454 dptr_close_oldest(True);
456 /* Now try again... */
457 dptr->dnum = bitmap_find(dptr_bmap, 0);
458 if(dptr->dnum == -1 || dptr->dnum > 254) {
459 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
468 * This is a new-style trans2 request. Allocate from
469 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
472 dptr->dnum = bitmap_find(dptr_bmap, 255);
474 if(dptr->dnum == -1 || dptr->dnum < 255) {
477 * Try and close the oldest handle close in the hope that
478 * the client has finished with that one. This will only
479 * happen in the case of the Win98 client bug where it leaks
483 dptr_close_oldest(False);
485 /* Now try again... */
486 dptr->dnum = bitmap_find(dptr_bmap, 255);
488 if(dptr->dnum == -1 || dptr->dnum < 255) {
489 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
497 bitmap_set(dptr_bmap, dptr->dnum);
499 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
501 string_set(&dptr->path,dir2);
503 dptr->dir_hnd = dir_hnd;
505 dptr->expect_close = expect_close;
506 dptr->wcard = NULL; /* Only used in lanman2 searches */
507 dptr->attr = 0; /* Only used in lanman2 searches */
508 dptr->has_wild = True; /* Only used in lanman2 searches */
510 DLIST_ADD(dirptrs, dptr);
512 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
513 dptr->dnum,path,expect_close));
521 /****************************************************************************
522 Wrapper functions to access the lower level directory handles.
523 ****************************************************************************/
525 int dptr_CloseDir(struct dptr_struct *dptr)
527 return CloseDir(dptr->dir_hnd);
530 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
532 SeekDir(dptr->dir_hnd, offset);
535 long dptr_TellDir(struct dptr_struct *dptr)
537 return TellDir(dptr->dir_hnd);
540 /****************************************************************************
541 Return the next visible file name, skipping veto'd and invisible files.
542 ****************************************************************************/
544 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
546 /* Normal search for the next file. */
548 while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
549 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
556 /****************************************************************************
557 Return the next visible file name, skipping veto'd and invisible files.
558 ****************************************************************************/
560 const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
564 SET_STAT_INVALID(*pst);
566 if (dptr->has_wild) {
567 return dptr_normal_ReadDirName(dptr, poffset, pst);
570 /* If poffset is -1 then we know we returned this name before and we have
571 no wildcards. We're at the end of the directory. */
572 if (*poffset == -1) {
576 /* We know the stored wcard contains no wildcard characters. See if we can match
577 with a stat call. If we can't, then set has_wild to true to
578 prevent us from doing this on every call. */
580 /* First check if it should be visible. */
581 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
582 dptr->has_wild = True;
583 return dptr_normal_ReadDirName(dptr, poffset, pst);
586 if (VALID_STAT(*pst)) {
587 /* We need to set the underlying dir_hdn offset to -1 also as
588 this function is usually called with the output from TellDir. */
589 dptr->dir_hnd->offset = *poffset = -1;
593 pstrcpy(pathreal,dptr->path);
594 pstrcat(pathreal,"/");
595 pstrcat(pathreal,dptr->wcard);
597 if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
598 /* We need to set the underlying dir_hdn offset to -1 also as
599 this function is usually called with the output from TellDir. */
600 dptr->dir_hnd->offset = *poffset = -1;
603 /* If we get any other error than ENOENT or ENOTDIR
604 then the file exists we just can't stat it. */
605 if (errno != ENOENT && errno != ENOTDIR) {
606 /* We need to set the underlying dir_hdn offset to -1 also as
607 this function is usually called with the output from TellDir. */
608 dptr->dir_hnd->offset = *poffset = -1;
613 /* In case sensitive mode we don't search - we know if it doesn't exist
614 with a stat we will fail. */
616 if (dptr->conn->case_sensitive) {
617 /* We need to set the underlying dir_hdn offset to -1 also as
618 this function is usually called with the output from TellDir. */
619 dptr->dir_hnd->offset = *poffset = -1;
622 dptr->has_wild = True;
623 return dptr_normal_ReadDirName(dptr, poffset, pst);
627 /****************************************************************************
628 Search for a file by name, skipping veto'ed and not visible files.
629 ****************************************************************************/
631 BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
633 SET_STAT_INVALID(*pst);
635 if (!dptr->has_wild && (dptr->dir_hnd->offset == -1)) {
636 /* This is a singleton directory and we're already at the end. */
641 if (SearchDir(dptr->dir_hnd, name, poffset)) {
642 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
649 /****************************************************************************
650 Fill the 5 byte server reserved dptr field.
651 ****************************************************************************/
653 BOOL dptr_fill(char *buf1,unsigned int key)
655 unsigned char *buf = (unsigned char *)buf1;
656 struct dptr_struct *dptr = dptr_get(key, False);
659 DEBUG(1,("filling null dirptr %d\n",key));
662 offset = (uint32)TellDir(dptr->dir_hnd);
663 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
664 (long)dptr->dir_hnd,(int)offset));
670 /****************************************************************************
671 Fetch the dir ptr and seek it given the 5 byte server field.
672 ****************************************************************************/
674 struct dptr_struct *dptr_fetch(char *buf,int *num)
676 unsigned int key = *(unsigned char *)buf;
677 struct dptr_struct *dptr = dptr_get(key, False);
682 DEBUG(3,("fetched null dirptr %d\n",key));
686 offset = IVAL(buf,1);
687 if (offset == (uint32)-1) {
690 seekoff = (long)offset;
692 SeekDir(dptr->dir_hnd,seekoff);
693 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
694 key,dptr_path(key),(int)seekoff));
698 /****************************************************************************
700 ****************************************************************************/
702 struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
704 struct dptr_struct *dptr = dptr_get(dptr_num, False);
707 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
710 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
714 /****************************************************************************
715 Check a filetype for being valid.
716 ****************************************************************************/
718 BOOL dir_check_ftype(connection_struct *conn,int mode,int dirtype)
722 /* Check the "may have" search bits. */
723 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
726 /* Check the "must have" bits, which are the may have bits shifted eight */
727 /* If must have bit is set, the file/dir can not be returned in search unless the matching
728 file attribute is set */
729 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
731 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
740 static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
742 mangle_map(filename,True,False,SNUM(conn));
743 return mask_match_search(filename,mask,False);
746 /****************************************************************************
747 Get an 8.3 directory entry.
748 ****************************************************************************/
750 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname,
751 SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
755 SMB_STRUCT_STAT sbuf;
761 *path = *pathreal = *filename = 0;
763 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
769 long curoff = dptr_TellDir(conn->dirptr);
770 dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
772 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
773 (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
778 pstrcpy(filename,dname);
780 /* notice the special *.* handling. This appears to be the only difference
781 between the wildcard handling in this routine and in the trans2 routines.
782 see masktest for a demo
784 if ((strcmp(mask,"*.*") == 0) ||
785 mask_match_search(filename,mask,False) ||
786 mangle_mask_match(conn,filename,mask)) {
788 if (!mangle_is_8_3(filename, False, SNUM(conn)))
789 mangle_map(filename,True,False,SNUM(conn));
791 pstrcpy(fname,filename);
793 pstrcpy(path,conn->dirpath);
796 pstrcpy(pathreal,path);
798 pstrcat(pathreal,dname);
799 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
800 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
804 *mode = dos_mode(conn,pathreal,&sbuf);
806 if (!dir_check_ftype(conn,*mode,dirtype)) {
807 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
811 *size = sbuf.st_size;
812 *date = sbuf.st_mtime;
814 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
823 /*******************************************************************
824 Check to see if a user can read a file. This is only approximate,
825 it is used as part of the "hide unreadable" option. Don't
826 use it for anything security sensitive.
827 ********************************************************************/
829 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
831 SEC_DESC *psd = NULL;
836 uint32 access_granted;
839 * If user is a member of the Admin group
840 * we never hide files from them.
843 if (conn->admin_user)
846 /* If we can't stat it does not show it */
847 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
850 /* Pseudo-open the file (note - no fd's created). */
852 if(S_ISDIR(pst->st_mode))
853 fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
856 fsp = open_file_stat(conn, name, pst);
861 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
862 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
863 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
864 close_file(fsp, True);
866 /* No access if SD get failed. */
870 return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
871 &access_granted, &status);
874 /*******************************************************************
875 Check to see if a user can write a file (and only files, we do not
876 check dirs on this one). This is only approximate,
877 it is used as part of the "hide unwriteable" option. Don't
878 use it for anything security sensitive.
879 ********************************************************************/
881 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
883 SEC_DESC *psd = NULL;
889 uint32 access_granted;
892 * If user is a member of the Admin group
893 * we never hide files from them.
896 if (conn->admin_user)
899 /* If we can't stat it does not show it */
900 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
903 /* Pseudo-open the file (note - no fd's created). */
905 if(S_ISDIR(pst->st_mode))
908 fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
909 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
910 &access_mode, &smb_action);
915 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
916 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
917 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
918 close_file(fsp, False);
920 /* No access if SD get failed. */
924 return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
925 &access_granted, &status);
928 /*******************************************************************
929 Is a file a "special" type ?
930 ********************************************************************/
932 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
935 * If user is a member of the Admin group
936 * we never hide files from them.
939 if (conn->admin_user)
942 /* If we can't stat it does not show it */
943 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
946 if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
952 /*******************************************************************
953 Should the file be seen by the client ?
954 ********************************************************************/
956 BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
958 BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
959 BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
960 BOOL hide_special = lp_hide_special_files(SNUM(conn));
962 SET_STAT_INVALID(*pst);
964 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
965 return True; /* . and .. are always visible. */
968 /* If it's a vetoed file, pretend it doesn't even exist */
969 if (use_veto && IS_VETO_PATH(conn, name)) {
973 if (hide_unreadable || hide_unwriteable || hide_special) {
976 if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
979 /* Honour _hide unreadable_ option */
980 if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
984 /* Honour _hide unwriteable_ option */
985 if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
989 /* Honour _hide_special_ option */
990 if (hide_special && file_is_special(conn, entry, pst)) {
999 /*******************************************************************
1001 ********************************************************************/
1003 struct smb_Dir *OpenDir(connection_struct *conn, const char *name)
1005 struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
1013 dirp->dir_path = SMB_STRDUP(name);
1014 if (!dirp->dir_path) {
1017 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path);
1019 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
1023 dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
1024 if (!dirp->name_cache) {
1035 SMB_VFS_CLOSEDIR(conn,dirp->dir);
1037 SAFE_FREE(dirp->dir_path);
1038 SAFE_FREE(dirp->name_cache);
1045 /*******************************************************************
1047 ********************************************************************/
1049 int CloseDir(struct smb_Dir *dirp)
1054 ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1056 SAFE_FREE(dirp->dir_path);
1057 if (dirp->name_cache) {
1058 for (i = 0; i < NAME_CACHE_SIZE; i++) {
1059 SAFE_FREE(dirp->name_cache[i].name);
1062 SAFE_FREE(dirp->name_cache);
1068 /*******************************************************************
1069 Read from a directory. Also return current offset.
1070 Don't check for veto or invisible files.
1071 ********************************************************************/
1073 const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
1076 connection_struct *conn = dirp->conn;
1078 /* Cheat to allow . and .. to be the first entries returned. */
1079 if ((*poffset == 0) && (dirp->file_number < 2)) {
1080 if (dirp->file_number == 0) {
1085 dirp->file_number++;
1088 /* A real offset, seek to it. */
1089 SeekDir(dirp, *poffset);
1092 while ((n = vfs_readdirname(conn, dirp->dir))) {
1093 struct name_cache_entry *e;
1094 /* Ignore . and .. - we've already returned them. */
1096 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1100 dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1101 dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
1102 e = &dirp->name_cache[dirp->name_cache_index];
1104 e->name = SMB_STRDUP(n);
1105 *poffset = e->offset= dirp->offset;
1106 dirp->file_number++;
1113 /*******************************************************************
1115 ********************************************************************/
1117 void SeekDir(struct smb_Dir *dirp, long offset)
1119 if (offset != dirp->offset) {
1120 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1121 dirp->offset = offset;
1125 /*******************************************************************
1126 Tell a dir position.
1127 ********************************************************************/
1129 long TellDir(struct smb_Dir *dirp)
1131 return(dirp->offset);
1134 /*******************************************************************
1135 Find an entry by name. Leave us at the offset after it.
1136 Don't check for veto or invisible files.
1137 ********************************************************************/
1139 BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1143 connection_struct *conn = dirp->conn;
1145 /* Search back in the name cache. */
1146 for (i = dirp->name_cache_index; i >= 0; i--) {
1147 struct name_cache_entry *e = &dirp->name_cache[i];
1148 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1149 *poffset = e->offset;
1150 SeekDir(dirp, e->offset);
1154 for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
1155 struct name_cache_entry *e = &dirp->name_cache[i];
1156 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1157 *poffset = e->offset;
1158 SeekDir(dirp, e->offset);
1163 /* Not found in the name cache. Rewind directory and start from scratch. */
1164 SMB_VFS_REWINDDIR(conn, dirp->dir);
1165 dirp->file_number = 0;
1167 while ((entry = ReadDirName(dirp, poffset))) {
1168 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {