make proto
[Samba/gbeck.git] / source / smbd / dir.c
blob5bf0dec944490ce3b49f088a19a3ab7ef9728c53
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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.
22 #include "includes.h"
24 extern int DEBUGLEVEL;
27 This module implements directory related functions for Samba.
30 typedef struct _dptr_struct {
31 struct _dptr_struct *next, *prev;
32 int dnum;
33 uint16 spid;
34 connection_struct *conn;
35 void *ptr;
36 BOOL expect_close;
37 char *wcard; /* Field only used for trans2_ searches */
38 uint16 attr; /* Field only used for trans2_ searches */
39 char *path;
40 } dptr_struct;
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 ****************************************************************************/
53 void init_dptrs(void)
55 static BOOL dptrs_init=False;
57 if (dptrs_init)
58 return;
60 dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
62 if (!dptr_bmap)
63 exit_server("out of memory in init_dptrs\n");
65 dptrs_init = True;
68 /****************************************************************************
69 Idle a dptr - the directory is closed but the control info is kept.
70 ****************************************************************************/
72 static void dptr_idle(dptr_struct *dptr)
74 if (dptr->ptr) {
75 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
76 dptrs_open--;
77 CloseDir(dptr->ptr);
78 dptr->ptr = NULL;
82 /****************************************************************************
83 Idle the oldest dptr.
84 ****************************************************************************/
86 static void dptr_idleoldest(void)
88 dptr_struct *dptr;
91 * Go to the end of the list.
93 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
96 if(!dptr) {
97 DEBUG(0,("No dptrs available to idle ?\n"));
98 return;
102 * Idle the oldest pointer.
105 for(; dptr; dptr = dptr->prev) {
106 if (dptr->ptr) {
107 dptr_idle(dptr);
108 return;
113 /****************************************************************************
114 Get the dptr_struct for a dir index.
115 ****************************************************************************/
117 static dptr_struct *dptr_get(int key, BOOL forclose)
119 dptr_struct *dptr;
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)
125 dptr_idleoldest();
126 DEBUG(4,("Reopening dptr key %d\n",key));
127 if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True)))
128 dptrs_open++;
130 DLIST_PROMOTE(dirptrs,dptr);
131 return dptr;
134 return(NULL);
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);
145 if (dptr)
146 return(dptr->ptr);
147 return(NULL);
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);
158 if (dptr)
159 return(dptr->path);
160 return(NULL);
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);
171 if (dptr)
172 return(dptr->wcard);
173 return(NULL);
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);
185 if (dptr) {
186 dptr->wcard = wcard;
187 return True;
189 return 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);
201 if (dptr) {
202 dptr->attr = attr;
203 return True;
205 return 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);
216 if (dptr)
217 return(dptr->attr);
218 return(0);
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",
238 dptr->dnum ));
241 bitmap_clear(dptr_bmap, dptr->dnum - 1);
243 if (dptr->ptr) {
244 CloseDir(dptr->ptr);
245 dptrs_open--;
248 /* Lanman 2 specific code */
249 if (dptr->wcard)
250 free(dptr->wcard);
251 string_set(&dptr->path,"");
252 free((char *)dptr);
255 /****************************************************************************
256 Close a dptr given a key.
257 ****************************************************************************/
259 void dptr_close(int *key)
261 dptr_struct *dptr;
263 if(*key == INVALID_DPTR_KEY)
264 return;
266 /* OS/2 seems to use -1 to indicate "close all directories" */
267 if (*key == -1) {
268 dptr_struct *next;
269 for(dptr = dirptrs; dptr; dptr = next) {
270 next = dptr->next;
271 dptr_close_internal(dptr);
273 *key = INVALID_DPTR_KEY;
274 return;
277 dptr = dptr_get(*key, True);
279 if (!dptr) {
280 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
281 return;
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) {
297 next = 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)
309 dptr_struct *dptr;
310 for(dptr = dirptrs; dptr; dptr = dptr->next) {
311 if (dptr->conn == conn && dptr->ptr)
312 dptr_idle(dptr);
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) {
324 next = 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))
339 return(False);
341 if (! *directory)
342 directory = ".";
344 conn->dirptr = OpenDir(conn, directory, True);
345 if (conn->dirptr) {
346 dptrs_open++;
347 string_set(&conn->dirpath,directory);
348 return(True);
351 return(False);
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)
362 dptr_struct *dptr;
365 * Go to the end of the list.
367 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
370 if(!dptr) {
371 DEBUG(0,("No old dptrs available to close oldest ?\n"));
372 return;
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);
385 return;
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)
401 dptr_struct *dptr;
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)
407 dptr_idleoldest();
409 dptr = (dptr_struct *)malloc(sizeof(dptr_struct));
410 if(!dptr) {
411 DEBUG(0,("malloc fail in dptr_create.\n"));
412 return -1;
415 ZERO_STRUCTP(dptr);
417 if(old_handle) {
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));
441 free((char *)dptr);
442 return -1;
445 } else {
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
460 * directory handles.
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));
470 free((char *)dptr);
471 return -1;
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);
482 dptr->conn = conn;
483 dptr->spid = spid;
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));
493 return(dptr->dnum);
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);
504 uint32 offset;
505 if (!p) {
506 DEBUG(1,("filling null dirptr %d\n",key));
507 return(False);
509 offset = TellDir(p);
510 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
511 (long)p,(int)offset));
512 buf[0] = key;
513 SIVAL(buf,1,offset | DPTR_MASK);
514 return(True);
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);
525 uint32 offset;
526 if (!p) {
527 DEBUG(3,("fetched null dirptr %d\n",key));
528 return(NULL);
530 *num = key;
531 offset = IVAL(buf,1)&~DPTR_MASK;
532 SeekDir(p,offset);
533 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
534 key,dptr_path(key),offset));
535 return(p);
538 /****************************************************************************
539 Fetch the dir ptr.
540 ****************************************************************************/
542 void *dptr_fetch_lanman2(int dptr_num)
544 void *p = dptr_ptr(dptr_num);
546 if (!p) {
547 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
548 return(NULL);
550 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
551 return(p);
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)
561 return False;
562 return True;
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)
572 char *dname;
573 BOOL found = False;
574 SMB_STRUCT_STAT sbuf;
575 pstring path;
576 pstring pathreal;
577 BOOL isrootdir;
578 pstring filename;
579 BOOL needslash;
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] != '/');
589 if (!conn->dirptr)
590 return(False);
592 while (!found)
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)));
599 if (dname == NULL)
600 return(False);
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,".")))
614 continue;
616 if (!is_8_3(filename, False)) {
617 name_map_mangle(filename,True,False,SNUM(conn));
620 pstrcpy(fname,filename);
621 *path = 0;
622 pstrcpy(path,conn->dirpath);
623 if(needslash)
624 pstrcat(path,"/");
625 pstrcpy(pathreal,path);
626 pstrcat(path,fname);
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) ));
631 continue;
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));
639 continue;
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));
647 found = True;
651 return(found);
656 typedef struct
658 int pos;
659 int numentries;
660 int mallocsize;
661 char *data;
662 char *current;
663 } Dir;
666 /*******************************************************************
667 Open a directory.
668 ********************************************************************/
670 void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
672 Dir *dirp;
673 char *n;
674 DIR *p = conn->vfs_ops.opendir(conn,dos_to_unix(name,False));
675 int used=0;
677 if (!p) return(NULL);
678 dirp = (Dir *)malloc(sizeof(Dir));
679 if (!dirp) {
680 conn->vfs_ops.closedir(conn,p);
681 return(NULL);
683 dirp->pos = dirp->numentries = dirp->mallocsize = 0;
684 dirp->data = dirp->current = NULL;
686 while ((n = vfs_readdirname(conn, p)))
688 int l;
690 l = strlen(n)+1;
692 /* Return value of vfs_readdirname has already gone through
693 unix_to_dos() */
695 /* If it's a vetoed file, pretend it doesn't even exist */
696 if (use_veto && conn && IS_VETO_PATH(conn, n)) continue;
698 if (used + l > dirp->mallocsize) {
699 int s = MAX(used+l,used+2000);
700 char *r;
701 r = (char *)Realloc(dirp->data,s);
702 if (!r) {
703 DEBUG(0,("Out of memory in OpenDir\n"));
704 break;
706 dirp->data = r;
707 dirp->mallocsize = s;
708 dirp->current = dirp->data;
710 pstrcpy(dirp->data+used,n);
711 used += l;
712 dirp->numentries++;
715 conn->vfs_ops.closedir(conn,p);
716 return((void *)dirp);
720 /*******************************************************************
721 Close a directory.
722 ********************************************************************/
724 void CloseDir(void *p)
726 Dir *dirp = (Dir *)p;
727 if (!dirp) return;
728 if (dirp->data) free(dirp->data);
729 free(dirp);
732 /*******************************************************************
733 Read from a directory.
734 ********************************************************************/
736 char *ReadDirName(void *p)
738 char *ret;
739 Dir *dirp = (Dir *)p;
741 if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
743 ret = dirp->current;
744 dirp->current = skip_string(dirp->current,1);
745 dirp->pos++;
747 return(ret);
751 /*******************************************************************
752 Seek a dir.
753 ********************************************************************/
755 BOOL SeekDir(void *p,int pos)
757 Dir *dirp = (Dir *)p;
759 if (!dirp) return(False);
761 if (pos < dirp->pos) {
762 dirp->current = dirp->data;
763 dirp->pos = 0;
766 while (dirp->pos < pos && ReadDirName(p)) ;
768 return(dirp->pos == pos);
771 /*******************************************************************
772 Tell a dir position.
773 ********************************************************************/
775 int TellDir(void *p)
777 Dir *dirp = (Dir *)p;
779 if (!dirp) return(-1);
781 return(dirp->pos);
784 /*******************************************************************************
785 This section manages a global directory cache.
786 (It should probably be split into a separate module. crh)
787 ********************************************************************************/
789 typedef struct {
790 ubi_dlNode node;
791 char *path;
792 char *name;
793 char *dname;
794 int snum;
795 } dir_cache_entry;
797 static ubi_dlNewList( dir_cache );
799 /*****************************************************************************
800 Add an entry to the directory cache.
801 Input: path -
802 name -
803 dname -
804 snum -
805 Output: None.
806 *****************************************************************************/
808 void DirCacheAdd( char *path, char *name, char *dname, int snum )
810 int pathlen;
811 int namelen;
812 dir_cache_entry *entry;
814 /* Allocate the structure & string space in one go so that it can be freed
815 * in one call to free().
817 pathlen = strlen( path ) +1; /* Bytes required to store path (with nul). */
818 namelen = strlen( name ) +1; /* Bytes required to store name (with nul). */
819 entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
820 + pathlen
821 + namelen
822 + strlen( dname ) +1 );
823 if( NULL == entry ) /* Not adding to the cache is not fatal, */
824 return; /* so just return as if nothing happened. */
826 /* Set pointers correctly and load values. */
827 entry->path = pstrcpy( (char *)&entry[1], path);
828 entry->name = pstrcpy( &(entry->path[pathlen]), name);
829 entry->dname = pstrcpy( &(entry->name[namelen]), dname);
830 entry->snum = snum;
832 /* Add the new entry to the linked list. */
833 (void)ubi_dlAddHead( dir_cache, entry );
834 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
836 /* Free excess cache entries. */
837 while( DIRCACHESIZE < dir_cache->count )
838 free( ubi_dlRemTail( dir_cache ) );
842 /*****************************************************************************
843 Search for an entry to the directory cache.
844 Input: path -
845 name -
846 snum -
847 Output: The dname string of the located entry, or NULL if the entry was
848 not found.
850 Notes: This uses a linear search, which is is okay because of
851 the small size of the cache. Use a splay tree or hash
852 for large caches.
853 *****************************************************************************/
855 char *DirCacheCheck( char *path, char *name, int snum )
857 dir_cache_entry *entry;
859 for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
860 NULL != entry;
861 entry = (dir_cache_entry *)ubi_dlNext( entry ) )
863 if( entry->snum == snum
864 && 0 == strcmp( name, entry->name )
865 && 0 == strcmp( path, entry->path ) )
867 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
868 return( entry->dname );
872 return(NULL);
875 /*****************************************************************************
876 Remove all cache entries which have an snum that matches the input.
877 Input: snum -
878 Output: None.
879 *****************************************************************************/
881 void DirCacheFlush(int snum)
883 dir_cache_entry *entry;
884 ubi_dlNodePtr next;
886 for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
887 NULL != entry; ) {
888 next = ubi_dlNext( entry );
889 if( entry->snum == snum )
890 free( ubi_dlRemThis( dir_cache, entry ) );
891 entry = (dir_cache_entry *)next;