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 */
249 SAFE_FREE(dptr
->wcard
);
250 string_set(&dptr
->path
,"");
254 /****************************************************************************
255 Close a dptr given a key.
256 ****************************************************************************/
258 void dptr_close(int *key
)
262 if(*key
== INVALID_DPTR_KEY
)
265 /* OS/2 seems to use -1 to indicate "close all directories" */
268 for(dptr
= dirptrs
; dptr
; dptr
= next
) {
270 dptr_close_internal(dptr
);
272 *key
= INVALID_DPTR_KEY
;
276 dptr
= dptr_get(*key
, True
);
279 DEBUG(0,("Invalid key %d given to dptr_close\n", *key
));
283 dptr_close_internal(dptr
);
285 *key
= INVALID_DPTR_KEY
;
288 /****************************************************************************
289 Close all dptrs for a cnum.
290 ****************************************************************************/
292 void dptr_closecnum(connection_struct
*conn
)
294 dptr_struct
*dptr
, *next
;
295 for(dptr
= dirptrs
; dptr
; dptr
= next
) {
297 if (dptr
->conn
== conn
)
298 dptr_close_internal(dptr
);
302 /****************************************************************************
303 Idle all dptrs for a cnum.
304 ****************************************************************************/
306 void dptr_idlecnum(connection_struct
*conn
)
309 for(dptr
= dirptrs
; dptr
; dptr
= dptr
->next
) {
310 if (dptr
->conn
== conn
&& dptr
->ptr
)
315 /****************************************************************************
316 Close a dptr that matches a given path, only if it matches the spid also.
317 ****************************************************************************/
319 void dptr_closepath(char *path
,uint16 spid
)
321 dptr_struct
*dptr
, *next
;
322 for(dptr
= dirptrs
; dptr
; dptr
= next
) {
324 if (spid
== dptr
->spid
&& strequal(dptr
->path
,path
))
325 dptr_close_internal(dptr
);
329 /****************************************************************************
330 Start a directory listing.
331 ****************************************************************************/
333 static BOOL
start_dir(connection_struct
*conn
,char *directory
)
335 DEBUG(5,("start_dir dir=%s\n",directory
));
337 if (!check_name(directory
,conn
))
343 conn
->dirptr
= OpenDir(conn
, directory
, True
);
346 string_set(&conn
->dirpath
,directory
);
353 /****************************************************************************
354 Try and close the oldest handle not marked for
355 expect close in the hope that the client has
356 finished with that one.
357 ****************************************************************************/
359 static void dptr_close_oldest(BOOL old
)
364 * Go to the end of the list.
366 for(dptr
= dirptrs
; dptr
&& dptr
->next
; dptr
= dptr
->next
)
370 DEBUG(0,("No old dptrs available to close oldest ?\n"));
375 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
376 * does not have expect_close set. If 'old' is false, close
377 * one of the new dnum handles.
380 for(; dptr
; dptr
= dptr
->prev
) {
381 if ((old
&& (dptr
->dnum
< 256) && !dptr
->expect_close
) ||
382 (!old
&& (dptr
->dnum
> 255))) {
383 dptr_close_internal(dptr
);
389 /****************************************************************************
390 Create a new dir ptr. If the flag old_handle is true then we must allocate
391 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
392 one byte long. If old_handle is false we allocate from the range
393 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
394 a directory handle is never zero. All the above is folklore taught to
395 me at Andrew's knee.... :-) :-). JRA.
396 ****************************************************************************/
398 int dptr_create(connection_struct
*conn
,char *path
, BOOL old_handle
, BOOL expect_close
,uint16 spid
)
402 if (!start_dir(conn
,path
))
403 return(-2); /* Code to say use a unix error return code. */
405 if (dptrs_open
>= MAX_OPEN_DIRECTORIES
)
408 dptr
= (dptr_struct
*)malloc(sizeof(dptr_struct
));
410 DEBUG(0,("malloc fail in dptr_create.\n"));
419 * This is an old-style SMBsearch request. Ensure the
420 * value we return will fit in the range 1-255.
423 dptr
->dnum
= bitmap_find(dptr_bmap
, 0);
425 if(dptr
->dnum
== -1 || dptr
->dnum
> 254) {
428 * Try and close the oldest handle not marked for
429 * expect close in the hope that the client has
430 * finished with that one.
433 dptr_close_oldest(True
);
435 /* Now try again... */
436 dptr
->dnum
= bitmap_find(dptr_bmap
, 0);
438 if(dptr
->dnum
== -1 || dptr
->dnum
> 254) {
439 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr
->dnum
));
447 * This is a new-style trans2 request. Allocate from
448 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
451 dptr
->dnum
= bitmap_find(dptr_bmap
, 255);
453 if(dptr
->dnum
== -1 || dptr
->dnum
< 255) {
456 * Try and close the oldest handle close in the hope that
457 * the client has finished with that one. This will only
458 * happen in the case of the Win98 client bug where it leaks
462 dptr_close_oldest(False
);
464 /* Now try again... */
465 dptr
->dnum
= bitmap_find(dptr_bmap
, 255);
467 if(dptr
->dnum
== -1 || dptr
->dnum
< 255) {
468 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr
->dnum
));
475 bitmap_set(dptr_bmap
, dptr
->dnum
);
477 dptr
->dnum
+= 1; /* Always bias the dnum by one - no zero dnums allowed. */
479 dptr
->ptr
= conn
->dirptr
;
480 string_set(&dptr
->path
,path
);
483 dptr
->expect_close
= expect_close
;
484 dptr
->wcard
= NULL
; /* Only used in lanman2 searches */
485 dptr
->attr
= 0; /* Only used in lanman2 searches */
487 DLIST_ADD(dirptrs
, dptr
);
489 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
490 dptr
->dnum
,path
,expect_close
));
495 /****************************************************************************
496 Fill the 5 byte server reserved dptr field.
497 ****************************************************************************/
499 BOOL
dptr_fill(char *buf1
,unsigned int key
)
501 unsigned char *buf
= (unsigned char *)buf1
;
502 void *p
= dptr_ptr(key
);
505 DEBUG(1,("filling null dirptr %d\n",key
));
509 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key
,
510 (long)p
,(int)offset
));
512 SIVAL(buf
,1,offset
| DPTR_MASK
);
516 /****************************************************************************
517 Fetch the dir ptr and seek it given the 5 byte server field.
518 ****************************************************************************/
520 void *dptr_fetch(char *buf
,int *num
)
522 unsigned int key
= *(unsigned char *)buf
;
523 void *p
= dptr_ptr(key
);
526 DEBUG(3,("fetched null dirptr %d\n",key
));
530 offset
= IVAL(buf
,1)&~DPTR_MASK
;
532 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
533 key
,dptr_path(key
),offset
));
537 /****************************************************************************
539 ****************************************************************************/
541 void *dptr_fetch_lanman2(int dptr_num
)
543 void *p
= dptr_ptr(dptr_num
);
546 DEBUG(3,("fetched null dirptr %d\n",dptr_num
));
549 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num
,dptr_path(dptr_num
)));
553 /****************************************************************************
554 Check a filetype for being valid.
555 ****************************************************************************/
557 BOOL
dir_check_ftype(connection_struct
*conn
,int mode
,SMB_STRUCT_STAT
*st
,int dirtype
)
559 if (((mode
& ~dirtype
) & (aHIDDEN
| aSYSTEM
| aDIR
)) != 0)
564 /****************************************************************************
565 Get an 8.3 directory entry.
566 ****************************************************************************/
568 BOOL
get_dir_entry(connection_struct
*conn
,char *mask
,int dirtype
,char *fname
,
569 SMB_OFF_T
*size
,int *mode
,time_t *date
,BOOL check_descend
)
573 SMB_STRUCT_STAT sbuf
;
580 *path
= *pathreal
= *filename
= 0;
582 isrootdir
= (strequal(conn
->dirpath
,"./") ||
583 strequal(conn
->dirpath
,".") ||
584 strequal(conn
->dirpath
,"/"));
586 needslash
= ( conn
->dirpath
[strlen(conn
->dirpath
) -1] != '/');
593 dname
= ReadDirName(conn
->dirptr
);
595 DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
596 (long)conn
->dirptr
,TellDir(conn
->dirptr
)));
601 pstrcpy(filename
,dname
);
603 /* notice the special *.* handling. This appears to be the only difference
604 between the wildcard handling in this routine and in the trans2 routines.
605 see masktest for a demo
607 if ((strcmp(mask
,"*.*") == 0) ||
608 mask_match(filename
,mask
,False
) ||
609 (name_map_mangle(filename
,True
,False
,SNUM(conn
)) &&
610 mask_match(filename
,mask
,False
)))
612 if (isrootdir
&& (strequal(filename
,"..") || strequal(filename
,".")))
615 if (!is_8_3(filename
, False
)) {
616 name_map_mangle(filename
,True
,False
,SNUM(conn
));
619 pstrcpy(fname
,filename
);
621 pstrcpy(path
,conn
->dirpath
);
624 pstrcpy(pathreal
,path
);
626 pstrcat(pathreal
,dname
);
627 if (conn
->vfs_ops
.stat(conn
, pathreal
, &sbuf
) != 0)
629 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path
, strerror(errno
) ));
633 *mode
= dos_mode(conn
,pathreal
,&sbuf
);
635 if (!dir_check_ftype(conn
,*mode
,&sbuf
,dirtype
))
637 DEBUG(5,("[%s] attribs didn't match %x\n",filename
,dirtype
));
641 *size
= sbuf
.st_size
;
642 *date
= sbuf
.st_mtime
;
644 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask
, pathreal
,fname
));
666 /*******************************************************************
667 check to see if a user can read a file. This is only approximate,
668 it is used as part of the "hide unreadable" option. Don't
669 use it for anything security sensitive
670 ********************************************************************/
671 static BOOL
user_can_read_file(connection_struct
*conn
, char *name
)
675 /* if we can't stat it does not show it */
676 if (vfs_stat(conn
, name
, &ste
) != 0) return False
;
678 if (ste
.st_uid
== conn
->uid
) {
679 return (ste
.st_mode
& S_IRUSR
) == S_IRUSR
;
682 if (ste
.st_gid
== conn
->gid
) {
683 return (ste
.st_mode
& S_IRGRP
) == S_IRGRP
;
685 for (i
=0; i
<conn
->ngroups
; i
++) {
686 if (conn
->groups
[i
] == ste
.st_gid
) {
687 return (ste
.st_mode
& S_IRGRP
) == S_IRGRP
;
692 return (ste
.st_mode
& S_IROTH
) == S_IROTH
;
695 /*******************************************************************
697 ********************************************************************/
699 void *OpenDir(connection_struct
*conn
, char *name
, BOOL use_veto
)
703 DIR *p
= conn
->vfs_ops
.opendir(conn
,name
);
706 if (!p
) return(NULL
);
707 dirp
= (Dir
*)malloc(sizeof(Dir
));
709 DEBUG(0,("Out of memory in OpenDir\n"));
710 conn
->vfs_ops
.closedir(conn
,p
);
713 dirp
->pos
= dirp
->numentries
= dirp
->mallocsize
= 0;
714 dirp
->data
= dirp
->current
= NULL
;
716 while ((n
= vfs_readdirname(conn
, p
)))
722 /* If it's a vetoed file, pretend it doesn't even exist */
723 if (use_veto
&& conn
&& IS_VETO_PATH(conn
, n
)) continue;
725 /* Honour _hide unreadable_ option */
726 if (conn
&& lp_hideunreadable(SNUM(conn
))) {
730 if (asprintf(&entry
, "%s/%s/%s", conn
->origpath
, name
, n
) > 0) {
731 ret
= user_can_read_file(conn
, entry
);
737 if (used
+ l
> dirp
->mallocsize
) {
738 int s
= MAX(used
+l
,used
+2000);
740 r
= (char *)Realloc(dirp
->data
,s
);
742 DEBUG(0,("Out of memory in OpenDir\n"));
746 dirp
->mallocsize
= s
;
747 dirp
->current
= dirp
->data
;
749 pstrcpy(dirp
->data
+used
,n
);
754 conn
->vfs_ops
.closedir(conn
,p
);
755 return((void *)dirp
);
759 /*******************************************************************
761 ********************************************************************/
763 void CloseDir(void *p
)
766 SAFE_FREE(((Dir
*)p
)->data
);
770 /*******************************************************************
771 Read from a directory.
772 ********************************************************************/
774 char *ReadDirName(void *p
)
777 Dir
*dirp
= (Dir
*)p
;
779 if (!dirp
|| !dirp
->current
|| dirp
->pos
>= dirp
->numentries
) return(NULL
);
782 dirp
->current
= skip_string(dirp
->current
,1);
789 /*******************************************************************
791 ********************************************************************/
793 BOOL
SeekDir(void *p
,int pos
)
795 Dir
*dirp
= (Dir
*)p
;
797 if (!dirp
) return(False
);
799 if (pos
< dirp
->pos
) {
800 dirp
->current
= dirp
->data
;
804 while (dirp
->pos
< pos
&& ReadDirName(p
)) ;
806 return(dirp
->pos
== pos
);
809 /*******************************************************************
811 ********************************************************************/
815 Dir
*dirp
= (Dir
*)p
;
817 if (!dirp
) return(-1);
822 /*******************************************************************************
823 This section manages a global directory cache.
824 (It should probably be split into a separate module. crh)
825 ********************************************************************************/
835 static ubi_dlNewList( dir_cache
);
837 /*****************************************************************************
838 Add an entry to the directory cache.
844 *****************************************************************************/
846 void DirCacheAdd( char *path
, char *name
, char *dname
, int snum
)
850 dir_cache_entry
*entry
;
852 /* Allocate the structure & string space in one go so that it can be freed
853 * in one call to free().
855 pathlen
= strlen( path
) +1; /* Bytes required to store path (with nul). */
856 namelen
= strlen( name
) +1; /* Bytes required to store name (with nul). */
857 entry
= (dir_cache_entry
*)malloc( sizeof( dir_cache_entry
)
860 + strlen( dname
) +1 );
861 if( NULL
== entry
) /* Not adding to the cache is not fatal, */
862 return; /* so just return as if nothing happened. */
864 /* Set pointers correctly and load values. */
865 entry
->path
= pstrcpy( (char *)&entry
[1], path
);
866 entry
->name
= pstrcpy( &(entry
->path
[pathlen
]), name
);
867 entry
->dname
= pstrcpy( &(entry
->name
[namelen
]), dname
);
870 /* Add the new entry to the linked list. */
871 (void)ubi_dlAddHead( dir_cache
, entry
);
872 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path
, name
, dname
) );
874 /* Free excess cache entries. */
875 while( DIRCACHESIZE
< dir_cache
->count
)
876 safe_free( ubi_dlRemTail( dir_cache
) );
880 /*****************************************************************************
881 Search for an entry to the directory cache.
885 Output: The dname string of the located entry, or NULL if the entry was
888 Notes: This uses a linear search, which is is okay because of
889 the small size of the cache. Use a splay tree or hash
891 *****************************************************************************/
893 char *DirCacheCheck( char *path
, char *name
, int snum
)
895 dir_cache_entry
*entry
;
897 for( entry
= (dir_cache_entry
*)ubi_dlFirst( dir_cache
);
899 entry
= (dir_cache_entry
*)ubi_dlNext( entry
) )
901 if( entry
->snum
== snum
902 && 0 == strcmp( name
, entry
->name
)
903 && 0 == strcmp( path
, entry
->path
) )
905 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path
,name
,entry
->dname
));
906 return( entry
->dname
);
913 /*****************************************************************************
914 Remove all cache entries which have an snum that matches the input.
917 *****************************************************************************/
919 void DirCacheFlush(int snum
)
921 dir_cache_entry
*entry
;
924 for(entry
= (dir_cache_entry
*)ubi_dlFirst( dir_cache
);
926 next
= ubi_dlNext( entry
);
927 if( entry
->snum
== snum
)
928 safe_free( ubi_dlRemThis( dir_cache
, entry
) );
929 entry
= (dir_cache_entry
*)next
;