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;
25 extern connection_struct Connections[];
28 This module implements directory related functions for Samba.
33 uint32 dircounter = 0;
36 #define NUMDIRPTRS 256
39 static struct dptr_struct
48 char *wcard; /* Field only used for lanman2 trans2_findfirst/next searches */
49 uint16 attr; /* Field only used for lanman2 trans2_findfirst/next searches */
55 static int dptrs_open = 0;
57 /****************************************************************************
58 initialise the dir array
59 ****************************************************************************/
62 static BOOL dptrs_init=False;
65 if (dptrs_init) return;
66 for (i=0;i<NUMDIRPTRS;i++)
68 dirptrs[i].valid = False;
69 dirptrs[i].wcard = NULL;
70 dirptrs[i].ptr = NULL;
71 string_init(&dirptrs[i].path,"");
76 /****************************************************************************
77 idle a dptr - the directory is closed but the control info is kept
78 ****************************************************************************/
79 static void dptr_idle(int key)
81 if (dirptrs[key].valid && dirptrs[key].ptr) {
82 DEBUG(4,("Idling dptr key %d\n",key));
84 CloseDir(dirptrs[key].ptr);
85 dirptrs[key].ptr = NULL;
89 /****************************************************************************
91 ****************************************************************************/
92 static void dptr_idleoldest(void)
95 uint32 old=dircounter+1;
97 for (i=0;i<NUMDIRPTRS;i++)
98 if (dirptrs[i].valid && dirptrs[i].ptr && dirptrs[i].lastused < old) {
99 old = dirptrs[i].lastused;
105 DEBUG(0,("No dptrs available to idle??\n"));
108 /****************************************************************************
109 get the dir ptr for a dir index
110 ****************************************************************************/
111 static void *dptr_get(int key,uint32 lastused)
113 struct dptr_struct *dp = &dirptrs[key];
116 if (lastused) dp->lastused = lastused;
118 if (dptrs_open >= MAXDIR)
120 DEBUG(4,("Reopening dptr key %d\n",key));
121 if ((dp->ptr = OpenDir(dp->cnum, dp->path, True)))
129 /****************************************************************************
130 get the dir path for a dir index
131 ****************************************************************************/
132 char *dptr_path(int key)
134 if (dirptrs[key].valid)
135 return(dirptrs[key].path);
139 /****************************************************************************
140 get the dir wcard for a dir index (lanman2 specific)
141 ****************************************************************************/
142 char *dptr_wcard(int key)
144 if (dirptrs[key].valid)
145 return(dirptrs[key].wcard);
149 /****************************************************************************
150 set the dir wcard for a dir index (lanman2 specific)
151 Returns 0 on ok, 1 on fail.
152 ****************************************************************************/
153 BOOL dptr_set_wcard(int key, char *wcard)
155 if (dirptrs[key].valid) {
156 dirptrs[key].wcard = wcard;
162 /****************************************************************************
163 set the dir attrib for a dir index (lanman2 specific)
164 Returns 0 on ok, 1 on fail.
165 ****************************************************************************/
166 BOOL dptr_set_attr(int key, uint16 attr)
168 if (dirptrs[key].valid) {
169 dirptrs[key].attr = attr;
175 /****************************************************************************
176 get the dir attrib for a dir index (lanman2 specific)
177 ****************************************************************************/
178 uint16 dptr_attr(int key)
180 if (dirptrs[key].valid)
181 return(dirptrs[key].attr);
185 /****************************************************************************
187 ****************************************************************************/
188 void dptr_close(int key)
190 /* OS/2 seems to use -1 to indicate "close all directories" */
193 for (i=0;i<NUMDIRPTRS;i++)
198 if (key < 0 || key >= NUMDIRPTRS) {
199 DEBUG(3,("Invalid key %d given to dptr_close\n",key));
203 if (dirptrs[key].valid) {
204 DEBUG(4,("closing dptr key %d\n",key));
205 if (dirptrs[key].ptr) {
206 CloseDir(dirptrs[key].ptr);
209 /* Lanman 2 specific code */
210 if (dirptrs[key].wcard)
211 free(dirptrs[key].wcard);
212 dirptrs[key].valid = False;
213 string_set(&dirptrs[key].path,"");
217 /****************************************************************************
218 close all dptrs for a cnum
219 ****************************************************************************/
220 void dptr_closecnum(int cnum)
223 for (i=0;i<NUMDIRPTRS;i++)
224 if (dirptrs[i].valid && dirptrs[i].cnum == cnum)
228 /****************************************************************************
229 idle all dptrs for a cnum
230 ****************************************************************************/
231 void dptr_idlecnum(int cnum)
234 for (i=0;i<NUMDIRPTRS;i++)
235 if (dirptrs[i].valid && dirptrs[i].cnum == cnum && dirptrs[i].ptr)
239 /****************************************************************************
240 close a dptr that matches a given path, only if it matches the pid also
241 ****************************************************************************/
242 void dptr_closepath(char *path,int pid)
245 for (i=0;i<NUMDIRPTRS;i++)
246 if (dirptrs[i].valid && pid == dirptrs[i].pid &&
247 strequal(dirptrs[i].path,path))
251 /****************************************************************************
252 start a directory listing
253 ****************************************************************************/
254 static BOOL start_dir(int cnum,char *directory)
256 DEBUG(5,("start_dir cnum=%d dir=%s\n",cnum,directory));
258 if (!check_name(directory,cnum))
264 Connections[cnum].dirptr = OpenDir(cnum, directory, True);
265 if (Connections[cnum].dirptr) {
267 string_set(&Connections[cnum].dirpath,directory);
275 /****************************************************************************
277 ****************************************************************************/
278 int dptr_create(int cnum,char *path, BOOL expect_close,int pid)
284 if (!start_dir(cnum,path))
285 return(-2); /* Code to say use a unix error return code. */
287 if (dptrs_open >= MAXDIR)
290 for (i=0;i<NUMDIRPTRS;i++)
291 if (!dirptrs[i].valid)
293 if (i == NUMDIRPTRS) i = -1;
296 /* as a 2nd option, grab the oldest not marked for expect_close */
300 for (i=0;i<NUMDIRPTRS;i++)
301 if (!dirptrs[i].expect_close && dirptrs[i].lastused < old) {
302 old = dirptrs[i].lastused;
308 /* a 3rd option - grab the oldest one */
312 for (i=0;i<NUMDIRPTRS;i++)
313 if (dirptrs[i].lastused < old) {
314 old = dirptrs[i].lastused;
321 DEBUG(0,("Error - all dirptrs in use??\n"));
325 if (dirptrs[i].valid)
328 dirptrs[i].ptr = Connections[cnum].dirptr;
329 string_set(&dirptrs[i].path,path);
330 dirptrs[i].lastused = dircounter++;
331 dirptrs[i].finished = False;
332 dirptrs[i].cnum = cnum;
333 dirptrs[i].pid = pid;
334 dirptrs[i].expect_close = expect_close;
335 dirptrs[i].wcard = NULL; /* Only used in lanman2 searches */
336 dirptrs[i].attr = 0; /* Only used in lanman2 searches */
337 dirptrs[i].valid = True;
339 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
340 i,path,expect_close));
345 #define DPTR_MASK ((uint32)(((uint32)1)<<31))
347 /****************************************************************************
348 fill the 5 byte server reserved dptr field
349 ****************************************************************************/
350 BOOL dptr_fill(char *buf1,unsigned int key)
352 unsigned char *buf = (unsigned char *)buf1;
353 void *p = dptr_get(key,0);
356 DEBUG(1,("filling null dirptr %d\n",key));
360 DEBUG(6,("fill on key %d dirptr 0x%x now at %d\n",key,p,offset));
362 SIVAL(buf,1,offset | DPTR_MASK);
367 /****************************************************************************
368 return True is the offset is at zero
369 ****************************************************************************/
370 BOOL dptr_zero(char *buf)
372 return((IVAL(buf,1)&~DPTR_MASK) == 0);
375 /****************************************************************************
376 fetch the dir ptr and seek it given the 5 byte server field
377 ****************************************************************************/
378 void *dptr_fetch(char *buf,int *num)
380 unsigned int key = *(unsigned char *)buf;
381 void *p = dptr_get(key,dircounter++);
384 DEBUG(3,("fetched null dirptr %d\n",key));
388 offset = IVAL(buf,1)&~DPTR_MASK;
390 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
391 key,dptr_path(key),offset));
395 /****************************************************************************
397 ****************************************************************************/
398 void *dptr_fetch_lanman2(int dptr_num)
400 void *p = dptr_get(dptr_num,dircounter++);
403 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
406 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
410 /****************************************************************************
411 check a filetype for being valid
412 ****************************************************************************/
413 BOOL dir_check_ftype(int cnum,int mode,struct stat *st,int dirtype)
415 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
420 /****************************************************************************
421 get a directory entry
422 ****************************************************************************/
423 BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend)
435 *path = *pathreal = *filename = 0;
437 isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
438 strequal(Connections[cnum].dirpath,".") ||
439 strequal(Connections[cnum].dirpath,"/"));
442 ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
444 if (!Connections[cnum].dirptr)
449 dname = ReadDirName(Connections[cnum].dirptr);
451 DEBUG(6,("readdir on dirptr 0x%x now at offset %d\n",
452 Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
459 pstrcpy(filename,dname);
461 if ((strcmp(filename,mask) == 0) ||
462 (name_map_mangle(filename,True,SNUM(cnum)) &&
463 mask_match(filename,mask,False,False)))
465 if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
468 pstrcpy(fname,filename);
470 pstrcpy(path,Connections[cnum].dirpath);
473 pstrcpy(pathreal,path);
475 strcat(pathreal,dname);
476 if (sys_stat(pathreal,&sbuf) != 0)
478 DEBUG(5,("Couldn't stat 1 [%s]\n",path));
483 !strequal(fname,".") && !strequal(fname,".."))
486 *mode = dos_mode(cnum,pathreal,&sbuf);
488 if (!dir_check_ftype(cnum,*mode,&sbuf,dirtype)) {
489 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
493 *size = sbuf.st_size;
494 *date = sbuf.st_mtime;
496 DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
517 /*******************************************************************
519 ********************************************************************/
520 void *OpenDir(int cnum, char *name, BOOL use_veto)
524 void *p = sys_opendir(name);
527 if (!p) return(NULL);
528 dirp = (Dir *)malloc(sizeof(Dir));
533 dirp->pos = dirp->numentries = dirp->mallocsize = 0;
534 dirp->data = dirp->current = NULL;
536 while ((n = readdirname(p)))
540 /* If it's a vetoed file, pretend it doesn't even exist */
541 if (use_veto && IS_VETO_PATH(cnum, n)) continue;
543 if (used + l > dirp->mallocsize) {
544 int s = MAX(used+l,used+2000);
546 r = (char *)Realloc(dirp->data,s);
548 DEBUG(0,("Out of memory in OpenDir\n"));
552 dirp->mallocsize = s;
553 dirp->current = dirp->data;
555 strcpy(dirp->data+used,n);
561 return((void *)dirp);
565 /*******************************************************************
567 ********************************************************************/
568 void CloseDir(void *p)
570 Dir *dirp = (Dir *)p;
572 if (dirp->data) free(dirp->data);
576 /*******************************************************************
577 read from a directory
578 ********************************************************************/
579 char *ReadDirName(void *p)
582 Dir *dirp = (Dir *)p;
584 if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
587 dirp->current = skip_string(dirp->current,1);
594 /*******************************************************************
596 ********************************************************************/
597 BOOL SeekDir(void *p,int pos)
599 Dir *dirp = (Dir *)p;
601 if (!dirp) return(False);
603 if (pos < dirp->pos) {
604 dirp->current = dirp->data;
608 while (dirp->pos < pos && ReadDirName(p)) ;
610 return(dirp->pos == pos);
613 /*******************************************************************
615 ********************************************************************/
618 Dir *dirp = (Dir *)p;
620 if (!dirp) return(-1);
626 /* -------------------------------------------------------------------------- **
627 * This section manages a global directory cache.
628 * (It should probably be split into a separate module. crh)
629 * -------------------------------------------------------------------------- **
641 static ubi_dlList dir_cache[1] = { { NULL, NULL, 0 } };
643 void DirCacheAdd( char *path, char *name, char *dname, int snum )
644 /* ------------------------------------------------------------------------ **
645 * Add an entry to the directory cache.
654 * ------------------------------------------------------------------------ **
659 dir_cache_entry *entry;
661 /* Allocate the structure & string space in one go so that it can be freed
662 * in one call to free().
664 pathlen = strlen( path ) +1; /* Bytes required to store path (with nul). */
665 namelen = strlen( name ) +1; /* Bytes required to store name (with nul). */
666 entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
669 + strlen( dname ) +1 );
670 if( NULL == entry ) /* Not adding to the cache is not fatal, */
671 return; /* so just return as if nothing happened. */
673 /* Set pointers correctly and load values. */
674 entry->path = strcpy( (char *)&entry[1], path);
675 entry->name = strcpy( &(entry->path[pathlen]), name);
676 entry->dname = strcpy( &(entry->name[namelen]), dname);
679 /* Add the new entry to the linked list. */
680 (void)ubi_dlAddHead( dir_cache, entry );
681 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
683 /* Free excess cache entries. */
684 while( DIRCACHESIZE < dir_cache->count )
685 free( ubi_dlRemTail( dir_cache ) );
690 char *DirCacheCheck( char *path, char *name, int snum )
691 /* ------------------------------------------------------------------------ **
692 * Search for an entry to the directory cache.
698 * Output: The dname string of the located entry, or NULL if the entry was
701 * Notes: This uses a linear search, which is is okay because of
702 * the small size of the cache. Use a splay tree or hash
705 * ------------------------------------------------------------------------ **
708 dir_cache_entry *entry;
710 for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
712 entry = (dir_cache_entry *)ubi_dlNext( entry ) )
714 if( entry->snum == snum
715 && 0 == strcmp( name, entry->name )
716 && 0 == strcmp( path, entry->path ) )
718 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
719 return( entry->dname );
724 } /* DirCacheCheck */
726 void DirCacheFlush( int snum )
727 /* ------------------------------------------------------------------------ **
728 * Remove all cache entries which have an snum that matches the input.
734 * ------------------------------------------------------------------------ **
737 dir_cache_entry *entry;
740 for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); NULL != entry; )
742 next = ubi_dlNext( entry );
743 if( entry->snum == snum )
744 free( ubi_dlRemThis( dir_cache, entry ) );
745 entry = (dir_cache_entry *)next;
747 } /* DirCacheFlush */
749 /* -------------------------------------------------------------------------- **
750 * End of the section that manages the global directory cache.
751 * -------------------------------------------------------------------------- **
756 /* This is getcwd.c from bash. It is needed in Interactive UNIX. To
757 * add support for another OS you need to determine which of the
758 * conditional compilation macros you need to define. All the options
759 * are defined for Interactive UNIX.
762 #define HAVE_UNISTD_H
767 #if defined (HAVE_UNISTD_H)
771 #if defined (__STDC__)
774 #else /* !__STDC__ */
777 #endif /* !__STDC__ */
779 #if !defined (PATH_MAX)
780 # if defined (MAXPATHLEN)
781 # define PATH_MAX MAXPATHLEN
782 # else /* !MAXPATHLEN */
783 # define PATH_MAX 1024
784 # endif /* !MAXPATHLEN */
785 #endif /* !PATH_MAX */
787 #if defined (_POSIX_VERSION) || defined (USGr3) || defined (HAVE_DIRENT_H)
788 # if !defined (HAVE_DIRENT)
790 # endif /* !HAVE_DIRENT */
791 #endif /* _POSIX_VERSION || USGr3 || HAVE_DIRENT_H */
793 #if defined (HAVE_DIRENT)
794 # define D_NAMLEN(d) (strlen ((d)->d_name))
796 # define D_NAMLEN(d) ((d)->d_namlen)
797 #endif /* ! (_POSIX_VERSION || USGr3) */
799 #if defined (USG) || defined (USGr3)
800 # define d_fileno d_ino
803 #if !defined (alloca)
804 extern char *alloca ();
807 /* Get the pathname of the current working directory,
808 and put it in SIZE bytes of BUF. Returns NULL if the
809 directory couldn't be determined or SIZE was too small.
810 If successful, returns BUF. In GNU, if BUF is NULL,
811 an array is allocated with `malloc'; the array is SIZE
812 bytes long, unless SIZE <= 0, in which case it is as
814 #if defined (__STDC__)
816 getcwd (char *buf, size_t size)
817 #else /* !__STDC__ */
822 #endif /* !__STDC__ */
824 static CONST char dots[]
825 = "../../../../../../../../../../../../../../../../../../../../../../../\
826 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
827 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
828 CONST char *dotp, *dotlist;
830 dev_t rootdev, thisdev;
831 ino_t rootino, thisino;
832 char path[PATH_MAX + 1];
833 register char *pathp;
838 if (buf != NULL && size == 0)
841 return ((char *)NULL);
844 pathsize = sizeof (path);
845 pathp = &path[pathsize];
849 if (stat (".", &st) < 0)
850 return ((char *)NULL);
854 if (stat ("/", &st) < 0)
855 return ((char *)NULL);
859 dotsize = sizeof (dots) - 1;
860 dotp = &dots[sizeof (dots)];
862 while (!(thisdev == rootdev && thisino == rootino))
864 register DIR *dirstream;
865 register struct dirent *d;
871 /* Look at the parent directory. */
874 /* My, what a deep directory tree you have, Grandma. */
878 new = malloc (dotsize * 2 + 1);
881 memcpy (new, dots, dotsize);
885 new = realloc ((PTR) dotlist, dotsize * 2 + 1);
889 memcpy (&new[dotsize], new, dotsize);
890 dotp = &new[dotsize];
898 /* Figure out if this directory is a mount point. */
899 if (stat (dotp, &st) < 0)
903 mount_point = dotdev != thisdev;
905 /* Search for the last directory. */
906 dirstream = opendir(dotp);
907 if (dirstream == NULL)
909 while ((d = (struct dirent *)readdir(dirstream)) != NULL)
911 if (d->d_name[0] == '.' &&
912 (d->d_name[1] == '\0' ||
913 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
915 if (mount_point || d->d_fileno == thisino)
919 namlen = D_NAMLEN(d);
921 alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
922 memcpy (name, dotp, dotlist + dotsize - dotp);
923 name[dotlist + dotsize - dotp] = '/';
924 memcpy (&name[dotlist + dotsize - dotp + 1],
925 d->d_name, namlen + 1);
926 if (lstat (name, &st) < 0)
933 if (st.st_dev == thisdev && st.st_ino == thisino)
948 while ((space = pathp - pathbuf) <= namlen)
954 new = malloc (pathsize * 2);
960 new = realloc ((PTR) pathbuf, (pathsize * 2));
965 (void) memcpy (new + pathsize + space, pathp, pathsize - space);
966 pathp = new + pathsize + space;
972 (void) memcpy (pathp, d->d_name, namlen);
981 if (pathp == &path[sizeof(path) - 1])
985 free ((PTR) dotlist);
988 size_t len = pathbuf + pathsize - pathp;
991 if (len < (size_t) size)
993 buf = (char *) malloc (len);
997 else if ((size_t) size < len)
1002 (void) memcpy((PTR) buf, (PTR) pathp, len);
1005 if (pathbuf != path)
1011 if ((dotlist != dots) && dotlist)
1014 free ((PTR) dotlist);
1019 if ((pathbuf != path) && pathbuf)
1022 free ((PTR) pathbuf);
1025 return ((char *)NULL);