Enable checking/resetting of account lockout and bad password based on policy
[Samba/gebeck_regimport.git] / source / smbd / dir.c
blobbbd79e165975d9852f3b7d529b5b6952ea675cd3
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 typedef struct _dptr_struct {
28 struct _dptr_struct *next, *prev;
29 int dnum;
30 uint16 spid;
31 connection_struct *conn;
32 void *ptr;
33 BOOL expect_close;
34 char *wcard; /* Field only used for trans2_ searches */
35 uint16 attr; /* Field only used for trans2_ searches */
36 char *path;
37 } dptr_struct;
39 static struct bitmap *dptr_bmap;
40 static dptr_struct *dirptrs;
42 static int dptrs_open = 0;
44 #define INVALID_DPTR_KEY (-3)
46 /****************************************************************************
47 Initialise the dir bitmap.
48 ****************************************************************************/
50 void init_dptrs(void)
52 static BOOL dptrs_init=False;
54 if (dptrs_init)
55 return;
57 dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
59 if (!dptr_bmap)
60 exit_server("out of memory in init_dptrs");
62 dptrs_init = True;
65 /****************************************************************************
66 Idle a dptr - the directory is closed but the control info is kept.
67 ****************************************************************************/
69 static void dptr_idle(dptr_struct *dptr)
71 if (dptr->ptr) {
72 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
73 dptrs_open--;
74 CloseDir(dptr->ptr);
75 dptr->ptr = NULL;
79 /****************************************************************************
80 Idle the oldest dptr.
81 ****************************************************************************/
83 static void dptr_idleoldest(void)
85 dptr_struct *dptr;
88 * Go to the end of the list.
90 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
93 if(!dptr) {
94 DEBUG(0,("No dptrs available to idle ?\n"));
95 return;
99 * Idle the oldest pointer.
102 for(; dptr; dptr = dptr->prev) {
103 if (dptr->ptr) {
104 dptr_idle(dptr);
105 return;
110 /****************************************************************************
111 Get the dptr_struct for a dir index.
112 ****************************************************************************/
114 static dptr_struct *dptr_get(int key, BOOL forclose)
116 dptr_struct *dptr;
118 for(dptr = dirptrs; dptr; dptr = dptr->next) {
119 if(dptr->dnum == key) {
120 if (!forclose && !dptr->ptr) {
121 if (dptrs_open >= MAX_OPEN_DIRECTORIES)
122 dptr_idleoldest();
123 DEBUG(4,("Reopening dptr key %d\n",key));
124 if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True)))
125 dptrs_open++;
127 DLIST_PROMOTE(dirptrs,dptr);
128 return dptr;
131 return(NULL);
134 /****************************************************************************
135 Get the dptr ptr for a dir index.
136 ****************************************************************************/
138 static void *dptr_ptr(int key)
140 dptr_struct *dptr = dptr_get(key, False);
142 if (dptr)
143 return(dptr->ptr);
144 return(NULL);
147 /****************************************************************************
148 Get the dir path for a dir index.
149 ****************************************************************************/
151 char *dptr_path(int key)
153 dptr_struct *dptr = dptr_get(key, False);
155 if (dptr)
156 return(dptr->path);
157 return(NULL);
160 /****************************************************************************
161 Get the dir wcard for a dir index (lanman2 specific).
162 ****************************************************************************/
164 char *dptr_wcard(int key)
166 dptr_struct *dptr = dptr_get(key, False);
168 if (dptr)
169 return(dptr->wcard);
170 return(NULL);
173 /****************************************************************************
174 Set the dir wcard for a dir index (lanman2 specific).
175 Returns 0 on ok, 1 on fail.
176 ****************************************************************************/
178 BOOL dptr_set_wcard(int key, char *wcard)
180 dptr_struct *dptr = dptr_get(key, False);
182 if (dptr) {
183 dptr->wcard = wcard;
184 return True;
186 return False;
189 /****************************************************************************
190 Set the dir attrib for a dir index (lanman2 specific).
191 Returns 0 on ok, 1 on fail.
192 ****************************************************************************/
194 BOOL dptr_set_attr(int key, uint16 attr)
196 dptr_struct *dptr = dptr_get(key, False);
198 if (dptr) {
199 dptr->attr = attr;
200 return True;
202 return False;
205 /****************************************************************************
206 Get the dir attrib for a dir index (lanman2 specific)
207 ****************************************************************************/
209 uint16 dptr_attr(int key)
211 dptr_struct *dptr = dptr_get(key, False);
213 if (dptr)
214 return(dptr->attr);
215 return(0);
218 /****************************************************************************
219 Close a dptr (internal func).
220 ****************************************************************************/
222 static void dptr_close_internal(dptr_struct *dptr)
224 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
226 DLIST_REMOVE(dirptrs, dptr);
229 * Free the dnum in the bitmap. Remember the dnum value is always
230 * biased by one with respect to the bitmap.
233 if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
234 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
235 dptr->dnum ));
238 bitmap_clear(dptr_bmap, dptr->dnum - 1);
240 if (dptr->ptr) {
241 CloseDir(dptr->ptr);
242 dptrs_open--;
245 /* Lanman 2 specific code */
246 SAFE_FREE(dptr->wcard);
247 string_set(&dptr->path,"");
248 SAFE_FREE(dptr);
251 /****************************************************************************
252 Close a dptr given a key.
253 ****************************************************************************/
255 void dptr_close(int *key)
257 dptr_struct *dptr;
259 if(*key == INVALID_DPTR_KEY)
260 return;
262 /* OS/2 seems to use -1 to indicate "close all directories" */
263 if (*key == -1) {
264 dptr_struct *next;
265 for(dptr = dirptrs; dptr; dptr = next) {
266 next = dptr->next;
267 dptr_close_internal(dptr);
269 *key = INVALID_DPTR_KEY;
270 return;
273 dptr = dptr_get(*key, True);
275 if (!dptr) {
276 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
277 return;
280 dptr_close_internal(dptr);
282 *key = INVALID_DPTR_KEY;
285 /****************************************************************************
286 Close all dptrs for a cnum.
287 ****************************************************************************/
289 void dptr_closecnum(connection_struct *conn)
291 dptr_struct *dptr, *next;
292 for(dptr = dirptrs; dptr; dptr = next) {
293 next = dptr->next;
294 if (dptr->conn == conn)
295 dptr_close_internal(dptr);
299 /****************************************************************************
300 Idle all dptrs for a cnum.
301 ****************************************************************************/
303 void dptr_idlecnum(connection_struct *conn)
305 dptr_struct *dptr;
306 for(dptr = dirptrs; dptr; dptr = dptr->next) {
307 if (dptr->conn == conn && dptr->ptr)
308 dptr_idle(dptr);
312 /****************************************************************************
313 Close a dptr that matches a given path, only if it matches the spid also.
314 ****************************************************************************/
316 void dptr_closepath(char *path,uint16 spid)
318 dptr_struct *dptr, *next;
319 for(dptr = dirptrs; dptr; dptr = next) {
320 next = dptr->next;
321 if (spid == dptr->spid && strequal(dptr->path,path))
322 dptr_close_internal(dptr);
326 /****************************************************************************
327 Start a directory listing.
328 ****************************************************************************/
330 static BOOL start_dir(connection_struct *conn, pstring directory)
332 const char *dir2;
334 DEBUG(5,("start_dir dir=%s\n",directory));
336 if (!check_name(directory,conn))
337 return(False);
339 /* use a const pointer from here on */
340 dir2 = directory;
342 if (! *dir2)
343 dir2 = ".";
345 conn->dirptr = OpenDir(conn, directory, True);
346 if (conn->dirptr) {
347 dptrs_open++;
348 string_set(&conn->dirpath,directory);
349 return(True);
352 return(False);
355 /****************************************************************************
356 Try and close the oldest handle not marked for
357 expect close in the hope that the client has
358 finished with that one.
359 ****************************************************************************/
361 static void dptr_close_oldest(BOOL old)
363 dptr_struct *dptr;
366 * Go to the end of the list.
368 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
371 if(!dptr) {
372 DEBUG(0,("No old dptrs available to close oldest ?\n"));
373 return;
377 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
378 * does not have expect_close set. If 'old' is false, close
379 * one of the new dnum handles.
382 for(; dptr; dptr = dptr->prev) {
383 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
384 (!old && (dptr->dnum > 255))) {
385 dptr_close_internal(dptr);
386 return;
391 /****************************************************************************
392 Create a new dir ptr. If the flag old_handle is true then we must allocate
393 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
394 one byte long. If old_handle is false we allocate from the range
395 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
396 a directory handle is never zero. All the above is folklore taught to
397 me at Andrew's knee.... :-) :-). JRA.
398 ****************************************************************************/
400 int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid)
402 dptr_struct *dptr;
404 if (!start_dir(conn,path))
405 return(-2); /* Code to say use a unix error return code. */
407 if (dptrs_open >= MAX_OPEN_DIRECTORIES)
408 dptr_idleoldest();
410 dptr = (dptr_struct *)malloc(sizeof(dptr_struct));
411 if(!dptr) {
412 DEBUG(0,("malloc fail in dptr_create.\n"));
413 return -1;
416 ZERO_STRUCTP(dptr);
418 if(old_handle) {
421 * This is an old-style SMBsearch request. Ensure the
422 * value we return will fit in the range 1-255.
425 dptr->dnum = bitmap_find(dptr_bmap, 0);
427 if(dptr->dnum == -1 || dptr->dnum > 254) {
430 * Try and close the oldest handle not marked for
431 * expect close in the hope that the client has
432 * finished with that one.
435 dptr_close_oldest(True);
437 /* Now try again... */
438 dptr->dnum = bitmap_find(dptr_bmap, 0);
439 if(dptr->dnum == -1 || dptr->dnum > 254) {
440 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
441 SAFE_FREE(dptr);
442 return -1;
445 } else {
448 * This is a new-style trans2 request. Allocate from
449 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
452 dptr->dnum = bitmap_find(dptr_bmap, 255);
454 if(dptr->dnum == -1 || dptr->dnum < 255) {
457 * Try and close the oldest handle close in the hope that
458 * the client has finished with that one. This will only
459 * happen in the case of the Win98 client bug where it leaks
460 * directory handles.
463 dptr_close_oldest(False);
465 /* Now try again... */
466 dptr->dnum = bitmap_find(dptr_bmap, 255);
468 if(dptr->dnum == -1 || dptr->dnum < 255) {
469 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
470 SAFE_FREE(dptr);
471 return -1;
476 bitmap_set(dptr_bmap, dptr->dnum);
478 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
480 dptr->ptr = conn->dirptr;
481 string_set(&dptr->path,path);
482 dptr->conn = conn;
483 dptr->spid = spid;
484 dptr->expect_close = expect_close;
485 dptr->wcard = NULL; /* Only used in lanman2 searches */
486 dptr->attr = 0; /* Only used in lanman2 searches */
488 DLIST_ADD(dirptrs, dptr);
490 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
491 dptr->dnum,path,expect_close));
493 return(dptr->dnum);
496 /****************************************************************************
497 Fill the 5 byte server reserved dptr field.
498 ****************************************************************************/
500 BOOL dptr_fill(char *buf1,unsigned int key)
502 unsigned char *buf = (unsigned char *)buf1;
503 void *p = dptr_ptr(key);
504 uint32 offset;
505 if (!p) {
506 DEBUG(1,("filling null dirptr %d\n",key));
507 return(False);
509 offset = TellDir(p);
510 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
511 (long)p,(int)offset));
512 buf[0] = key;
513 SIVAL(buf,1,offset | DPTR_MASK);
514 return(True);
517 /****************************************************************************
518 Fetch the dir ptr and seek it given the 5 byte server field.
519 ****************************************************************************/
521 void *dptr_fetch(char *buf,int *num)
523 unsigned int key = *(unsigned char *)buf;
524 void *p = dptr_ptr(key);
525 uint32 offset;
527 if (!p) {
528 DEBUG(3,("fetched null dirptr %d\n",key));
529 return(NULL);
531 *num = key;
532 offset = IVAL(buf,1)&~DPTR_MASK;
533 SeekDir(p,offset);
534 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
535 key,dptr_path(key),offset));
536 return(p);
539 /****************************************************************************
540 Fetch the dir ptr.
541 ****************************************************************************/
543 void *dptr_fetch_lanman2(int dptr_num)
545 void *p = dptr_ptr(dptr_num);
547 if (!p) {
548 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
549 return(NULL);
551 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
552 return(p);
555 /****************************************************************************
556 Check a filetype for being valid.
557 ****************************************************************************/
559 BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
561 int mask;
563 /* Check the "may have" search bits. */
564 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
565 return False;
567 /* Check the "must have" bits, which are the may have bits shifted eight */
568 /* If must have bit is set, the file/dir can not be returned in search unless the matching
569 file attribute is set */
570 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
571 if(mask) {
572 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
573 return True;
574 else
575 return False;
578 return True;
581 static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
583 mangle_map(filename,True,False,SNUM(conn));
584 return mask_match(filename,mask,False);
587 /****************************************************************************
588 Get an 8.3 directory entry.
589 ****************************************************************************/
591 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname,
592 SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
594 const char *dname;
595 BOOL found = False;
596 SMB_STRUCT_STAT sbuf;
597 pstring path;
598 pstring pathreal;
599 BOOL isrootdir;
600 pstring filename;
601 BOOL needslash;
603 *path = *pathreal = *filename = 0;
605 isrootdir = (strequal(conn->dirpath,"./") ||
606 strequal(conn->dirpath,".") ||
607 strequal(conn->dirpath,"/"));
609 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
611 if (!conn->dirptr)
612 return(False);
614 while (!found) {
615 dname = ReadDirName(conn->dirptr);
617 DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
618 (long)conn->dirptr,TellDir(conn->dirptr)));
620 if (dname == NULL)
621 return(False);
623 pstrcpy(filename,dname);
625 /* notice the special *.* handling. This appears to be the only difference
626 between the wildcard handling in this routine and in the trans2 routines.
627 see masktest for a demo
629 if ((strcmp(mask,"*.*") == 0) ||
630 mask_match(filename,mask,False) ||
631 mangle_mask_match(conn,filename,mask)) {
632 if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
633 continue;
635 if (!mangle_is_8_3(filename, False))
636 mangle_map(filename,True,False,SNUM(conn));
638 pstrcpy(fname,filename);
639 *path = 0;
640 pstrcpy(path,conn->dirpath);
641 if(needslash)
642 pstrcat(path,"/");
643 pstrcpy(pathreal,path);
644 pstrcat(path,fname);
645 pstrcat(pathreal,dname);
646 if (SMB_VFS_STAT(conn, pathreal, &sbuf) != 0) {
647 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
648 continue;
651 *mode = dos_mode(conn,pathreal,&sbuf);
653 if (!dir_check_ftype(conn,*mode,&sbuf,dirtype)) {
654 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
655 continue;
658 *size = sbuf.st_size;
659 *date = sbuf.st_mtime;
661 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
663 found = True;
667 return(found);
670 typedef struct {
671 int pos;
672 int numentries;
673 int mallocsize;
674 char *data;
675 char *current;
676 } Dir;
678 /*******************************************************************
679 Check to see if a user can read a file. This is only approximate,
680 it is used as part of the "hide unreadable" option. Don't
681 use it for anything security sensitive.
682 ********************************************************************/
684 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
686 extern struct current_user current_user;
687 SEC_DESC *psd = NULL;
688 size_t sd_size;
689 files_struct *fsp;
690 int smb_action;
691 NTSTATUS status;
692 uint32 access_granted;
695 * If user is a member of the Admin group
696 * we never hide files from them.
699 if (conn->admin_user)
700 return True;
702 /* If we can't stat it does not show it */
703 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
704 return False;
706 /* Pseudo-open the file (note - no fd's created). */
708 if(S_ISDIR(pst->st_mode))
709 fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
710 unix_mode(conn,aRONLY|aDIR, name), &smb_action);
711 else
712 fsp = open_file_stat(conn, name, pst);
714 if (!fsp)
715 return False;
717 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
718 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
719 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
720 close_file(fsp, True);
722 /* No access if SD get failed. */
723 if (!sd_size)
724 return False;
726 return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
727 &access_granted, &status);
730 /*******************************************************************
731 Check to see if a user can write a file (and only files, we do not
732 check dirs on this one). This is only approximate,
733 it is used as part of the "hide unwriteable" option. Don't
734 use it for anything security sensitive.
735 ********************************************************************/
737 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
739 extern struct current_user current_user;
740 SEC_DESC *psd = NULL;
741 size_t sd_size;
742 files_struct *fsp;
743 int smb_action;
744 int access_mode;
745 NTSTATUS status;
746 uint32 access_granted;
749 * If user is a member of the Admin group
750 * we never hide files from them.
753 if (conn->admin_user)
754 return True;
756 /* If we can't stat it does not show it */
757 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
758 return False;
760 /* Pseudo-open the file (note - no fd's created). */
762 if(S_ISDIR(pst->st_mode))
763 return True;
764 else
765 fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
766 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
768 if (!fsp)
769 return False;
771 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
772 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
773 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
774 close_file(fsp, False);
776 /* No access if SD get failed. */
777 if (!sd_size)
778 return False;
780 return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
781 &access_granted, &status);
784 /*******************************************************************
785 Is a file a "special" type ?
786 ********************************************************************/
788 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
791 * If user is a member of the Admin group
792 * we never hide files from them.
795 if (conn->admin_user)
796 return False;
798 /* If we can't stat it does not show it */
799 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
800 return True;
802 if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
803 return False;
805 return True;
808 /*******************************************************************
809 Open a directory.
810 ********************************************************************/
812 void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto)
814 Dir *dirp;
815 const char *n;
816 DIR *p = SMB_VFS_OPENDIR(conn,name);
817 int used=0;
819 if (!p)
820 return(NULL);
821 dirp = (Dir *)malloc(sizeof(Dir));
822 if (!dirp) {
823 DEBUG(0,("Out of memory in OpenDir\n"));
824 SMB_VFS_CLOSEDIR(conn,p);
825 return(NULL);
827 dirp->pos = dirp->numentries = dirp->mallocsize = 0;
828 dirp->data = dirp->current = NULL;
830 while (True) {
831 int l;
832 BOOL normal_entry = True;
833 SMB_STRUCT_STAT st;
834 char *entry = NULL;
836 if (used == 0) {
837 n = ".";
838 normal_entry = False;
839 } else if (used == 2) {
840 n = "..";
841 normal_entry = False;
842 } else {
843 n = vfs_readdirname(conn, p);
844 if (n == NULL)
845 break;
846 if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0))
847 continue;
848 normal_entry = True;
851 ZERO_STRUCT(st);
852 l = strlen(n)+1;
854 /* If it's a vetoed file, pretend it doesn't even exist */
855 if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n))
856 continue;
858 /* Honour _hide unreadable_ option */
859 if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) {
860 int ret=0;
862 if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
863 ret = user_can_read_file(conn, entry, &st);
865 if (!ret) {
866 SAFE_FREE(entry);
867 continue;
871 /* Honour _hide unwriteable_ option */
872 if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) {
873 int ret=0;
875 if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
876 ret = user_can_write_file(conn, entry, &st);
878 if (!ret) {
879 SAFE_FREE(entry);
880 continue;
884 /* Honour _hide_special_ option */
885 if (normal_entry && conn && lp_hide_special_files(SNUM(conn))) {
886 int ret=0;
888 if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
889 ret = file_is_special(conn, entry, &st);
891 if (ret) {
892 SAFE_FREE(entry);
893 continue;
897 SAFE_FREE(entry);
899 if (used + l > dirp->mallocsize) {
900 int s = MAX(used+l,used+2000);
901 char *r;
902 r = (char *)Realloc(dirp->data,s);
903 if (!r) {
904 DEBUG(0,("Out of memory in OpenDir\n"));
905 break;
907 dirp->data = r;
908 dirp->mallocsize = s;
909 dirp->current = dirp->data;
912 safe_strcpy_base(dirp->data+used,n, dirp->data, dirp->mallocsize);
913 used += l;
914 dirp->numentries++;
917 SMB_VFS_CLOSEDIR(conn,p);
918 return((void *)dirp);
922 /*******************************************************************
923 Close a directory.
924 ********************************************************************/
926 void CloseDir(void *p)
928 if (!p)
929 return;
930 SAFE_FREE(((Dir *)p)->data);
931 SAFE_FREE(p);
934 /*******************************************************************
935 Read from a directory.
936 ********************************************************************/
938 const char *ReadDirName(void *p)
940 char *ret;
941 Dir *dirp = (Dir *)p;
943 if (!dirp || !dirp->current || dirp->pos >= dirp->numentries)
944 return(NULL);
946 ret = dirp->current;
947 dirp->current = skip_string(dirp->current,1);
948 dirp->pos++;
950 return(ret);
953 /*******************************************************************
954 Seek a dir.
955 ********************************************************************/
957 BOOL SeekDir(void *p,int pos)
959 Dir *dirp = (Dir *)p;
961 if (!dirp)
962 return(False);
964 if (pos < dirp->pos) {
965 dirp->current = dirp->data;
966 dirp->pos = 0;
969 while (dirp->pos < pos && ReadDirName(p))
972 return (dirp->pos == pos);
975 /*******************************************************************
976 Tell a dir position.
977 ********************************************************************/
979 int TellDir(void *p)
981 Dir *dirp = (Dir *)p;
983 if (!dirp)
984 return(-1);
986 return(dirp->pos);
989 /*******************************************************************************
990 This section manages a global directory cache.
991 (It should probably be split into a separate module. crh)
992 ********************************************************************************/
994 typedef struct {
995 ubi_dlNode node;
996 char *path;
997 char *name;
998 char *dname;
999 int snum;
1000 } dir_cache_entry;
1002 static ubi_dlNewList( dir_cache );
1004 /*****************************************************************************
1005 Add an entry to the directory cache.
1006 Input: path -
1007 name -
1008 dname -
1009 snum -
1010 Output: None.
1011 *****************************************************************************/
1013 void DirCacheAdd( const char *path, const char *name, const char *dname, int snum )
1015 int pathlen;
1016 int namelen;
1017 dir_cache_entry *entry;
1020 * Allocate the structure & string space in one go so that it can be freed
1021 * in one call to free().
1023 pathlen = strlen(path) + 1; /* Bytes required to store path (with nul). */
1024 namelen = strlen(name) + 1; /* Bytes required to store name (with nul). */
1025 entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
1026 + pathlen
1027 + namelen
1028 + strlen( dname ) +1 );
1029 if( NULL == entry ) /* Not adding to the cache is not fatal, */
1030 return; /* so just return as if nothing happened. */
1032 /* Set pointers correctly and load values. */
1033 entry->path = memcpy( (char *)&entry[1], path, strlen(path)+1 );
1034 entry->name = memcpy( &(entry->path[pathlen]), name, strlen(name)+1 );
1035 entry->dname = memcpy( &(entry->name[namelen]), dname, strlen(dname)+1 );
1036 entry->snum = snum;
1038 /* Add the new entry to the linked list. */
1039 (void)ubi_dlAddHead( dir_cache, entry );
1040 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
1042 /* Free excess cache entries. */
1043 while( DIRCACHESIZE < dir_cache->count )
1044 safe_free( ubi_dlRemTail( dir_cache ) );
1047 /*****************************************************************************
1048 Search for an entry to the directory cache.
1049 Input: path -
1050 name -
1051 snum -
1052 Output: The dname string of the located entry, or NULL if the entry was
1053 not found.
1055 Notes: This uses a linear search, which is is okay because of
1056 the small size of the cache. Use a splay tree or hash
1057 for large caches.
1058 *****************************************************************************/
1060 char *DirCacheCheck( const char *path, const char *name, int snum )
1062 dir_cache_entry *entry;
1064 for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
1065 NULL != entry;
1066 entry = (dir_cache_entry *)ubi_dlNext( entry ) ) {
1067 if( entry->snum == snum
1068 && entry->name && 0 == strcmp( name, entry->name )
1069 && entry->path && 0 == strcmp( path, entry->path ) ) {
1070 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
1071 return( entry->dname );
1075 return(NULL);
1078 /*****************************************************************************
1079 Remove all cache entries which have an snum that matches the input.
1080 Input: snum -
1081 Output: None.
1082 *****************************************************************************/
1084 void DirCacheFlush(int snum)
1086 dir_cache_entry *entry;
1087 ubi_dlNodePtr next;
1089 for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
1090 NULL != entry; ) {
1091 next = ubi_dlNext( entry );
1092 if( entry->snum == snum )
1093 safe_free( ubi_dlRemThis( dir_cache, entry ) );
1094 entry = (dir_cache_entry *)next;