4 Unix SMB/Netbios implementation.
6 Directory handling routines
7 Copyright (C) Andrew Tridgell 1992-1998
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 extern int DEBUGLEVEL;
29 This module implements directory related functions for Samba.
32 typedef struct _dptr_struct {
33 struct _dptr_struct *next, *prev;
36 connection_struct *conn;
39 char *wcard; /* Field only used for trans2_ searches */
40 uint16 attr; /* Field only used for trans2_ searches */
44 static struct bitmap *dptr_bmap;
45 static dptr_struct *dirptrs;
47 static int dptrs_open = 0;
49 #define INVALID_DPTR_KEY (-3)
51 /****************************************************************************
52 Initialise the dir bitmap.
53 ****************************************************************************/
57 static BOOL dptrs_init=False;
62 dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
65 exit_server("out of memory in init_dptrs\n");
70 /****************************************************************************
71 Idle a dptr - the directory is closed but the control info is kept.
72 ****************************************************************************/
74 static void dptr_idle(dptr_struct *dptr)
77 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
84 /****************************************************************************
86 ****************************************************************************/
88 static void dptr_idleoldest(void)
93 * Go to the end of the list.
95 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
99 DEBUG(0,("No dptrs available to idle ?\n"));
104 * Idle the oldest pointer.
107 for(; dptr; dptr = dptr->prev) {
115 /****************************************************************************
116 Get the dptr_struct for a dir index.
117 ****************************************************************************/
119 static dptr_struct *dptr_get(int key, BOOL forclose)
123 for(dptr = dirptrs; dptr; dptr = dptr->next) {
124 if(dptr->dnum == key) {
125 if (!forclose && !dptr->ptr) {
126 if (dptrs_open >= MAX_OPEN_DIRECTORIES)
128 DEBUG(4,("Reopening dptr key %d\n",key));
129 if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True)))
132 DLIST_PROMOTE(dirptrs,dptr);
139 /****************************************************************************
140 Get the dptr ptr for a dir index.
141 ****************************************************************************/
143 static void *dptr_ptr(int key)
145 dptr_struct *dptr = dptr_get(key, False);
152 /****************************************************************************
153 Get the dir path for a dir index.
154 ****************************************************************************/
156 char *dptr_path(int key)
158 dptr_struct *dptr = dptr_get(key, False);
165 /****************************************************************************
166 Get the dir wcard for a dir index (lanman2 specific).
167 ****************************************************************************/
169 char *dptr_wcard(int key)
171 dptr_struct *dptr = dptr_get(key, False);
178 /****************************************************************************
179 Set the dir wcard for a dir index (lanman2 specific).
180 Returns 0 on ok, 1 on fail.
181 ****************************************************************************/
183 BOOL dptr_set_wcard(int key, char *wcard)
185 dptr_struct *dptr = dptr_get(key, False);
194 /****************************************************************************
195 Set the dir attrib for a dir index (lanman2 specific).
196 Returns 0 on ok, 1 on fail.
197 ****************************************************************************/
199 BOOL dptr_set_attr(int key, uint16 attr)
201 dptr_struct *dptr = dptr_get(key, False);
210 /****************************************************************************
211 Get the dir attrib for a dir index (lanman2 specific)
212 ****************************************************************************/
214 uint16 dptr_attr(int key)
216 dptr_struct *dptr = dptr_get(key, False);
223 /****************************************************************************
224 Close a dptr (internal func).
225 ****************************************************************************/
227 static void dptr_close_internal(dptr_struct *dptr)
229 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
231 DLIST_REMOVE(dirptrs, dptr);
234 * Free the dnum in the bitmap. Remember the dnum value is always
235 * biased by one with respect to the bitmap.
238 if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
239 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
243 bitmap_clear(dptr_bmap, dptr->dnum - 1);
250 /* Lanman 2 specific code */
253 string_set(&dptr->path,"");
257 /****************************************************************************
258 Close a dptr given a key.
259 ****************************************************************************/
261 void dptr_close(int *key)
265 if(*key == INVALID_DPTR_KEY)
268 /* OS/2 seems to use -1 to indicate "close all directories" */
271 for(dptr = dirptrs; dptr; dptr = next) {
273 dptr_close_internal(dptr);
275 *key = INVALID_DPTR_KEY;
279 dptr = dptr_get(*key, True);
282 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
286 dptr_close_internal(dptr);
288 *key = INVALID_DPTR_KEY;
291 /****************************************************************************
292 Close all dptrs for a cnum.
293 ****************************************************************************/
295 void dptr_closecnum(connection_struct *conn)
297 dptr_struct *dptr, *next;
298 for(dptr = dirptrs; dptr; dptr = next) {
300 if (dptr->conn == conn)
301 dptr_close_internal(dptr);
305 /****************************************************************************
306 Idle all dptrs for a cnum.
307 ****************************************************************************/
309 void dptr_idlecnum(connection_struct *conn)
312 for(dptr = dirptrs; dptr; dptr = dptr->next) {
313 if (dptr->conn == conn && dptr->ptr)
318 /****************************************************************************
319 Close a dptr that matches a given path, only if it matches the spid also.
320 ****************************************************************************/
322 void dptr_closepath(char *path,uint16 spid)
324 dptr_struct *dptr, *next;
325 for(dptr = dirptrs; dptr; dptr = next) {
327 if (spid == dptr->spid && strequal(dptr->path,path))
328 dptr_close_internal(dptr);
332 /****************************************************************************
333 Start a directory listing.
334 ****************************************************************************/
336 static BOOL start_dir(connection_struct *conn,char *directory)
338 DEBUG(5,("start_dir dir=%s\n",directory));
340 if (!check_name(directory,conn))
346 conn->dirptr = OpenDir(conn, directory, True);
349 string_set(&conn->dirpath,directory);
356 /****************************************************************************
357 Try and close the oldest handle not marked for
358 expect close in the hope that the client has
359 finished with that one.
360 ****************************************************************************/
362 static void dptr_close_oldest(BOOL old)
367 * Go to the end of the list.
369 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
373 DEBUG(0,("No old dptrs available to close oldest ?\n"));
378 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
379 * does not have expect_close set. If 'old' is false, close
380 * one of the new dnum handles.
383 for(; dptr; dptr = dptr->prev) {
384 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
385 (!old && (dptr->dnum > 255))) {
386 dptr_close_internal(dptr);
392 /****************************************************************************
393 Create a new dir ptr. If the flag old_handle is true then we must allocate
394 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
395 one byte long. If old_handle is false we allocate from the range
396 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
397 a directory handle is never zero. All the above is folklore taught to
398 me at Andrew's knee.... :-) :-). JRA.
399 ****************************************************************************/
401 int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,uint16 spid)
405 if (!start_dir(conn,path))
406 return(-2); /* Code to say use a unix error return code. */
408 if (dptrs_open >= MAX_OPEN_DIRECTORIES)
411 dptr = (dptr_struct *)malloc(sizeof(dptr_struct));
413 DEBUG(0,("malloc fail in dptr_create.\n"));
422 * This is an old-style SMBsearch request. Ensure the
423 * value we return will fit in the range 1-255.
426 dptr->dnum = bitmap_find(dptr_bmap, 0);
428 if(dptr->dnum == -1 || dptr->dnum > 254) {
431 * Try and close the oldest handle not marked for
432 * expect close in the hope that the client has
433 * finished with that one.
436 dptr_close_oldest(True);
438 /* Now try again... */
439 dptr->dnum = bitmap_find(dptr_bmap, 0);
441 if(dptr->dnum == -1 || dptr->dnum > 254) {
442 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
450 * This is a new-style trans2 request. Allocate from
451 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
454 dptr->dnum = bitmap_find(dptr_bmap, 255);
456 if(dptr->dnum == -1 || dptr->dnum < 255) {
459 * Try and close the oldest handle close in the hope that
460 * the client has finished with that one. This will only
461 * happen in the case of the Win98 client bug where it leaks
465 dptr_close_oldest(False);
467 /* Now try again... */
468 dptr->dnum = bitmap_find(dptr_bmap, 255);
470 if(dptr->dnum == -1 || dptr->dnum < 255) {
471 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
478 bitmap_set(dptr_bmap, dptr->dnum);
480 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
482 dptr->ptr = conn->dirptr;
483 string_set(&dptr->path,path);
486 dptr->expect_close = expect_close;
487 dptr->wcard = NULL; /* Only used in lanman2 searches */
488 dptr->attr = 0; /* Only used in lanman2 searches */
490 DLIST_ADD(dirptrs, dptr);
492 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
493 dptr->dnum,path,expect_close));
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);
519 /****************************************************************************
520 Fetch the dir ptr and seek it given the 5 byte server field.
521 ****************************************************************************/
523 void *dptr_fetch(char *buf,int *num)
525 unsigned int key = *(unsigned char *)buf;
526 void *p = dptr_ptr(key);
529 DEBUG(3,("fetched null dirptr %d\n",key));
533 offset = IVAL(buf,1)&~DPTR_MASK;
535 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
536 key,dptr_path(key),offset));
540 /****************************************************************************
542 ****************************************************************************/
544 void *dptr_fetch_lanman2(int dptr_num)
546 void *p = dptr_ptr(dptr_num);
549 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
552 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
556 /****************************************************************************
557 Check a filetype for being valid.
558 ****************************************************************************/
560 BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
562 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
567 /****************************************************************************
568 Get an 8.3 directory entry.
569 ****************************************************************************/
571 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
572 SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
576 SMB_STRUCT_STAT sbuf;
583 *path = *pathreal = *filename = 0;
585 isrootdir = (strequal(conn->dirpath,"./") ||
586 strequal(conn->dirpath,".") ||
587 strequal(conn->dirpath,"/"));
589 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
596 dname = ReadDirName(conn->dirptr);
598 DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
599 (long)conn->dirptr,TellDir(conn->dirptr)));
604 pstrcpy(filename,dname);
606 /* notice the special *.* handling. This appears to be the only difference
607 between the wildcard handling in this routine and in the trans2 routines.
608 see masktest for a demo
610 if ((strcmp(mask,"*.*") == 0) ||
611 mask_match(filename,mask,False) ||
612 (name_map_mangle(filename,True,False,SNUM(conn)) &&
613 mask_match(filename,mask,False)))
615 if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
618 if (!is_8_3(filename, False)) {
619 name_map_mangle(filename,True,False,SNUM(conn));
622 pstrcpy(fname,filename);
624 pstrcpy(path,conn->dirpath);
627 pstrcpy(pathreal,path);
629 pstrcat(pathreal,dname);
630 if (conn->vfs_ops.stat(conn,dos_to_unix(pathreal, False), &sbuf) != 0)
632 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
636 *mode = dos_mode(conn,pathreal,&sbuf);
638 if (!dir_check_ftype(conn,*mode,&sbuf,dirtype))
640 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
644 *size = sbuf.st_size;
645 *date = sbuf.st_mtime;
647 DEBUG(0,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
668 /*******************************************************************
670 ********************************************************************/
672 void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
676 DIR *p = conn->vfs_ops.opendir(conn,dos_to_unix(name,False));
679 if (!p) return(NULL);
680 dirp = (Dir *)malloc(sizeof(Dir));
682 conn->vfs_ops.closedir(conn,p);
685 dirp->pos = dirp->numentries = dirp->mallocsize = 0;
686 dirp->data = dirp->current = NULL;
688 while ((n = vfs_readdirname(conn, p)))
694 /* Return value of vfs_readdirname has already gone through
697 /* If it's a vetoed file, pretend it doesn't even exist */
698 if (use_veto && conn && IS_VETO_PATH(conn, n)) continue;
700 if (used + l > dirp->mallocsize) {
701 int s = MAX(used+l,used+2000);
703 r = (char *)Realloc(dirp->data,s);
705 DEBUG(0,("Out of memory in OpenDir\n"));
709 dirp->mallocsize = s;
710 dirp->current = dirp->data;
712 pstrcpy(dirp->data+used,n);
717 conn->vfs_ops.closedir(conn,p);
718 return((void *)dirp);
722 /*******************************************************************
724 ********************************************************************/
726 void CloseDir(void *p)
728 Dir *dirp = (Dir *)p;
730 if (dirp->data) free(dirp->data);
734 /*******************************************************************
735 Read from a directory.
736 ********************************************************************/
738 char *ReadDirName(void *p)
741 Dir *dirp = (Dir *)p;
743 if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
746 dirp->current = skip_string(dirp->current,1);
753 /*******************************************************************
755 ********************************************************************/
757 BOOL SeekDir(void *p,int pos)
759 Dir *dirp = (Dir *)p;
761 if (!dirp) return(False);
763 if (pos < dirp->pos) {
764 dirp->current = dirp->data;
768 while (dirp->pos < pos && ReadDirName(p)) ;
770 return(dirp->pos == pos);
773 /*******************************************************************
775 ********************************************************************/
779 Dir *dirp = (Dir *)p;
781 if (!dirp) return(-1);
786 /*******************************************************************************
787 This section manages a global directory cache.
788 (It should probably be split into a separate module. crh)
789 ********************************************************************************/
799 static ubi_dlNewList( dir_cache );
801 /*****************************************************************************
802 Add an entry to the directory cache.
808 *****************************************************************************/
810 void DirCacheAdd( char *path, char *name, char *dname, int snum )
814 dir_cache_entry *entry;
816 /* Allocate the structure & string space in one go so that it can be freed
817 * in one call to free().
819 pathlen = strlen( path ) +1; /* Bytes required to store path (with nul). */
820 namelen = strlen( name ) +1; /* Bytes required to store name (with nul). */
821 entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
824 + strlen( dname ) +1 );
825 if( NULL == entry ) /* Not adding to the cache is not fatal, */
826 return; /* so just return as if nothing happened. */
828 /* Set pointers correctly and load values. */
829 entry->path = pstrcpy( (char *)&entry[1], path);
830 entry->name = pstrcpy( &(entry->path[pathlen]), name);
831 entry->dname = pstrcpy( &(entry->name[namelen]), dname);
834 /* Add the new entry to the linked list. */
835 (void)ubi_dlAddHead( dir_cache, entry );
836 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
838 /* Free excess cache entries. */
839 while( DIRCACHESIZE < dir_cache->count )
840 free( ubi_dlRemTail( dir_cache ) );
844 /*****************************************************************************
845 Search for an entry to the directory cache.
849 Output: The dname string of the located entry, or NULL if the entry was
852 Notes: This uses a linear search, which is is okay because of
853 the small size of the cache. Use a splay tree or hash
855 *****************************************************************************/
857 char *DirCacheCheck( char *path, char *name, int snum )
859 dir_cache_entry *entry;
861 for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
863 entry = (dir_cache_entry *)ubi_dlNext( entry ) )
865 if( entry->snum == snum
866 && 0 == strcmp( name, entry->name )
867 && 0 == strcmp( path, entry->path ) )
869 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
870 return( entry->dname );
877 /*****************************************************************************
878 Remove all cache entries which have an snum that matches the input.
881 *****************************************************************************/
883 void DirCacheFlush(int snum)
885 dir_cache_entry *entry;
888 for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
890 next = ubi_dlNext( entry );
891 if( entry->snum == snum )
892 free( ubi_dlRemThis( dir_cache, entry ) );
893 entry = (dir_cache_entry *)next;