fix for bad check spotted by Ray Simard <ray@sylvan-glade.com>
[Samba.git] / source3 / smbd / dir.c
blob396ecd98c495e8f856edf090e96d54fa19b66a80
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,char *directory)
332 DEBUG(5,("start_dir dir=%s\n",directory));
334 if (!check_name(directory,conn))
335 return(False);
337 if (! *directory)
338 directory = ".";
340 conn->dirptr = OpenDir(conn, directory, True);
341 if (conn->dirptr) {
342 dptrs_open++;
343 string_set(&conn->dirpath,directory);
344 return(True);
347 return(False);
350 /****************************************************************************
351 Try and close the oldest handle not marked for
352 expect close in the hope that the client has
353 finished with that one.
354 ****************************************************************************/
356 static void dptr_close_oldest(BOOL old)
358 dptr_struct *dptr;
361 * Go to the end of the list.
363 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
366 if(!dptr) {
367 DEBUG(0,("No old dptrs available to close oldest ?\n"));
368 return;
372 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
373 * does not have expect_close set. If 'old' is false, close
374 * one of the new dnum handles.
377 for(; dptr; dptr = dptr->prev) {
378 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
379 (!old && (dptr->dnum > 255))) {
380 dptr_close_internal(dptr);
381 return;
386 /****************************************************************************
387 Create a new dir ptr. If the flag old_handle is true then we must allocate
388 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
389 one byte long. If old_handle is false we allocate from the range
390 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
391 a directory handle is never zero. All the above is folklore taught to
392 me at Andrew's knee.... :-) :-). JRA.
393 ****************************************************************************/
395 int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,uint16 spid)
397 dptr_struct *dptr;
399 if (!start_dir(conn,path))
400 return(-2); /* Code to say use a unix error return code. */
402 if (dptrs_open >= MAX_OPEN_DIRECTORIES)
403 dptr_idleoldest();
405 dptr = (dptr_struct *)malloc(sizeof(dptr_struct));
406 if(!dptr) {
407 DEBUG(0,("malloc fail in dptr_create.\n"));
408 return -1;
411 ZERO_STRUCTP(dptr);
413 if(old_handle) {
416 * This is an old-style SMBsearch request. Ensure the
417 * value we return will fit in the range 1-255.
420 dptr->dnum = bitmap_find(dptr_bmap, 0);
422 if(dptr->dnum == -1 || dptr->dnum > 254) {
425 * Try and close the oldest handle not marked for
426 * expect close in the hope that the client has
427 * finished with that one.
430 dptr_close_oldest(True);
432 /* Now try again... */
433 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));
437 SAFE_FREE(dptr);
438 return -1;
441 } else {
444 * This is a new-style trans2 request. Allocate from
445 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
448 dptr->dnum = bitmap_find(dptr_bmap, 255);
450 if(dptr->dnum == -1 || dptr->dnum < 255) {
453 * Try and close the oldest handle close in the hope that
454 * the client has finished with that one. This will only
455 * happen in the case of the Win98 client bug where it leaks
456 * directory handles.
459 dptr_close_oldest(False);
461 /* Now try again... */
462 dptr->dnum = bitmap_find(dptr_bmap, 255);
464 if(dptr->dnum == -1 || dptr->dnum < 255) {
465 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
466 SAFE_FREE(dptr);
467 return -1;
472 bitmap_set(dptr_bmap, dptr->dnum);
474 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
476 dptr->ptr = conn->dirptr;
477 string_set(&dptr->path,path);
478 dptr->conn = conn;
479 dptr->spid = spid;
480 dptr->expect_close = expect_close;
481 dptr->wcard = NULL; /* Only used in lanman2 searches */
482 dptr->attr = 0; /* Only used in lanman2 searches */
484 DLIST_ADD(dirptrs, dptr);
486 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
487 dptr->dnum,path,expect_close));
489 return(dptr->dnum);
492 /****************************************************************************
493 Fill the 5 byte server reserved dptr field.
494 ****************************************************************************/
496 BOOL dptr_fill(char *buf1,unsigned int key)
498 unsigned char *buf = (unsigned char *)buf1;
499 void *p = dptr_ptr(key);
500 uint32 offset;
501 if (!p) {
502 DEBUG(1,("filling null dirptr %d\n",key));
503 return(False);
505 offset = TellDir(p);
506 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
507 (long)p,(int)offset));
508 buf[0] = key;
509 SIVAL(buf,1,offset | DPTR_MASK);
510 return(True);
513 /****************************************************************************
514 Fetch the dir ptr and seek it given the 5 byte server field.
515 ****************************************************************************/
517 void *dptr_fetch(char *buf,int *num)
519 unsigned int key = *(unsigned char *)buf;
520 void *p = dptr_ptr(key);
521 uint32 offset;
522 if (!p) {
523 DEBUG(3,("fetched null dirptr %d\n",key));
524 return(NULL);
526 *num = key;
527 offset = IVAL(buf,1)&~DPTR_MASK;
528 SeekDir(p,offset);
529 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
530 key,dptr_path(key),offset));
531 return(p);
534 /****************************************************************************
535 Fetch the dir ptr.
536 ****************************************************************************/
538 void *dptr_fetch_lanman2(int dptr_num)
540 void *p = dptr_ptr(dptr_num);
542 if (!p) {
543 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
544 return(NULL);
546 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
547 return(p);
550 /****************************************************************************
551 Check a filetype for being valid.
552 ****************************************************************************/
554 BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
556 int mask;
558 /* Check the "may have" search bits. */
559 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
560 return False;
562 /* Check the "must have" bits, which are the may have bits shifted eight */
563 /* If must have bit is set, the file/dir can not be returned in search unless the matching
564 file attribute is set */
565 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
566 if(mask) {
567 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
568 return True;
569 else
570 return False;
573 return True;
576 static BOOL mangle_mask_match(connection_struct *conn, char *filename, char *mask)
578 mangle_map(filename,True,False,SNUM(conn));
579 return mask_match(filename,mask,False);
582 /****************************************************************************
583 Get an 8.3 directory entry.
584 ****************************************************************************/
586 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
587 SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
589 char *dname;
590 BOOL found = False;
591 SMB_STRUCT_STAT sbuf;
592 pstring path;
593 pstring pathreal;
594 BOOL isrootdir;
595 pstring filename;
596 BOOL needslash;
598 *path = *pathreal = *filename = 0;
600 isrootdir = (strequal(conn->dirpath,"./") ||
601 strequal(conn->dirpath,".") ||
602 strequal(conn->dirpath,"/"));
604 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
606 if (!conn->dirptr)
607 return(False);
609 while (!found)
611 dname = ReadDirName(conn->dirptr);
613 DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
614 (long)conn->dirptr,TellDir(conn->dirptr)));
616 if (dname == NULL)
617 return(False);
619 pstrcpy(filename,dname);
621 /* notice the special *.* handling. This appears to be the only difference
622 between the wildcard handling in this routine and in the trans2 routines.
623 see masktest for a demo
625 if ((strcmp(mask,"*.*") == 0) ||
626 mask_match(filename,mask,False) ||
627 mangle_mask_match(conn,filename,mask))
629 if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
630 continue;
632 if (!mangle_is_8_3(filename, False)) {
633 mangle_map(filename,True,False,SNUM(conn));
636 pstrcpy(fname,filename);
637 *path = 0;
638 pstrcpy(path,conn->dirpath);
639 if(needslash)
640 pstrcat(path,"/");
641 pstrcpy(pathreal,path);
642 pstrcat(path,fname);
643 pstrcat(pathreal,dname);
644 if (conn->vfs_ops.stat(conn, pathreal, &sbuf) != 0)
646 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
647 continue;
650 *mode = dos_mode(conn,pathreal,&sbuf);
652 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);
672 typedef struct
674 int pos;
675 int numentries;
676 int mallocsize;
677 char *data;
678 char *current;
679 } Dir;
681 /*******************************************************************
682 Check to see if a user can read a file. This is only approximate,
683 it is used as part of the "hide unreadable" option. Don't
684 use it for anything security sensitive.
685 ********************************************************************/
687 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
689 extern struct current_user current_user;
690 SEC_DESC *psd = NULL;
691 size_t sd_size;
692 files_struct *fsp;
693 int smb_action;
694 int access_mode;
695 NTSTATUS status;
696 uint32 access_granted;
699 * If user is a member of the Admin group
700 * we never hide files from them.
703 if (conn->admin_user)
704 return True;
706 /* If we can't stat it does not show it */
707 if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0))
708 return False;
710 /* Pseudo-open the file (note - no fd's created). */
712 if(S_ISDIR(pst->st_mode))
713 fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
714 unix_mode(conn,aRONLY|aDIR, name), &smb_action);
715 else
716 fsp = open_file_shared1(conn, name, pst, FILE_READ_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
717 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
719 if (!fsp)
720 return False;
722 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
723 sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
724 close_file(fsp, False);
726 /* No access if SD get failed. */
727 if (!sd_size)
728 return False;
730 return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
731 &access_granted, &status);
734 /*******************************************************************
735 Check to see if a user can write a file (and only files, we do not
736 check dirs on this one). This is only approximate,
737 it is used as part of the "hide unwriteable" option. Don't
738 use it for anything security sensitive.
739 ********************************************************************/
741 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
743 extern struct current_user current_user;
744 SEC_DESC *psd = NULL;
745 size_t sd_size;
746 files_struct *fsp;
747 int smb_action;
748 int access_mode;
749 NTSTATUS status;
750 uint32 access_granted;
753 * If user is a member of the Admin group
754 * we never hide files from them.
757 if (conn->admin_user)
758 return True;
760 /* If we can't stat it does not show it */
761 if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0))
762 return False;
764 /* Pseudo-open the file (note - no fd's created). */
766 if(S_ISDIR(pst->st_mode))
767 return True;
768 else
769 fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
770 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
772 if (!fsp)
773 return False;
775 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
776 sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
777 close_file(fsp, False);
779 /* No access if SD get failed. */
780 if (!sd_size)
781 return False;
783 return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
784 &access_granted, &status);
787 /*******************************************************************
788 Is a file a "special" type ?
789 ********************************************************************/
791 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
794 * If user is a member of the Admin group
795 * we never hide files from them.
798 if (conn->admin_user)
799 return True;
801 /* If we can't stat it does not show it */
802 if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0))
803 return True;
805 if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
806 return False;
808 return True;
811 /*******************************************************************
812 Open a directory.
813 ********************************************************************/
815 void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
817 Dir *dirp;
818 char *n;
819 DIR *p = conn->vfs_ops.opendir(conn,name);
820 int used=0;
822 if (!p)
823 return(NULL);
824 dirp = (Dir *)malloc(sizeof(Dir));
825 if (!dirp) {
826 DEBUG(0,("Out of memory in OpenDir\n"));
827 conn->vfs_ops.closedir(conn,p);
828 return(NULL);
830 dirp->pos = dirp->numentries = dirp->mallocsize = 0;
831 dirp->data = dirp->current = NULL;
833 while (True) {
834 int l;
835 BOOL normal_entry = True;
836 SMB_STRUCT_STAT st;
837 char *entry = NULL;
839 if (used == 0) {
840 n = ".";
841 normal_entry = False;
842 } else if (used == 2) {
843 n = "..";
844 normal_entry = False;
845 } else {
846 n = vfs_readdirname(conn, p);
847 if (n == NULL)
848 break;
849 if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0))
850 continue;
851 normal_entry = True;
854 ZERO_STRUCT(st);
855 l = strlen(n)+1;
857 /* If it's a vetoed file, pretend it doesn't even exist */
858 if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n))
859 continue;
861 /* Honour _hide unreadable_ option */
862 if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) {
863 int ret=0;
865 if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
866 ret = user_can_read_file(conn, entry, &st);
868 if (!ret) {
869 SAFE_FREE(entry);
870 continue;
874 /* Honour _hide unwriteable_ option */
875 if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) {
876 int ret=0;
878 if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
879 ret = user_can_write_file(conn, entry, &st);
881 if (!ret) {
882 SAFE_FREE(entry);
883 continue;
887 /* Honour _hide_special_ option */
888 if (normal_entry && conn && lp_hide_special_files(SNUM(conn))) {
889 int ret=0;
891 if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
892 ret = file_is_special(conn, entry, &st);
894 if (ret) {
895 SAFE_FREE(entry);
896 continue;
900 SAFE_FREE(entry);
902 if (used + l > dirp->mallocsize) {
903 int s = MAX(used+l,used+2000);
904 char *r;
905 r = (char *)Realloc(dirp->data,s);
906 if (!r) {
907 DEBUG(0,("Out of memory in OpenDir\n"));
908 break;
910 dirp->data = r;
911 dirp->mallocsize = s;
912 dirp->current = dirp->data;
915 pstrcpy(dirp->data+used,n);
916 used += l;
917 dirp->numentries++;
920 conn->vfs_ops.closedir(conn,p);
921 return((void *)dirp);
925 /*******************************************************************
926 Close a directory.
927 ********************************************************************/
929 void CloseDir(void *p)
931 if (!p) return;
932 SAFE_FREE(((Dir *)p)->data);
933 SAFE_FREE(p);
936 /*******************************************************************
937 Read from a directory.
938 ********************************************************************/
940 char *ReadDirName(void *p)
942 char *ret;
943 Dir *dirp = (Dir *)p;
945 if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
947 ret = dirp->current;
948 dirp->current = skip_string(dirp->current,1);
949 dirp->pos++;
951 return(ret);
955 /*******************************************************************
956 Seek a dir.
957 ********************************************************************/
959 BOOL SeekDir(void *p,int pos)
961 Dir *dirp = (Dir *)p;
963 if (!dirp) return(False);
965 if (pos < dirp->pos) {
966 dirp->current = dirp->data;
967 dirp->pos = 0;
970 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) return(-1);
985 return(dirp->pos);
988 /*******************************************************************************
989 This section manages a global directory cache.
990 (It should probably be split into a separate module. crh)
991 ********************************************************************************/
993 typedef struct {
994 ubi_dlNode node;
995 char *path;
996 char *name;
997 char *dname;
998 int snum;
999 } dir_cache_entry;
1001 static ubi_dlNewList( dir_cache );
1003 /*****************************************************************************
1004 Add an entry to the directory cache.
1005 Input: path -
1006 name -
1007 dname -
1008 snum -
1009 Output: None.
1010 *****************************************************************************/
1012 void DirCacheAdd( char *path, char *name, char *dname, int snum )
1014 int pathlen;
1015 int namelen;
1016 dir_cache_entry *entry;
1018 /* Allocate the structure & string space in one go so that it can be freed
1019 * in one call to free().
1021 pathlen = strlen( path ) +1; /* Bytes required to store path (with nul). */
1022 namelen = strlen( name ) +1; /* Bytes required to store name (with nul). */
1023 entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
1024 + pathlen
1025 + namelen
1026 + strlen( dname ) +1 );
1027 if( NULL == entry ) /* Not adding to the cache is not fatal, */
1028 return; /* so just return as if nothing happened. */
1030 /* Set pointers correctly and load values. */
1031 entry->path = pstrcpy( (char *)&entry[1], path);
1032 entry->name = pstrcpy( &(entry->path[pathlen]), name);
1033 entry->dname = pstrcpy( &(entry->name[namelen]), dname);
1034 entry->snum = snum;
1036 /* Add the new entry to the linked list. */
1037 (void)ubi_dlAddHead( dir_cache, entry );
1038 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
1040 /* Free excess cache entries. */
1041 while( DIRCACHESIZE < dir_cache->count )
1042 safe_free( ubi_dlRemTail( dir_cache ) );
1046 /*****************************************************************************
1047 Search for an entry to the directory cache.
1048 Input: path -
1049 name -
1050 snum -
1051 Output: The dname string of the located entry, or NULL if the entry was
1052 not found.
1054 Notes: This uses a linear search, which is is okay because of
1055 the small size of the cache. Use a splay tree or hash
1056 for large caches.
1057 *****************************************************************************/
1059 char *DirCacheCheck( char *path, char *name, int snum )
1061 dir_cache_entry *entry;
1063 for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
1064 NULL != entry;
1065 entry = (dir_cache_entry *)ubi_dlNext( entry ) )
1067 if( entry->snum == snum
1068 && 0 == strcmp( name, entry->name )
1069 && 0 == strcmp( path, entry->path ) )
1071 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
1072 return( entry->dname );
1076 return(NULL);
1079 /*****************************************************************************
1080 Remove all cache entries which have an snum that matches the input.
1081 Input: snum -
1082 Output: None.
1083 *****************************************************************************/
1085 void DirCacheFlush(int snum)
1087 dir_cache_entry *entry;
1088 ubi_dlNodePtr next;
1090 for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
1091 NULL != entry; ) {
1092 next = ubi_dlNext( entry );
1093 if( entry->snum == snum )
1094 safe_free( ubi_dlRemThis( dir_cache, entry ) );
1095 entry = (dir_cache_entry *)next;