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 #define DPTR_MASK ((uint32)(((uint32)1)<<31))
498 /****************************************************************************
499 Fill the 5 byte server reserved dptr field.
500 ****************************************************************************/
502 BOOL dptr_fill(char *buf1,unsigned int key)
504 unsigned char *buf = (unsigned char *)buf1;
505 void *p = dptr_ptr(key);
508 DEBUG(1,("filling null dirptr %d\n",key));
512 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
513 (long)p,(int)offset));
515 SIVAL(buf,1,offset | DPTR_MASK);
520 /****************************************************************************
521 Return True if the offset is at zero.
522 ****************************************************************************/
524 BOOL dptr_zero(char *buf)
526 return((IVAL(buf,1)&~DPTR_MASK) == 0);
529 /****************************************************************************
530 Fetch the dir ptr and seek it given the 5 byte server field.
531 ****************************************************************************/
533 void *dptr_fetch(char *buf,int *num)
535 unsigned int key = *(unsigned char *)buf;
536 void *p = dptr_ptr(key);
539 DEBUG(3,("fetched null dirptr %d\n",key));
543 offset = IVAL(buf,1)&~DPTR_MASK;
545 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
546 key,dptr_path(key),offset));
550 /****************************************************************************
552 ****************************************************************************/
554 void *dptr_fetch_lanman2(int dptr_num)
556 void *p = dptr_ptr(dptr_num);
559 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
562 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
566 /****************************************************************************
567 Check a filetype for being valid.
568 ****************************************************************************/
570 BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
572 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
577 /****************************************************************************
578 Get an 8.3 directory entry.
579 ****************************************************************************/
581 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
582 SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
586 SMB_STRUCT_STAT sbuf;
593 *path = *pathreal = *filename = 0;
595 isrootdir = (strequal(conn->dirpath,"./") ||
596 strequal(conn->dirpath,".") ||
597 strequal(conn->dirpath,"/"));
599 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
606 BOOL filename_is_mask = False;
607 dname = ReadDirName(conn->dirptr);
609 DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
610 (long)conn->dirptr,TellDir(conn->dirptr)));
615 pstrcpy(filename,dname);
617 if ((filename_is_mask = (strcmp(filename,mask) == 0)) ||
618 (name_map_mangle(filename,True,False,SNUM(conn)) &&
619 mask_match(filename,mask,False,False)))
621 if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
624 pstrcpy(fname,filename);
626 pstrcpy(path,conn->dirpath);
629 pstrcpy(pathreal,path);
631 pstrcat(pathreal,dname);
632 if (dos_stat(pathreal,&sbuf) != 0)
634 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
638 if (check_descend && !strequal(fname,".") && !strequal(fname,".."))
641 *mode = dos_mode(conn,pathreal,&sbuf);
643 if (!dir_check_ftype(conn,*mode,&sbuf,dirtype))
645 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
649 if (!filename_is_mask)
651 /* Now we can allow the mangled cache to be updated */
652 pstrcpy(filename,dname);
653 name_map_mangle(filename,True,True,SNUM(conn));
656 *size = sbuf.st_size;
657 *date = sbuf.st_mtime;
659 DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
680 /*******************************************************************
682 ********************************************************************/
684 void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
688 DIR *p = dos_opendir(name);
691 if (!p) return(NULL);
692 dirp = (Dir *)malloc(sizeof(Dir));
697 dirp->pos = dirp->numentries = dirp->mallocsize = 0;
698 dirp->data = dirp->current = NULL;
700 while ((n = dos_readdirname(p)))
704 /* If it's a vetoed file, pretend it doesn't even exist */
705 if (use_veto && conn && IS_VETO_PATH(conn, n)) continue;
707 if (used + l > dirp->mallocsize) {
708 int s = MAX(used+l,used+2000);
710 r = (char *)Realloc(dirp->data,s);
712 DEBUG(0,("Out of memory in OpenDir\n"));
716 dirp->mallocsize = s;
717 dirp->current = dirp->data;
719 pstrcpy(dirp->data+used,n);
725 return((void *)dirp);
729 /*******************************************************************
731 ********************************************************************/
733 void CloseDir(void *p)
735 Dir *dirp = (Dir *)p;
737 if (dirp->data) free(dirp->data);
741 /*******************************************************************
742 Read from a directory.
743 ********************************************************************/
745 char *ReadDirName(void *p)
748 Dir *dirp = (Dir *)p;
750 if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
753 dirp->current = skip_string(dirp->current,1);
760 /*******************************************************************
762 ********************************************************************/
764 BOOL SeekDir(void *p,int pos)
766 Dir *dirp = (Dir *)p;
768 if (!dirp) return(False);
770 if (pos < dirp->pos) {
771 dirp->current = dirp->data;
775 while (dirp->pos < pos && ReadDirName(p)) ;
777 return(dirp->pos == pos);
780 /*******************************************************************
782 ********************************************************************/
786 Dir *dirp = (Dir *)p;
788 if (!dirp) return(-1);
794 /* -------------------------------------------------------------------------- **
795 * This section manages a global directory cache.
796 * (It should probably be split into a separate module. crh)
797 * -------------------------------------------------------------------------- **
809 static ubi_dlNewList( dir_cache );
811 void DirCacheAdd( char *path, char *name, char *dname, int snum )
812 /* ------------------------------------------------------------------------ **
813 * Add an entry to the directory cache.
822 * ------------------------------------------------------------------------ **
827 dir_cache_entry *entry;
829 /* Allocate the structure & string space in one go so that it can be freed
830 * in one call to free().
832 pathlen = strlen( path ) +1; /* Bytes required to store path (with nul). */
833 namelen = strlen( name ) +1; /* Bytes required to store name (with nul). */
834 entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
837 + strlen( dname ) +1 );
838 if( NULL == entry ) /* Not adding to the cache is not fatal, */
839 return; /* so just return as if nothing happened. */
841 /* Set pointers correctly and load values. */
842 entry->path = pstrcpy( (char *)&entry[1], path);
843 entry->name = pstrcpy( &(entry->path[pathlen]), name);
844 entry->dname = pstrcpy( &(entry->name[namelen]), dname);
847 /* Add the new entry to the linked list. */
848 (void)ubi_dlAddHead( dir_cache, entry );
849 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
851 /* Free excess cache entries. */
852 while( DIRCACHESIZE < dir_cache->count )
853 free( ubi_dlRemTail( dir_cache ) );
858 char *DirCacheCheck( char *path, char *name, int snum )
859 /* ------------------------------------------------------------------------ **
860 * Search for an entry to the directory cache.
866 * Output: The dname string of the located entry, or NULL if the entry was
869 * Notes: This uses a linear search, which is is okay because of
870 * the small size of the cache. Use a splay tree or hash
873 * ------------------------------------------------------------------------ **
876 dir_cache_entry *entry;
878 for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
880 entry = (dir_cache_entry *)ubi_dlNext( entry ) )
882 if( entry->snum == snum
883 && 0 == strcmp( name, entry->name )
884 && 0 == strcmp( path, entry->path ) )
886 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
887 return( entry->dname );
892 } /* DirCacheCheck */
894 void DirCacheFlush(int snum)
895 /* ------------------------------------------------------------------------ **
896 * Remove all cache entries which have an snum that matches the input.
902 * ------------------------------------------------------------------------ **
905 dir_cache_entry *entry;
908 for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
910 next = ubi_dlNext( entry );
911 if( entry->snum == snum )
912 free( ubi_dlRemThis( dir_cache, entry ) );
913 entry = (dir_cache_entry *)next;
915 } /* DirCacheFlush */
917 /* -------------------------------------------------------------------------- **
918 * End of the section that manages the global directory cache.
919 * -------------------------------------------------------------------------- **