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;
48 struct dptr_struct *next, *prev;
51 struct connection_struct *conn;
52 struct smb_Dir *dir_hnd;
57 BOOL has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
60 static struct bitmap *dptr_bmap;
61 static struct dptr_struct *dirptrs;
62 static int dirhandles_open = 0;
64 #define INVALID_DPTR_KEY (-3)
66 /****************************************************************************
67 Initialise the dir bitmap.
68 ****************************************************************************/
72 static BOOL dptrs_init=False;
77 dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
80 exit_server("out of memory in init_dptrs");
85 /****************************************************************************
86 Idle a dptr - the directory is closed but the control info is kept.
87 ****************************************************************************/
89 static void dptr_idle(struct dptr_struct *dptr)
92 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
93 CloseDir(dptr->dir_hnd);
98 /****************************************************************************
100 ****************************************************************************/
102 static void dptr_idleoldest(void)
104 struct dptr_struct *dptr;
107 * Go to the end of the list.
109 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
113 DEBUG(0,("No dptrs available to idle ?\n"));
118 * Idle the oldest pointer.
121 for(; dptr; dptr = dptr->prev) {
129 /****************************************************************************
130 Get the struct dptr_struct for a dir index.
131 ****************************************************************************/
133 static struct dptr_struct *dptr_get(int key, BOOL forclose)
135 struct dptr_struct *dptr;
137 for(dptr = dirptrs; dptr; dptr = dptr->next) {
138 if(dptr->dnum == key) {
139 if (!forclose && !dptr->dir_hnd) {
140 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
142 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
143 if (!(dptr->dir_hnd = OpenDir(dptr->conn, dptr->path))) {
144 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
149 DLIST_PROMOTE(dirptrs,dptr);
156 /****************************************************************************
157 Get the dir path for a dir index.
158 ****************************************************************************/
160 char *dptr_path(int key)
162 struct dptr_struct *dptr = dptr_get(key, False);
168 /****************************************************************************
169 Get the dir wcard for a dir index.
170 ****************************************************************************/
172 char *dptr_wcard(int key)
174 struct dptr_struct *dptr = dptr_get(key, False);
180 /****************************************************************************
181 Get the dir attrib for a dir index.
182 ****************************************************************************/
184 uint16 dptr_attr(int key)
186 struct dptr_struct *dptr = dptr_get(key, False);
192 /****************************************************************************
193 Set the dir wcard for a dir index.
194 Returns 0 on ok, 1 on fail.
195 ****************************************************************************/
197 BOOL dptr_set_wcard_and_attributes(int key, const char *wcard, uint16 attr)
199 struct dptr_struct *dptr = dptr_get(key, False);
203 dptr->wcard = SMB_STRDUP(wcard);
206 if (wcard[0] == '.' && wcard[1] == 0) {
207 dptr->has_wild = True;
209 dptr->has_wild = ms_has_wild(wcard);
216 /****************************************************************************
217 Close a dptr (internal func).
218 ****************************************************************************/
220 static void dptr_close_internal(struct dptr_struct *dptr)
222 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
224 DLIST_REMOVE(dirptrs, dptr);
227 * Free the dnum in the bitmap. Remember the dnum value is always
228 * biased by one with respect to the bitmap.
231 if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
232 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
236 bitmap_clear(dptr_bmap, dptr->dnum - 1);
239 CloseDir(dptr->dir_hnd);
242 /* Lanman 2 specific code */
243 SAFE_FREE(dptr->wcard);
244 string_set(&dptr->path,"");
248 /****************************************************************************
249 Close a dptr given a key.
250 ****************************************************************************/
252 void dptr_close(int *key)
254 struct dptr_struct *dptr;
256 if(*key == INVALID_DPTR_KEY)
259 /* OS/2 seems to use -1 to indicate "close all directories" */
261 struct dptr_struct *next;
262 for(dptr = dirptrs; dptr; dptr = next) {
264 dptr_close_internal(dptr);
266 *key = INVALID_DPTR_KEY;
270 dptr = dptr_get(*key, True);
273 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
277 dptr_close_internal(dptr);
279 *key = INVALID_DPTR_KEY;
282 /****************************************************************************
283 Close all dptrs for a cnum.
284 ****************************************************************************/
286 void dptr_closecnum(connection_struct *conn)
288 struct dptr_struct *dptr, *next;
289 for(dptr = dirptrs; dptr; dptr = next) {
291 if (dptr->conn == conn)
292 dptr_close_internal(dptr);
296 /****************************************************************************
297 Idle all dptrs for a cnum.
298 ****************************************************************************/
300 void dptr_idlecnum(connection_struct *conn)
302 struct dptr_struct *dptr;
303 for(dptr = dirptrs; dptr; dptr = dptr->next) {
304 if (dptr->conn == conn && dptr->dir_hnd)
309 /****************************************************************************
310 Close a dptr that matches a given path, only if it matches the spid also.
311 ****************************************************************************/
313 void dptr_closepath(char *path,uint16 spid)
315 struct dptr_struct *dptr, *next;
316 for(dptr = dirptrs; dptr; dptr = next) {
318 if (spid == dptr->spid && strequal(dptr->path,path))
319 dptr_close_internal(dptr);
323 /****************************************************************************
324 Try and close the oldest handle not marked for
325 expect close in the hope that the client has
326 finished with that one.
327 ****************************************************************************/
329 static void dptr_close_oldest(BOOL old)
331 struct dptr_struct *dptr;
334 * Go to the end of the list.
336 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
340 DEBUG(0,("No old dptrs available to close oldest ?\n"));
345 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
346 * does not have expect_close set. If 'old' is false, close
347 * one of the new dnum handles.
350 for(; dptr; dptr = dptr->prev) {
351 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
352 (!old && (dptr->dnum > 255))) {
353 dptr_close_internal(dptr);
359 /****************************************************************************
360 Create a new dir ptr. If the flag old_handle is true then we must allocate
361 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
362 one byte long. If old_handle is false we allocate from the range
363 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
364 a directory handle is never zero.
365 ****************************************************************************/
367 int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid)
369 struct dptr_struct *dptr = NULL;
370 struct smb_Dir *dir_hnd;
373 DEBUG(5,("dptr_create dir=%s\n", path));
375 if (!check_name(path,conn))
376 return(-2); /* Code to say use a unix error return code. */
378 /* use a const pointer from here on */
383 dir_hnd = OpenDir(conn, dir2);
388 string_set(&conn->dirpath,dir2);
390 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
393 dptr = SMB_MALLOC_P(struct dptr_struct);
395 DEBUG(0,("malloc fail in dptr_create.\n"));
405 * This is an old-style SMBsearch request. Ensure the
406 * value we return will fit in the range 1-255.
409 dptr->dnum = bitmap_find(dptr_bmap, 0);
411 if(dptr->dnum == -1 || dptr->dnum > 254) {
414 * Try and close the oldest handle not marked for
415 * expect close in the hope that the client has
416 * finished with that one.
419 dptr_close_oldest(True);
421 /* Now try again... */
422 dptr->dnum = bitmap_find(dptr_bmap, 0);
423 if(dptr->dnum == -1 || dptr->dnum > 254) {
424 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
433 * This is a new-style trans2 request. Allocate from
434 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
437 dptr->dnum = bitmap_find(dptr_bmap, 255);
439 if(dptr->dnum == -1 || dptr->dnum < 255) {
442 * Try and close the oldest handle close in the hope that
443 * the client has finished with that one. This will only
444 * happen in the case of the Win98 client bug where it leaks
448 dptr_close_oldest(False);
450 /* Now try again... */
451 dptr->dnum = bitmap_find(dptr_bmap, 255);
453 if(dptr->dnum == -1 || dptr->dnum < 255) {
454 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
462 bitmap_set(dptr_bmap, dptr->dnum);
464 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
466 string_set(&dptr->path,dir2);
468 dptr->dir_hnd = dir_hnd;
470 dptr->expect_close = expect_close;
471 dptr->wcard = NULL; /* Only used in lanman2 searches */
472 dptr->attr = 0; /* Only used in lanman2 searches */
473 dptr->has_wild = True; /* Only used in lanman2 searches */
475 DLIST_ADD(dirptrs, dptr);
477 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
478 dptr->dnum,path,expect_close));
486 /****************************************************************************
487 Wrapper functions to access the lower level directory handles.
488 ****************************************************************************/
490 int dptr_CloseDir(struct dptr_struct *dptr)
492 return CloseDir(dptr->dir_hnd);
495 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
497 SeekDir(dptr->dir_hnd, offset);
500 long dptr_TellDir(struct dptr_struct *dptr)
502 return TellDir(dptr->dir_hnd);
505 /****************************************************************************
506 Return the next visible file name, skipping veto'd and invisible files.
507 ****************************************************************************/
509 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
511 /* Normal search for the next file. */
513 while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
514 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
521 /****************************************************************************
522 Return the next visible file name, skipping veto'd and invisible files.
523 ****************************************************************************/
525 const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
531 if (dptr->has_wild) {
532 return dptr_normal_ReadDirName(dptr, poffset, pst);
535 /* If poffset is -1 then we know we returned this name before and we have
536 no wildcards. We're at the end of the directory. */
537 if (*poffset == -1) {
541 /* We know the stored wcard contains no wildcard characters. See if we can match
542 with a stat call. If we can't, then set has_wild to true to
543 prevent us from doing this on every call. */
545 /* First check if it should be visible. */
546 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
547 dptr->has_wild = True;
548 return dptr_normal_ReadDirName(dptr, poffset, pst);
551 if (VALID_STAT(*pst)) {
552 /* We need to set the underlying dir_hdn offset to -1 also as
553 this function is usually called with the output from TellDir. */
554 dptr->dir_hnd->offset = *poffset = -1;
558 pstrcpy(pathreal,dptr->path);
559 pstrcat(pathreal,"/");
560 pstrcat(pathreal,dptr->wcard);
562 if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
563 /* We need to set the underlying dir_hdn offset to -1 also as
564 this function is usually called with the output from TellDir. */
565 dptr->dir_hnd->offset = *poffset = -1;
568 /* If we get any other error than ENOENT or ENOTDIR
569 then the file exists we just can't stat it. */
570 if (errno != ENOENT && errno != ENOTDIR) {
571 /* We need to set the underlying dir_hdn offset to -1 also as
572 this function is usually called with the output from TellDir. */
573 dptr->dir_hnd->offset = *poffset = -1;
578 /* In case sensitive mode we don't search - we know if it doesn't exist
579 with a stat we will fail. */
581 if (dptr->conn->case_sensitive) {
582 /* We need to set the underlying dir_hdn offset to -1 also as
583 this function is usually called with the output from TellDir. */
584 dptr->dir_hnd->offset = *poffset = -1;
587 dptr->has_wild = True;
588 return dptr_normal_ReadDirName(dptr, poffset, pst);
592 /****************************************************************************
593 Search for a file by name, skipping veto'ed and not visible files.
594 ****************************************************************************/
596 BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
600 if (!dptr->has_wild && (dptr->dir_hnd->offset == -1)) {
601 /* This is a singleton directory and we're already at the end. */
606 if (SearchDir(dptr->dir_hnd, name, poffset)) {
607 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
614 /****************************************************************************
615 Fill the 5 byte server reserved dptr field.
616 ****************************************************************************/
618 BOOL dptr_fill(char *buf1,unsigned int key)
620 unsigned char *buf = (unsigned char *)buf1;
621 struct dptr_struct *dptr = dptr_get(key, False);
624 DEBUG(1,("filling null dirptr %d\n",key));
627 offset = TellDir(dptr->dir_hnd);
628 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
629 (long)dptr->dir_hnd,(int)offset));
631 SIVAL(buf,1,offset | DPTR_MASK);
635 /****************************************************************************
636 Fetch the dir ptr and seek it given the 5 byte server field.
637 ****************************************************************************/
639 struct dptr_struct *dptr_fetch(char *buf,int *num)
641 unsigned int key = *(unsigned char *)buf;
642 struct dptr_struct *dptr = dptr_get(key, False);
646 DEBUG(3,("fetched null dirptr %d\n",key));
650 offset = IVAL(buf,1)&~DPTR_MASK;
651 SeekDir(dptr->dir_hnd,(long)offset);
652 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
653 key,dptr_path(key),offset));
657 /****************************************************************************
659 ****************************************************************************/
661 struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
663 struct dptr_struct *dptr = dptr_get(dptr_num, False);
666 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
669 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
673 /****************************************************************************
674 Check a filetype for being valid.
675 ****************************************************************************/
677 BOOL dir_check_ftype(connection_struct *conn,int mode,int dirtype)
681 /* Check the "may have" search bits. */
682 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
685 /* Check the "must have" bits, which are the may have bits shifted eight */
686 /* If must have bit is set, the file/dir can not be returned in search unless the matching
687 file attribute is set */
688 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
690 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
699 static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
701 mangle_map(filename,True,False,SNUM(conn));
702 return mask_match_search(filename,mask,False);
705 /****************************************************************************
706 Get an 8.3 directory entry.
707 ****************************************************************************/
709 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname,
710 SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
714 SMB_STRUCT_STAT sbuf;
720 *path = *pathreal = *filename = 0;
722 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
728 long curoff = dptr_TellDir(conn->dirptr);
729 dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
731 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
732 (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
737 pstrcpy(filename,dname);
739 /* notice the special *.* handling. This appears to be the only difference
740 between the wildcard handling in this routine and in the trans2 routines.
741 see masktest for a demo
743 if ((strcmp(mask,"*.*") == 0) ||
744 mask_match_search(filename,mask,False) ||
745 mangle_mask_match(conn,filename,mask)) {
747 if (!mangle_is_8_3(filename, False))
748 mangle_map(filename,True,False,SNUM(conn));
750 pstrcpy(fname,filename);
752 pstrcpy(path,conn->dirpath);
755 pstrcpy(pathreal,path);
757 pstrcat(pathreal,dname);
758 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
759 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
763 *mode = dos_mode(conn,pathreal,&sbuf);
765 if (!dir_check_ftype(conn,*mode,dirtype)) {
766 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
770 *size = sbuf.st_size;
771 *date = sbuf.st_mtime;
773 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
782 /*******************************************************************
783 Check to see if a user can read a file. This is only approximate,
784 it is used as part of the "hide unreadable" option. Don't
785 use it for anything security sensitive.
786 ********************************************************************/
788 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
790 SEC_DESC *psd = NULL;
795 uint32 access_granted;
798 * If user is a member of the Admin group
799 * we never hide files from them.
802 if (conn->admin_user)
805 /* If we can't stat it does not show it */
806 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
809 /* Pseudo-open the file (note - no fd's created). */
811 if(S_ISDIR(pst->st_mode))
812 fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
815 fsp = open_file_stat(conn, name, pst);
820 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
821 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
822 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
823 close_file(fsp, True);
825 /* No access if SD get failed. */
829 return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
830 &access_granted, &status);
833 /*******************************************************************
834 Check to see if a user can write a file (and only files, we do not
835 check dirs on this one). This is only approximate,
836 it is used as part of the "hide unwriteable" option. Don't
837 use it for anything security sensitive.
838 ********************************************************************/
840 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
842 SEC_DESC *psd = NULL;
848 uint32 access_granted;
851 * If user is a member of the Admin group
852 * we never hide files from them.
855 if (conn->admin_user)
858 /* If we can't stat it does not show it */
859 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
862 /* Pseudo-open the file (note - no fd's created). */
864 if(S_ISDIR(pst->st_mode))
867 fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
868 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
869 &access_mode, &smb_action);
874 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
875 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
876 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
877 close_file(fsp, False);
879 /* No access if SD get failed. */
883 return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
884 &access_granted, &status);
887 /*******************************************************************
888 Is a file a "special" type ?
889 ********************************************************************/
891 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
894 * If user is a member of the Admin group
895 * we never hide files from them.
898 if (conn->admin_user)
901 /* If we can't stat it does not show it */
902 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
905 if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
911 /*******************************************************************
912 Should the file be seen by the client ?
913 ********************************************************************/
915 BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
917 BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
918 BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
919 BOOL hide_special = lp_hide_special_files(SNUM(conn));
923 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
924 return True; /* . and .. are always visible. */
927 /* If it's a vetoed file, pretend it doesn't even exist */
928 if (use_veto && IS_VETO_PATH(conn, name)) {
932 if (hide_unreadable || hide_unwriteable || hide_special) {
935 if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
938 /* Honour _hide unreadable_ option */
939 if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
943 /* Honour _hide unwriteable_ option */
944 if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
948 /* Honour _hide_special_ option */
949 if (hide_special && !file_is_special(conn, entry, pst)) {
958 /*******************************************************************
960 ********************************************************************/
962 struct smb_Dir *OpenDir(connection_struct *conn, const char *name)
964 struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
972 dirp->dir_path = SMB_STRDUP(name);
973 if (!dirp->dir_path) {
976 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path);
978 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
982 dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
983 if (!dirp->name_cache) {
994 SMB_VFS_CLOSEDIR(conn,dirp->dir);
996 SAFE_FREE(dirp->dir_path);
997 SAFE_FREE(dirp->name_cache);
1004 /*******************************************************************
1006 ********************************************************************/
1008 int CloseDir(struct smb_Dir *dirp)
1013 ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1015 SAFE_FREE(dirp->dir_path);
1016 if (dirp->name_cache) {
1017 for (i = 0; i < NAME_CACHE_SIZE; i++) {
1018 SAFE_FREE(dirp->name_cache[i].name);
1021 SAFE_FREE(dirp->name_cache);
1027 /*******************************************************************
1028 Read from a directory. Also return current offset.
1029 Don't check for veto or invisible files.
1030 ********************************************************************/
1032 const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
1035 connection_struct *conn = dirp->conn;
1037 SeekDir(dirp, *poffset);
1038 while ((n = vfs_readdirname(conn, dirp->dir))) {
1039 struct name_cache_entry *e;
1040 dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1041 if (dirp->offset == -1) {
1044 dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
1046 e = &dirp->name_cache[dirp->name_cache_index];
1048 e->name = SMB_STRDUP(n);
1049 *poffset = e->offset= dirp->offset;
1056 /*******************************************************************
1058 ********************************************************************/
1060 void SeekDir(struct smb_Dir *dirp, long offset)
1062 if (offset != dirp->offset) {
1063 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1064 dirp->offset = offset;
1068 /*******************************************************************
1069 Tell a dir position.
1070 ********************************************************************/
1072 long TellDir(struct smb_Dir *dirp)
1074 return(dirp->offset);
1077 /*******************************************************************
1078 Find an entry by name. Leave us at the offset after it.
1079 Don't check for veto or invisible files.
1080 ********************************************************************/
1082 BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1086 connection_struct *conn = dirp->conn;
1088 /* Search back in the name cache. */
1089 for (i = dirp->name_cache_index; i >= 0; i--) {
1090 struct name_cache_entry *e = &dirp->name_cache[i];
1091 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1092 *poffset = e->offset;
1093 SeekDir(dirp, e->offset);
1097 for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
1098 struct name_cache_entry *e = &dirp->name_cache[i];
1099 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1100 *poffset = e->offset;
1101 SeekDir(dirp, e->offset);
1106 /* Not found in the name cache. Rewind directory and start from scratch. */
1107 SMB_VFS_REWINDDIR(conn, dirp->dir);
1109 while ((entry = ReadDirName(dirp, poffset))) {
1110 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {