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 BOOL filename_is_mask
= False
;
595 dname
= ReadDirName(conn
->dirptr
);
597 DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
598 (long)conn
->dirptr
,TellDir(conn
->dirptr
)));
603 pstrcpy(filename
,dname
);
605 if ((filename_is_mask
= (strcmp(filename
,mask
) == 0)) ||
606 (name_map_mangle(filename
,True
,False
,SNUM(conn
)) &&
607 mask_match(filename
,mask
,False
,False
)))
609 if (isrootdir
&& (strequal(filename
,"..") || strequal(filename
,".")))
612 pstrcpy(fname
,filename
);
614 pstrcpy(path
,conn
->dirpath
);
617 pstrcpy(pathreal
,path
);
619 pstrcat(pathreal
,dname
);
620 if (dos_stat(pathreal
,&sbuf
) != 0)
622 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path
, strerror(errno
) ));
626 if (check_descend
&& !strequal(fname
,".") && !strequal(fname
,".."))
629 *mode
= dos_mode(conn
,pathreal
,&sbuf
);
631 if (!dir_check_ftype(conn
,*mode
,&sbuf
,dirtype
))
633 DEBUG(5,("[%s] attribs didn't match %x\n",filename
,dirtype
));
637 if (!filename_is_mask
)
639 /* Now we can allow the mangled cache to be updated */
640 pstrcpy(filename
,dname
);
641 name_map_mangle(filename
,True
,True
,SNUM(conn
));
644 *size
= sbuf
.st_size
;
645 *date
= sbuf
.st_mtime
;
647 DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal
,fname
));
668 /*******************************************************************
670 ********************************************************************/
672 void *OpenDir(connection_struct
*conn
, char *name
, BOOL use_veto
)
676 DIR *p
= dos_opendir(name
);
679 if (!p
) return(NULL
);
680 dirp
= (Dir
*)malloc(sizeof(Dir
));
685 dirp
->pos
= dirp
->numentries
= dirp
->mallocsize
= 0;
686 dirp
->data
= dirp
->current
= NULL
;
688 while ((n
= dos_readdirname(p
)))
692 /* If it's a vetoed file, pretend it doesn't even exist */
693 if (use_veto
&& conn
&& IS_VETO_PATH(conn
, n
)) continue;
695 if (used
+ l
> dirp
->mallocsize
) {
696 int s
= MAX(used
+l
,used
+2000);
698 r
= (char *)Realloc(dirp
->data
,s
);
700 DEBUG(0,("Out of memory in OpenDir\n"));
704 dirp
->mallocsize
= s
;
705 dirp
->current
= dirp
->data
;
707 pstrcpy(dirp
->data
+used
,n
);
713 return((void *)dirp
);
717 /*******************************************************************
719 ********************************************************************/
721 void CloseDir(void *p
)
723 Dir
*dirp
= (Dir
*)p
;
725 if (dirp
->data
) free(dirp
->data
);
729 /*******************************************************************
730 Read from a directory.
731 ********************************************************************/
733 char *ReadDirName(void *p
)
736 Dir
*dirp
= (Dir
*)p
;
738 if (!dirp
|| !dirp
->current
|| dirp
->pos
>= dirp
->numentries
) return(NULL
);
741 dirp
->current
= skip_string(dirp
->current
,1);
748 /*******************************************************************
750 ********************************************************************/
752 BOOL
SeekDir(void *p
,int pos
)
754 Dir
*dirp
= (Dir
*)p
;
756 if (!dirp
) return(False
);
758 if (pos
< dirp
->pos
) {
759 dirp
->current
= dirp
->data
;
763 while (dirp
->pos
< pos
&& ReadDirName(p
)) ;
765 return(dirp
->pos
== pos
);
768 /*******************************************************************
770 ********************************************************************/
774 Dir
*dirp
= (Dir
*)p
;
776 if (!dirp
) return(-1);
782 /* -------------------------------------------------------------------------- **
783 * This section manages a global directory cache.
784 * (It should probably be split into a separate module. crh)
785 * -------------------------------------------------------------------------- **
797 static ubi_dlNewList( dir_cache
);
799 void DirCacheAdd( char *path
, char *name
, char *dname
, int snum
)
800 /* ------------------------------------------------------------------------ **
801 * Add an entry to the directory cache.
810 * ------------------------------------------------------------------------ **
815 dir_cache_entry
*entry
;
817 /* Allocate the structure & string space in one go so that it can be freed
818 * in one call to free().
820 pathlen
= strlen( path
) +1; /* Bytes required to store path (with nul). */
821 namelen
= strlen( name
) +1; /* Bytes required to store name (with nul). */
822 entry
= (dir_cache_entry
*)malloc( sizeof( dir_cache_entry
)
825 + strlen( dname
) +1 );
826 if( NULL
== entry
) /* Not adding to the cache is not fatal, */
827 return; /* so just return as if nothing happened. */
829 /* Set pointers correctly and load values. */
830 entry
->path
= pstrcpy( (char *)&entry
[1], path
);
831 entry
->name
= pstrcpy( &(entry
->path
[pathlen
]), name
);
832 entry
->dname
= pstrcpy( &(entry
->name
[namelen
]), dname
);
835 /* Add the new entry to the linked list. */
836 (void)ubi_dlAddHead( dir_cache
, entry
);
837 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path
, name
, dname
) );
839 /* Free excess cache entries. */
840 while( DIRCACHESIZE
< dir_cache
->count
)
841 free( ubi_dlRemTail( dir_cache
) );
846 char *DirCacheCheck( char *path
, char *name
, int snum
)
847 /* ------------------------------------------------------------------------ **
848 * Search for an entry to the directory cache.
854 * Output: The dname string of the located entry, or NULL if the entry was
857 * Notes: This uses a linear search, which is is okay because of
858 * the small size of the cache. Use a splay tree or hash
861 * ------------------------------------------------------------------------ **
864 dir_cache_entry
*entry
;
866 for( entry
= (dir_cache_entry
*)ubi_dlFirst( dir_cache
);
868 entry
= (dir_cache_entry
*)ubi_dlNext( entry
) )
870 if( entry
->snum
== snum
871 && 0 == strcmp( name
, entry
->name
)
872 && 0 == strcmp( path
, entry
->path
) )
874 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path
,name
,entry
->dname
));
875 return( entry
->dname
);
880 } /* DirCacheCheck */
882 void DirCacheFlush(int snum
)
883 /* ------------------------------------------------------------------------ **
884 * Remove all cache entries which have an snum that matches the input.
890 * ------------------------------------------------------------------------ **
893 dir_cache_entry
*entry
;
896 for(entry
= (dir_cache_entry
*)ubi_dlFirst( dir_cache
);
898 next
= ubi_dlNext( entry
);
899 if( entry
->snum
== snum
)
900 free( ubi_dlRemThis( dir_cache
, entry
) );
901 entry
= (dir_cache_entry
*)next
;
903 } /* DirCacheFlush */
905 /* -------------------------------------------------------------------------- **
906 * End of the section that manages the global directory cache.
907 * -------------------------------------------------------------------------- **