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.
24 extern int DEBUGLEVEL
;
27 This module implements directory related functions for Samba.
30 typedef struct _dptr_struct
{
31 struct _dptr_struct
*next
, *prev
;
34 connection_struct
*conn
;
37 char *wcard
; /* Field only used for trans2_ searches */
38 uint16 attr
; /* Field only used for trans2_ searches */
42 static struct bitmap
*dptr_bmap
;
43 static dptr_struct
*dirptrs
;
45 static int dptrs_open
= 0;
47 #define INVALID_DPTR_KEY (-3)
49 /****************************************************************************
50 Initialise the dir bitmap.
51 ****************************************************************************/
55 static BOOL dptrs_init
=False
;
60 dptr_bmap
= bitmap_allocate(MAX_DIRECTORY_HANDLES
);
63 exit_server("out of memory in init_dptrs\n");
68 /****************************************************************************
69 Idle a dptr - the directory is closed but the control info is kept.
70 ****************************************************************************/
72 static void dptr_idle(dptr_struct
*dptr
)
75 DEBUG(4,("Idling dptr dnum %d\n",dptr
->dnum
));
82 /****************************************************************************
84 ****************************************************************************/
86 static void dptr_idleoldest(void)
91 * Go to the end of the list.
93 for(dptr
= dirptrs
; dptr
&& dptr
->next
; dptr
= dptr
->next
)
97 DEBUG(0,("No dptrs available to idle ?\n"));
102 * Idle the oldest pointer.
105 for(; dptr
; dptr
= dptr
->prev
) {
113 /****************************************************************************
114 Get the dptr_struct for a dir index.
115 ****************************************************************************/
117 static dptr_struct
*dptr_get(int key
, BOOL forclose
)
121 for(dptr
= dirptrs
; dptr
; dptr
= dptr
->next
) {
122 if(dptr
->dnum
== key
) {
123 if (!forclose
&& !dptr
->ptr
) {
124 if (dptrs_open
>= MAX_OPEN_DIRECTORIES
)
126 DEBUG(4,("Reopening dptr key %d\n",key
));
127 if ((dptr
->ptr
= OpenDir(dptr
->conn
, dptr
->path
, True
)))
130 DLIST_PROMOTE(dirptrs
,dptr
);
137 /****************************************************************************
138 Get the dptr ptr for a dir index.
139 ****************************************************************************/
141 static void *dptr_ptr(int key
)
143 dptr_struct
*dptr
= dptr_get(key
, False
);
150 /****************************************************************************
151 Get the dir path for a dir index.
152 ****************************************************************************/
154 char *dptr_path(int key
)
156 dptr_struct
*dptr
= dptr_get(key
, False
);
163 /****************************************************************************
164 Get the dir wcard for a dir index (lanman2 specific).
165 ****************************************************************************/
167 char *dptr_wcard(int key
)
169 dptr_struct
*dptr
= dptr_get(key
, False
);
176 /****************************************************************************
177 Set the dir wcard for a dir index (lanman2 specific).
178 Returns 0 on ok, 1 on fail.
179 ****************************************************************************/
181 BOOL
dptr_set_wcard(int key
, char *wcard
)
183 dptr_struct
*dptr
= dptr_get(key
, False
);
192 /****************************************************************************
193 Set the dir attrib for a dir index (lanman2 specific).
194 Returns 0 on ok, 1 on fail.
195 ****************************************************************************/
197 BOOL
dptr_set_attr(int key
, uint16 attr
)
199 dptr_struct
*dptr
= dptr_get(key
, False
);
208 /****************************************************************************
209 Get the dir attrib for a dir index (lanman2 specific)
210 ****************************************************************************/
212 uint16
dptr_attr(int key
)
214 dptr_struct
*dptr
= dptr_get(key
, False
);
221 /****************************************************************************
222 Close a dptr (internal func).
223 ****************************************************************************/
225 static void dptr_close_internal(dptr_struct
*dptr
)
227 DEBUG(4,("closing dptr key %d\n",dptr
->dnum
));
229 DLIST_REMOVE(dirptrs
, dptr
);
232 * Free the dnum in the bitmap. Remember the dnum value is always
233 * biased by one with respect to the bitmap.
236 if(bitmap_query( dptr_bmap
, dptr
->dnum
- 1) != True
) {
237 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
241 bitmap_clear(dptr_bmap
, dptr
->dnum
- 1);
248 /* Lanman 2 specific code */
251 string_set(&dptr
->path
,"");
255 /****************************************************************************
256 Close a dptr given a key.
257 ****************************************************************************/
259 void dptr_close(int *key
)
263 if(*key
== INVALID_DPTR_KEY
)
266 /* OS/2 seems to use -1 to indicate "close all directories" */
269 for(dptr
= dirptrs
; dptr
; dptr
= next
) {
271 dptr_close_internal(dptr
);
273 *key
= INVALID_DPTR_KEY
;
277 dptr
= dptr_get(*key
, True
);
280 DEBUG(0,("Invalid key %d given to dptr_close\n", *key
));
284 dptr_close_internal(dptr
);
286 *key
= INVALID_DPTR_KEY
;
289 /****************************************************************************
290 Close all dptrs for a cnum.
291 ****************************************************************************/
293 void dptr_closecnum(connection_struct
*conn
)
295 dptr_struct
*dptr
, *next
;
296 for(dptr
= dirptrs
; dptr
; dptr
= next
) {
298 if (dptr
->conn
== conn
)
299 dptr_close_internal(dptr
);
303 /****************************************************************************
304 Idle all dptrs for a cnum.
305 ****************************************************************************/
307 void dptr_idlecnum(connection_struct
*conn
)
310 for(dptr
= dirptrs
; dptr
; dptr
= dptr
->next
) {
311 if (dptr
->conn
== conn
&& dptr
->ptr
)
316 /****************************************************************************
317 Close a dptr that matches a given path, only if it matches the spid also.
318 ****************************************************************************/
320 void dptr_closepath(char *path
,uint16 spid
)
322 dptr_struct
*dptr
, *next
;
323 for(dptr
= dirptrs
; dptr
; dptr
= next
) {
325 if (spid
== dptr
->spid
&& strequal(dptr
->path
,path
))
326 dptr_close_internal(dptr
);
330 /****************************************************************************
331 Start a directory listing.
332 ****************************************************************************/
334 static BOOL
start_dir(connection_struct
*conn
,char *directory
)
336 DEBUG(5,("start_dir dir=%s\n",directory
));
338 if (!check_name(directory
,conn
))
344 conn
->dirptr
= OpenDir(conn
, directory
, True
);
347 string_set(&conn
->dirpath
,directory
);
354 /****************************************************************************
355 Try and close the oldest handle not marked for
356 expect close in the hope that the client has
357 finished with that one.
358 ****************************************************************************/
360 static void dptr_close_oldest(BOOL old
)
365 * Go to the end of the list.
367 for(dptr
= dirptrs
; dptr
&& dptr
->next
; dptr
= dptr
->next
)
371 DEBUG(0,("No old dptrs available to close oldest ?\n"));
376 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
377 * does not have expect_close set. If 'old' is false, close
378 * one of the new dnum handles.
381 for(; dptr
; dptr
= dptr
->prev
) {
382 if ((old
&& (dptr
->dnum
< 256) && !dptr
->expect_close
) ||
383 (!old
&& (dptr
->dnum
> 255))) {
384 dptr_close_internal(dptr
);
390 /****************************************************************************
391 Create a new dir ptr. If the flag old_handle is true then we must allocate
392 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
393 one byte long. If old_handle is false we allocate from the range
394 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
395 a directory handle is never zero. All the above is folklore taught to
396 me at Andrew's knee.... :-) :-). JRA.
397 ****************************************************************************/
399 int dptr_create(connection_struct
*conn
,char *path
, BOOL old_handle
, BOOL expect_close
,uint16 spid
)
403 if (!start_dir(conn
,path
))
404 return(-2); /* Code to say use a unix error return code. */
406 if (dptrs_open
>= MAX_OPEN_DIRECTORIES
)
409 dptr
= (dptr_struct
*)malloc(sizeof(dptr_struct
));
411 DEBUG(0,("malloc fail in dptr_create.\n"));
420 * This is an old-style SMBsearch request. Ensure the
421 * value we return will fit in the range 1-255.
424 dptr
->dnum
= bitmap_find(dptr_bmap
, 0);
426 if(dptr
->dnum
== -1 || dptr
->dnum
> 254) {
429 * Try and close the oldest handle not marked for
430 * expect close in the hope that the client has
431 * finished with that one.
434 dptr_close_oldest(True
);
436 /* Now try again... */
437 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
));
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
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
));
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
);
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
));
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
);
506 DEBUG(1,("filling null dirptr %d\n",key
));
510 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key
,
511 (long)p
,(int)offset
));
513 SIVAL(buf
,1,offset
| DPTR_MASK
);
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
);
527 DEBUG(3,("fetched null dirptr %d\n",key
));
531 offset
= IVAL(buf
,1)&~DPTR_MASK
;
533 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
534 key
,dptr_path(key
),offset
));
538 /****************************************************************************
540 ****************************************************************************/
542 void *dptr_fetch_lanman2(int dptr_num
)
544 void *p
= dptr_ptr(dptr_num
);
547 DEBUG(3,("fetched null dirptr %d\n",dptr_num
));
550 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num
,dptr_path(dptr_num
)));
554 /****************************************************************************
555 Check a filetype for being valid.
556 ****************************************************************************/
558 BOOL
dir_check_ftype(connection_struct
*conn
,int mode
,SMB_STRUCT_STAT
*st
,int dirtype
)
560 if (((mode
& ~dirtype
) & (aHIDDEN
| aSYSTEM
| aDIR
)) != 0)
565 /****************************************************************************
566 Get an 8.3 directory entry.
567 ****************************************************************************/
569 BOOL
get_dir_entry(connection_struct
*conn
,char *mask
,int dirtype
,char *fname
,
570 SMB_OFF_T
*size
,int *mode
,time_t *date
,BOOL check_descend
)
574 SMB_STRUCT_STAT sbuf
;
581 *path
= *pathreal
= *filename
= 0;
583 isrootdir
= (strequal(conn
->dirpath
,"./") ||
584 strequal(conn
->dirpath
,".") ||
585 strequal(conn
->dirpath
,"/"));
587 needslash
= ( conn
->dirpath
[strlen(conn
->dirpath
) -1] != '/');
594 dname
= ReadDirName(conn
->dirptr
);
596 DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
597 (long)conn
->dirptr
,TellDir(conn
->dirptr
)));
602 pstrcpy(filename
,dname
);
604 /* notice the special *.* handling. This appears to be the only difference
605 between the wildcard handling in this routine and in the trans2 routines.
606 see masktest for a demo
608 if ((strcmp(mask
,"*.*") == 0) ||
609 mask_match(filename
,mask
,False
) ||
610 (name_map_mangle(filename
,True
,False
,SNUM(conn
)) &&
611 mask_match(filename
,mask
,False
)))
613 if (isrootdir
&& (strequal(filename
,"..") || strequal(filename
,".")))
616 if (!is_8_3(filename
, False
)) {
617 name_map_mangle(filename
,True
,False
,SNUM(conn
));
620 pstrcpy(fname
,filename
);
622 pstrcpy(path
,conn
->dirpath
);
625 pstrcpy(pathreal
,path
);
627 pstrcat(pathreal
,dname
);
628 if (conn
->vfs_ops
.stat(conn
,dos_to_unix(pathreal
, False
), &sbuf
) != 0)
630 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path
, strerror(errno
) ));
634 *mode
= dos_mode(conn
,pathreal
,&sbuf
);
636 if (!dir_check_ftype(conn
,*mode
,&sbuf
,dirtype
))
638 DEBUG(5,("[%s] attribs didn't match %x\n",filename
,dirtype
));
642 *size
= sbuf
.st_size
;
643 *date
= sbuf
.st_mtime
;
645 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask
, pathreal
,fname
));
667 /*******************************************************************
668 check to see if a user can read a file. This is only approximate,
669 it is used as part of the "hide unreadable" option. Don't
670 use it for anything security sensitive
671 ********************************************************************/
672 static BOOL
user_can_read_file(connection_struct
*conn
, char *name
)
676 /* if we can't stat it does not show it */
677 if (vfs_stat(conn
, name
, &ste
) != 0) return False
;
679 if (ste
.st_uid
== conn
->uid
) {
680 return (ste
.st_mode
& S_IRUSR
) == S_IRUSR
;
683 if (ste
.st_gid
== conn
->gid
) {
684 return (ste
.st_mode
& S_IRGRP
) == S_IRGRP
;
686 for (i
=0; i
<conn
->ngroups
; i
++) {
687 if (conn
->groups
[i
] == ste
.st_gid
) {
688 return (ste
.st_mode
& S_IRGRP
) == S_IRGRP
;
693 return (ste
.st_mode
& S_IROTH
) == S_IROTH
;
696 /*******************************************************************
698 ********************************************************************/
700 void *OpenDir(connection_struct
*conn
, char *name
, BOOL use_veto
)
704 DIR *p
= conn
->vfs_ops
.opendir(conn
,dos_to_unix(name
,False
));
707 if (!p
) return(NULL
);
708 dirp
= (Dir
*)malloc(sizeof(Dir
));
710 DEBUG(0,("Out of memory in OpenDir\n"));
711 conn
->vfs_ops
.closedir(conn
,p
);
714 dirp
->pos
= dirp
->numentries
= dirp
->mallocsize
= 0;
715 dirp
->data
= dirp
->current
= NULL
;
717 while ((n
= vfs_readdirname(conn
, p
)))
723 /* Return value of vfs_readdirname has already gone through
726 /* If it's a vetoed file, pretend it doesn't even exist */
727 if (use_veto
&& conn
&& IS_VETO_PATH(conn
, n
)) continue;
729 /* Honour _hide unreadable_ option */
730 if (conn
&& lp_hideunreadable(SNUM(conn
))) {
734 if (asprintf(&entry
, "%s/%s/%s", conn
->origpath
, name
, n
) > 0) {
735 ret
= user_can_read_file(conn
, entry
);
741 if (used
+ l
> dirp
->mallocsize
) {
742 int s
= MAX(used
+l
,used
+2000);
744 r
= (char *)Realloc(dirp
->data
,s
);
746 DEBUG(0,("Out of memory in OpenDir\n"));
750 dirp
->mallocsize
= s
;
751 dirp
->current
= dirp
->data
;
753 pstrcpy(dirp
->data
+used
,n
);
758 conn
->vfs_ops
.closedir(conn
,p
);
759 return((void *)dirp
);
763 /*******************************************************************
765 ********************************************************************/
767 void CloseDir(void *p
)
769 Dir
*dirp
= (Dir
*)p
;
771 if (dirp
->data
) free(dirp
->data
);
775 /*******************************************************************
776 Read from a directory.
777 ********************************************************************/
779 char *ReadDirName(void *p
)
782 Dir
*dirp
= (Dir
*)p
;
784 if (!dirp
|| !dirp
->current
|| dirp
->pos
>= dirp
->numentries
) return(NULL
);
787 dirp
->current
= skip_string(dirp
->current
,1);
794 /*******************************************************************
796 ********************************************************************/
798 BOOL
SeekDir(void *p
,int pos
)
800 Dir
*dirp
= (Dir
*)p
;
802 if (!dirp
) return(False
);
804 if (pos
< dirp
->pos
) {
805 dirp
->current
= dirp
->data
;
809 while (dirp
->pos
< pos
&& ReadDirName(p
)) ;
811 return(dirp
->pos
== pos
);
814 /*******************************************************************
816 ********************************************************************/
820 Dir
*dirp
= (Dir
*)p
;
822 if (!dirp
) return(-1);
827 /*******************************************************************************
828 This section manages a global directory cache.
829 (It should probably be split into a separate module. crh)
830 ********************************************************************************/
840 static ubi_dlNewList( dir_cache
);
842 /*****************************************************************************
843 Add an entry to the directory cache.
849 *****************************************************************************/
851 void DirCacheAdd( char *path
, char *name
, char *dname
, int snum
)
855 dir_cache_entry
*entry
;
857 /* Allocate the structure & string space in one go so that it can be freed
858 * in one call to free().
860 pathlen
= strlen( path
) +1; /* Bytes required to store path (with nul). */
861 namelen
= strlen( name
) +1; /* Bytes required to store name (with nul). */
862 entry
= (dir_cache_entry
*)malloc( sizeof( dir_cache_entry
)
865 + strlen( dname
) +1 );
866 if( NULL
== entry
) /* Not adding to the cache is not fatal, */
867 return; /* so just return as if nothing happened. */
869 /* Set pointers correctly and load values. */
870 entry
->path
= pstrcpy( (char *)&entry
[1], path
);
871 entry
->name
= pstrcpy( &(entry
->path
[pathlen
]), name
);
872 entry
->dname
= pstrcpy( &(entry
->name
[namelen
]), dname
);
875 /* Add the new entry to the linked list. */
876 (void)ubi_dlAddHead( dir_cache
, entry
);
877 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path
, name
, dname
) );
879 /* Free excess cache entries. */
880 while( DIRCACHESIZE
< dir_cache
->count
)
881 free( ubi_dlRemTail( dir_cache
) );
885 /*****************************************************************************
886 Search for an entry to the directory cache.
890 Output: The dname string of the located entry, or NULL if the entry was
893 Notes: This uses a linear search, which is is okay because of
894 the small size of the cache. Use a splay tree or hash
896 *****************************************************************************/
898 char *DirCacheCheck( char *path
, char *name
, int snum
)
900 dir_cache_entry
*entry
;
902 for( entry
= (dir_cache_entry
*)ubi_dlFirst( dir_cache
);
904 entry
= (dir_cache_entry
*)ubi_dlNext( entry
) )
906 if( entry
->snum
== snum
907 && 0 == strcmp( name
, entry
->name
)
908 && 0 == strcmp( path
, entry
->path
) )
910 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path
,name
,entry
->dname
));
911 return( entry
->dname
);
918 /*****************************************************************************
919 Remove all cache entries which have an snum that matches the input.
922 *****************************************************************************/
924 void DirCacheFlush(int snum
)
926 dir_cache_entry
*entry
;
929 for(entry
= (dir_cache_entry
*)ubi_dlFirst( dir_cache
);
931 next
= ubi_dlNext( entry
);
932 if( entry
->snum
== snum
)
933 free( ubi_dlRemThis( dir_cache
, entry
) );
934 entry
= (dir_cache_entry
*)next
;