2 Unix SMB/Netbios implementation.
4 Directory handling routines
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 This module implements directory related functions for Samba.
28 typedef struct _dptr_struct
{
29 struct _dptr_struct
*next
, *prev
;
32 connection_struct
*conn
;
35 char *wcard
; /* Field only used for trans2_ searches */
36 uint16 attr
; /* Field only used for trans2_ searches */
40 static struct bitmap
*dptr_bmap
;
41 static dptr_struct
*dirptrs
;
43 static int dptrs_open
= 0;
45 #define INVALID_DPTR_KEY (-3)
47 /****************************************************************************
48 Initialise the dir bitmap.
49 ****************************************************************************/
53 static BOOL dptrs_init
=False
;
58 dptr_bmap
= bitmap_allocate(MAX_DIRECTORY_HANDLES
);
61 exit_server("out of memory in init_dptrs\n");
66 /****************************************************************************
67 Idle a dptr - the directory is closed but the control info is kept.
68 ****************************************************************************/
70 static void dptr_idle(dptr_struct
*dptr
)
73 DEBUG(4,("Idling dptr dnum %d\n",dptr
->dnum
));
80 /****************************************************************************
82 ****************************************************************************/
84 static void dptr_idleoldest(void)
89 * Go to the end of the list.
91 for(dptr
= dirptrs
; dptr
&& dptr
->next
; dptr
= dptr
->next
)
95 DEBUG(0,("No dptrs available to idle ?\n"));
100 * Idle the oldest pointer.
103 for(; dptr
; dptr
= dptr
->prev
) {
111 /****************************************************************************
112 Get the dptr_struct for a dir index.
113 ****************************************************************************/
115 static dptr_struct
*dptr_get(int key
, BOOL forclose
)
119 for(dptr
= dirptrs
; dptr
; dptr
= dptr
->next
) {
120 if(dptr
->dnum
== key
) {
121 if (!forclose
&& !dptr
->ptr
) {
122 if (dptrs_open
>= MAX_OPEN_DIRECTORIES
)
124 DEBUG(4,("Reopening dptr key %d\n",key
));
125 if ((dptr
->ptr
= OpenDir(dptr
->conn
, dptr
->path
, True
)))
128 DLIST_PROMOTE(dirptrs
,dptr
);
135 /****************************************************************************
136 Get the dptr ptr for a dir index.
137 ****************************************************************************/
139 static void *dptr_ptr(int key
)
141 dptr_struct
*dptr
= dptr_get(key
, False
);
148 /****************************************************************************
149 Get the dir path for a dir index.
150 ****************************************************************************/
152 char *dptr_path(int key
)
154 dptr_struct
*dptr
= dptr_get(key
, False
);
161 /****************************************************************************
162 Get the dir wcard for a dir index (lanman2 specific).
163 ****************************************************************************/
165 char *dptr_wcard(int key
)
167 dptr_struct
*dptr
= dptr_get(key
, False
);
174 /****************************************************************************
175 Set the dir wcard for a dir index (lanman2 specific).
176 Returns 0 on ok, 1 on fail.
177 ****************************************************************************/
179 BOOL
dptr_set_wcard(int key
, char *wcard
)
181 dptr_struct
*dptr
= dptr_get(key
, False
);
190 /****************************************************************************
191 Set the dir attrib for a dir index (lanman2 specific).
192 Returns 0 on ok, 1 on fail.
193 ****************************************************************************/
195 BOOL
dptr_set_attr(int key
, uint16 attr
)
197 dptr_struct
*dptr
= dptr_get(key
, False
);
206 /****************************************************************************
207 Get the dir attrib for a dir index (lanman2 specific)
208 ****************************************************************************/
210 uint16
dptr_attr(int key
)
212 dptr_struct
*dptr
= dptr_get(key
, False
);
219 /****************************************************************************
220 Close a dptr (internal func).
221 ****************************************************************************/
223 static void dptr_close_internal(dptr_struct
*dptr
)
225 DEBUG(4,("closing dptr key %d\n",dptr
->dnum
));
227 DLIST_REMOVE(dirptrs
, dptr
);
230 * Free the dnum in the bitmap. Remember the dnum value is always
231 * biased by one with respect to the bitmap.
234 if(bitmap_query( dptr_bmap
, dptr
->dnum
- 1) != True
) {
235 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
239 bitmap_clear(dptr_bmap
, dptr
->dnum
- 1);
246 /* Lanman 2 specific code */
247 SAFE_FREE(dptr
->wcard
);
248 string_set(&dptr
->path
,"");
252 /****************************************************************************
253 Close a dptr given a key.
254 ****************************************************************************/
256 void dptr_close(int *key
)
260 if(*key
== INVALID_DPTR_KEY
)
263 /* OS/2 seems to use -1 to indicate "close all directories" */
266 for(dptr
= dirptrs
; dptr
; dptr
= next
) {
268 dptr_close_internal(dptr
);
270 *key
= INVALID_DPTR_KEY
;
274 dptr
= dptr_get(*key
, True
);
277 DEBUG(0,("Invalid key %d given to dptr_close\n", *key
));
281 dptr_close_internal(dptr
);
283 *key
= INVALID_DPTR_KEY
;
286 /****************************************************************************
287 Close all dptrs for a cnum.
288 ****************************************************************************/
290 void dptr_closecnum(connection_struct
*conn
)
292 dptr_struct
*dptr
, *next
;
293 for(dptr
= dirptrs
; dptr
; dptr
= next
) {
295 if (dptr
->conn
== conn
)
296 dptr_close_internal(dptr
);
300 /****************************************************************************
301 Idle all dptrs for a cnum.
302 ****************************************************************************/
304 void dptr_idlecnum(connection_struct
*conn
)
307 for(dptr
= dirptrs
; dptr
; dptr
= dptr
->next
) {
308 if (dptr
->conn
== conn
&& dptr
->ptr
)
313 /****************************************************************************
314 Close a dptr that matches a given path, only if it matches the spid also.
315 ****************************************************************************/
317 void dptr_closepath(char *path
,uint16 spid
)
319 dptr_struct
*dptr
, *next
;
320 for(dptr
= dirptrs
; dptr
; dptr
= next
) {
322 if (spid
== dptr
->spid
&& strequal(dptr
->path
,path
))
323 dptr_close_internal(dptr
);
327 /****************************************************************************
328 Start a directory listing.
329 ****************************************************************************/
331 static BOOL
start_dir(connection_struct
*conn
,char *directory
)
335 DEBUG(5,("start_dir dir=%s\n",directory
));
337 if (!check_name(directory
,conn
))
345 conn
->dirptr
= OpenDir(conn
, dir2
, True
);
348 string_set(&conn
->dirpath
,dir2
);
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
)
366 * Go to the end of the list.
368 for(dptr
= dirptrs
; dptr
&& dptr
->next
; dptr
= dptr
->next
)
372 DEBUG(0,("No old dptrs available to close oldest ?\n"));
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
);
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
,char *path
, BOOL old_handle
, BOOL expect_close
,uint16 spid
)
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
)
410 dptr
= (dptr_struct
*)malloc(sizeof(dptr_struct
));
412 DEBUG(0,("malloc fail in dptr_create.\n"));
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);
440 if(dptr
->dnum
== -1 || dptr
->dnum
> 254) {
441 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr
->dnum
));
449 * This is a new-style trans2 request. Allocate from
450 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
453 dptr
->dnum
= bitmap_find(dptr_bmap
, 255);
455 if(dptr
->dnum
== -1 || dptr
->dnum
< 255) {
458 * Try and close the oldest handle close in the hope that
459 * the client has finished with that one. This will only
460 * happen in the case of the Win98 client bug where it leaks
464 dptr_close_oldest(False
);
466 /* Now try again... */
467 dptr
->dnum
= bitmap_find(dptr_bmap
, 255);
469 if(dptr
->dnum
== -1 || dptr
->dnum
< 255) {
470 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr
->dnum
));
477 bitmap_set(dptr_bmap
, dptr
->dnum
);
479 dptr
->dnum
+= 1; /* Always bias the dnum by one - no zero dnums allowed. */
481 dptr
->ptr
= conn
->dirptr
;
482 string_set(&dptr
->path
,path
);
485 dptr
->expect_close
= expect_close
;
486 dptr
->wcard
= NULL
; /* Only used in lanman2 searches */
487 dptr
->attr
= 0; /* Only used in lanman2 searches */
489 DLIST_ADD(dirptrs
, dptr
);
491 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
492 dptr
->dnum
,path
,expect_close
));
497 /****************************************************************************
498 Fill the 5 byte server reserved dptr field.
499 ****************************************************************************/
501 BOOL
dptr_fill(char *buf1
,unsigned int key
)
503 unsigned char *buf
= (unsigned char *)buf1
;
504 void *p
= dptr_ptr(key
);
507 DEBUG(1,("filling null dirptr %d\n",key
));
511 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key
,
512 (long)p
,(int)offset
));
514 SIVAL(buf
,1,offset
| DPTR_MASK
);
518 /****************************************************************************
519 Fetch the dir ptr and seek it given the 5 byte server field.
520 ****************************************************************************/
522 void *dptr_fetch(char *buf
,int *num
)
524 unsigned int key
= *(unsigned char *)buf
;
525 void *p
= dptr_ptr(key
);
528 DEBUG(3,("fetched null dirptr %d\n",key
));
532 offset
= IVAL(buf
,1)&~DPTR_MASK
;
534 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
535 key
,dptr_path(key
),offset
));
539 /****************************************************************************
541 ****************************************************************************/
543 void *dptr_fetch_lanman2(int dptr_num
)
545 void *p
= dptr_ptr(dptr_num
);
548 DEBUG(3,("fetched null dirptr %d\n",dptr_num
));
551 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num
,dptr_path(dptr_num
)));
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
)
563 /* Check the "may have" search bits. */
564 if (((mode
& ~dirtype
) & (aHIDDEN
| aSYSTEM
| aDIR
)) != 0)
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 */
572 if((mask
& (mode
& (aDIR
|aARCH
|aRONLY
|aHIDDEN
|aSYSTEM
))) == mask
) /* check if matching attribute present */
581 static BOOL
mangle_mask_match(connection_struct
*conn
, char *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
,char *fname
,
592 SMB_OFF_T
*size
,int *mode
,time_t *date
,BOOL check_descend
)
596 SMB_STRUCT_STAT sbuf
;
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] != '/');
616 dname
= ReadDirName(conn
->dirptr
);
618 DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
619 (long)conn
->dirptr
,TellDir(conn
->dirptr
)));
624 pstrcpy(filename
,dname
);
626 /* notice the special *.* handling. This appears to be the only difference
627 between the wildcard handling in this routine and in the trans2 routines.
628 see masktest for a demo
630 if ((strcmp(mask
,"*.*") == 0) ||
631 mask_match(filename
,mask
,False
) ||
632 mangle_mask_match(conn
,filename
,mask
))
634 if (isrootdir
&& (strequal(filename
,"..") || strequal(filename
,".")))
637 if (!mangle_is_8_3(filename
, False
)) {
638 mangle_map(filename
,True
,False
,SNUM(conn
));
641 pstrcpy(fname
,filename
);
643 pstrcpy(path
,conn
->dirpath
);
646 pstrcpy(pathreal
,path
);
648 pstrcat(pathreal
,dname
);
649 if (conn
->vfs_ops
.stat(conn
,dos_to_unix_static(pathreal
), &sbuf
) != 0)
651 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path
, strerror(errno
) ));
655 *mode
= dos_mode(conn
,pathreal
,&sbuf
);
657 if (!dir_check_ftype(conn
,*mode
,&sbuf
,dirtype
))
659 DEBUG(5,("[%s] attribs didn't match %x\n",filename
,dirtype
));
663 *size
= sbuf
.st_size
;
664 *date
= sbuf
.st_mtime
;
666 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask
, pathreal
,fname
));
688 /*******************************************************************
689 check to see if a user can read a file. This is only approximate,
690 it is used as part of the "hide unreadable" option. Don't
691 use it for anything security sensitive
692 ********************************************************************/
694 static BOOL
user_can_read_file(connection_struct
*conn
, char *name
)
696 extern struct current_user current_user
;
698 SEC_DESC
*psd
= NULL
;
703 uint32 access_granted
;
708 * If user is a member of the Admin group
709 * we never hide files from them.
712 if (conn
->admin_user
)
715 /* If we can't stat it does not show it */
716 if (vfs_stat(conn
, name
, &ste
) != 0)
719 /* Pseudo-open the file (note - no fd's created). */
721 if(S_ISDIR(ste
.st_mode
))
722 fsp
= open_directory(conn
, name
, &ste
, 0, SET_DENY_MODE(DENY_NONE
), (FILE_FAIL_IF_NOT_EXIST
|FILE_EXISTS_OPEN
),
723 unix_mode(conn
,aRONLY
|aDIR
, name
), &smb_action
);
725 fsp
= open_file_stat(conn
, name
, &ste
);
730 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
731 sd_size
= conn
->vfs_ops
.fget_nt_acl(fsp
, fsp
->fd
, &psd
);
732 close_file(fsp
, True
);
734 /* No access if SD get failed. */
738 return se_access_check(psd
, current_user
.nt_user_token
, FILE_READ_DATA
,
739 &access_granted
, &status
);
742 /*******************************************************************
744 ********************************************************************/
746 void *OpenDir(connection_struct
*conn
, const char *name
, BOOL use_veto
)
750 DIR *p
= conn
->vfs_ops
.opendir(conn
,dos_to_unix_static(name
));
755 dirp
= (Dir
*)malloc(sizeof(Dir
));
757 DEBUG(0,("Out of memory in OpenDir\n"));
758 conn
->vfs_ops
.closedir(conn
,p
);
762 dirp
->pos
= dirp
->numentries
= dirp
->mallocsize
= 0;
763 dirp
->data
= dirp
->current
= NULL
;
767 BOOL normal_entry
= True
;
771 normal_entry
= False
;
772 } else if (used
== 2) {
774 normal_entry
= False
;
776 n
= vfs_readdirname(conn
, p
);
779 if ((strcmp(".",n
) == 0) ||(strcmp("..",n
) == 0))
786 /* Return value of vfs_readdirname has already gone through
789 /* If it's a vetoed file, pretend it doesn't even exist */
790 if (normal_entry
&& use_veto
&& conn
&& IS_VETO_PATH(conn
, n
))
793 /* Honour _hide unreadable_ option */
794 if (normal_entry
&& conn
&& lp_hideunreadable(SNUM(conn
))) {
798 if (asprintf(&entry
, "%s/%s/%s", conn
->origpath
, name
, n
) > 0) {
799 ret
= user_can_read_file(conn
, entry
);
806 if (used
+ l
> dirp
->mallocsize
) {
807 int s
= MAX(used
+l
,used
+2000);
809 r
= (char *)Realloc(dirp
->data
,s
);
811 DEBUG(0,("Out of memory in OpenDir\n"));
815 dirp
->mallocsize
= s
;
816 dirp
->current
= dirp
->data
;
818 pstrcpy(dirp
->data
+used
,n
);
823 conn
->vfs_ops
.closedir(conn
,p
);
824 return((void *)dirp
);
828 /*******************************************************************
830 ********************************************************************/
832 void CloseDir(void *p
)
834 Dir
*dirp
= (Dir
*)p
;
836 SAFE_FREE(dirp
->data
);
840 /*******************************************************************
841 Read from a directory.
842 ********************************************************************/
844 char *ReadDirName(void *p
)
847 Dir
*dirp
= (Dir
*)p
;
849 if (!dirp
|| !dirp
->current
|| dirp
->pos
>= dirp
->numentries
) return(NULL
);
852 dirp
->current
= skip_string(dirp
->current
,1);
859 /*******************************************************************
861 ********************************************************************/
863 BOOL
SeekDir(void *p
,int pos
)
865 Dir
*dirp
= (Dir
*)p
;
867 if (!dirp
) return(False
);
869 if (pos
< dirp
->pos
) {
870 dirp
->current
= dirp
->data
;
874 while (dirp
->pos
< pos
&& ReadDirName(p
)) ;
876 return(dirp
->pos
== pos
);
879 /*******************************************************************
881 ********************************************************************/
885 Dir
*dirp
= (Dir
*)p
;
887 if (!dirp
) return(-1);
892 /*******************************************************************************
893 This section manages a global directory cache.
894 (It should probably be split into a separate module. crh)
895 ********************************************************************************/
905 static ubi_dlNewList( dir_cache
);
907 /*****************************************************************************
908 Add an entry to the directory cache.
914 *****************************************************************************/
916 void DirCacheAdd( const char *path
, const char *name
, const char *dname
, int snum
)
920 dir_cache_entry
*entry
;
922 /* Allocate the structure & string space in one go so that it can be freed
923 * in one call to free().
925 pathlen
= strlen( path
) +1; /* Bytes required to store path (with nul). */
926 namelen
= strlen( name
) +1; /* Bytes required to store name (with nul). */
927 entry
= (dir_cache_entry
*)malloc( sizeof( dir_cache_entry
)
930 + strlen( dname
) +1 );
931 if( NULL
== entry
) /* Not adding to the cache is not fatal, */
932 return; /* so just return as if nothing happened. */
934 /* Set pointers correctly and load values. */
935 entry
->path
= memcpy( (char *)&entry
[1], path
, strlen(path
)+1 );
936 entry
->name
= memcpy( &(entry
->path
[pathlen
]), name
, strlen(name
)+1 );
937 entry
->dname
= memcpy( &(entry
->name
[namelen
]), dname
, strlen(dname
)+1 );
940 /* Add the new entry to the linked list. */
941 (void)ubi_dlAddHead( dir_cache
, entry
);
942 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path
, name
, dname
) );
944 /* Free excess cache entries. */
945 while( DIRCACHESIZE
< dir_cache
->count
)
946 safe_free( ubi_dlRemTail( dir_cache
) );
950 /*****************************************************************************
951 Search for an entry to the directory cache.
955 Output: The dname string of the located entry, or NULL if the entry was
958 Notes: This uses a linear search, which is is okay because of
959 the small size of the cache. Use a splay tree or hash
961 *****************************************************************************/
963 char *DirCacheCheck( const char *path
, const char *name
, int snum
)
965 dir_cache_entry
*entry
;
967 for( entry
= (dir_cache_entry
*)ubi_dlFirst( dir_cache
);
969 entry
= (dir_cache_entry
*)ubi_dlNext( entry
) )
971 if( entry
->snum
== snum
972 && entry
->name
&& 0 == strcmp( name
, entry
->name
)
973 && entry
->path
&& 0 == strcmp( path
, entry
->path
) )
975 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path
,name
,entry
->dname
));
976 return( entry
->dname
);
983 /*****************************************************************************
984 Remove all cache entries which have an snum that matches the input.
987 *****************************************************************************/
989 void DirCacheFlush(int snum
)
991 dir_cache_entry
*entry
;
994 for(entry
= (dir_cache_entry
*)ubi_dlFirst( dir_cache
);
996 next
= ubi_dlNext( entry
);
997 if( entry
->snum
== snum
)
998 safe_free( ubi_dlRemThis( dir_cache
, entry
) );
999 entry
= (dir_cache_entry
*)next
;