2 Unix SMB/Netbios implementation.
4 Directory handling routines
5 Copyright (C) Andrew Tridgell 1992-1997
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 /****************************************************************************
396 fetch the dir ptr and seek it given the lanman2 parameter block
397 ****************************************************************************/
398 void *dptr_fetch_lanman2(char *params,int dptr_num)
400 void *p = dptr_get(dptr_num,dircounter++);
401 uint32 resume_key = SVAL(params,6);
402 BOOL uses_resume_key = BITSETW(params+10,2);
403 BOOL continue_bit = BITSETW(params+10,3);
406 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
409 if(uses_resume_key && !continue_bit)
410 SeekDir(p,resume_key);
411 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
415 /****************************************************************************
416 check a filetype for being valid
417 ****************************************************************************/
418 BOOL dir_check_ftype(int cnum,int mode,struct stat *st,int dirtype)
420 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
425 /****************************************************************************
426 get a directory entry
427 ****************************************************************************/
428 BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend)
440 *path = *pathreal = *filename = 0;
442 isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
443 strequal(Connections[cnum].dirpath,".") ||
444 strequal(Connections[cnum].dirpath,"/"));
447 ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
449 if (!Connections[cnum].dirptr)
454 dname = ReadDirName(Connections[cnum].dirptr);
456 DEBUG(6,("readdir on dirptr 0x%x now at offset %d\n",
457 Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
464 pstrcpy(filename,dname);
466 if ((strcmp(filename,mask) == 0) ||
467 (name_map_mangle(filename,True,SNUM(cnum)) &&
468 mask_match(filename,mask,False,False)))
470 if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
473 pstrcpy(fname,filename);
475 pstrcpy(path,Connections[cnum].dirpath);
478 pstrcpy(pathreal,path);
480 strcat(pathreal,dname);
481 if (sys_stat(pathreal,&sbuf) != 0)
483 DEBUG(5,("Couldn't stat 1 [%s]\n",path));
488 !strequal(fname,".") && !strequal(fname,".."))
491 *mode = dos_mode(cnum,pathreal,&sbuf);
493 if (!dir_check_ftype(cnum,*mode,&sbuf,dirtype)) {
494 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
498 *size = sbuf.st_size;
499 *date = sbuf.st_mtime;
501 DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
522 /*******************************************************************
524 ********************************************************************/
525 void *OpenDir(int cnum, char *name, BOOL use_veto)
529 void *p = sys_opendir(name);
532 if (!p) return(NULL);
533 dirp = (Dir *)malloc(sizeof(Dir));
538 dirp->pos = dirp->numentries = dirp->mallocsize = 0;
539 dirp->data = dirp->current = NULL;
541 while ((n = readdirname(p)))
545 /* If it's a vetoed file, pretend it doesn't even exist */
546 if (use_veto && IS_VETO_PATH(cnum, n)) continue;
548 if (used + l > dirp->mallocsize) {
549 int s = MAX(used+l,used+2000);
551 r = (char *)Realloc(dirp->data,s);
553 DEBUG(0,("Out of memory in OpenDir\n"));
557 dirp->mallocsize = s;
558 dirp->current = dirp->data;
560 strcpy(dirp->data+used,n);
566 return((void *)dirp);
570 /*******************************************************************
572 ********************************************************************/
573 void CloseDir(void *p)
575 Dir *dirp = (Dir *)p;
577 if (dirp->data) free(dirp->data);
581 /*******************************************************************
582 read from a directory
583 ********************************************************************/
584 char *ReadDirName(void *p)
587 Dir *dirp = (Dir *)p;
589 if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
592 dirp->current = skip_string(dirp->current,1);
599 /*******************************************************************
601 ********************************************************************/
602 BOOL SeekDir(void *p,int pos)
604 Dir *dirp = (Dir *)p;
606 if (!dirp) return(False);
608 if (pos < dirp->pos) {
609 dirp->current = dirp->data;
613 while (dirp->pos < pos && ReadDirName(p)) ;
615 return(dirp->pos == pos);
618 /*******************************************************************
620 ********************************************************************/
623 Dir *dirp = (Dir *)p;
625 if (!dirp) return(-1);
631 static int dir_cache_size = 0;
632 static struct dir_cache {
633 struct dir_cache *next;
634 struct dir_cache *prev;
641 /*******************************************************************
642 add an entry to the directory cache
643 ********************************************************************/
644 void DirCacheAdd(char *path,char *name,char *dname,int snum)
647 struct dir_cache *entry = (struct dir_cache *)malloc(sizeof(*entry));
649 entry->path = strdup(path);
650 entry->name = strdup(name);
651 entry->dname = strdup(dname);
653 if (!entry->path || !entry->name || !entry->dname) return;
655 entry->next = dir_cache;
657 if (entry->next) entry->next->prev = entry;
660 DEBUG(4,("Added dir cache entry %s %s -> %s\n",path,name,dname));
662 if (dir_cache_size == DIRCACHESIZE) {
663 for (entry=dir_cache, count=1;
664 entry->next && count < dir_cache_size + 1;
665 entry=entry->next, count++) ;
666 if (entry->next || count != dir_cache_size + 1) {
667 DEBUG(0,("DirCache bug - please report %d %d\n",dir_cache_size,count));
672 if (entry->prev) entry->prev->next = entry->next;
680 /*******************************************************************
681 check for an entry in the directory cache
682 ********************************************************************/
683 char *DirCacheCheck(char *path,char *name,int snum)
685 struct dir_cache *entry;
687 for (entry=dir_cache; entry; entry=entry->next) {
688 if (entry->snum == snum &&
689 strcmp(path,entry->path) == 0 &&
690 strcmp(name,entry->name) == 0) {
691 DEBUG(4,("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
692 return(entry->dname);
699 /*******************************************************************
700 flush entries in the dir_cache
701 ********************************************************************/
702 void DirCacheFlush(int snum)
704 struct dir_cache *entry,*next;
706 for (entry=dir_cache; entry; entry=next) {
707 if (entry->snum == snum) {
712 if (entry->prev) entry->prev->next = entry->next;
713 if (entry->next) entry->next->prev = entry->prev;
714 if (dir_cache == entry) dir_cache = entry->next;
725 /* This is getcwd.c from bash. It is needed in Interactive UNIX. To
726 * add support for another OS you need to determine which of the
727 * conditional compilation macros you need to define. All the options
728 * are defined for Interactive UNIX.
731 #define HAVE_UNISTD_H
736 #if defined (HAVE_UNISTD_H)
740 #if defined (__STDC__)
743 #else /* !__STDC__ */
746 #endif /* !__STDC__ */
748 #if !defined (PATH_MAX)
749 # if defined (MAXPATHLEN)
750 # define PATH_MAX MAXPATHLEN
751 # else /* !MAXPATHLEN */
752 # define PATH_MAX 1024
753 # endif /* !MAXPATHLEN */
754 #endif /* !PATH_MAX */
756 #if defined (_POSIX_VERSION) || defined (USGr3) || defined (HAVE_DIRENT_H)
757 # if !defined (HAVE_DIRENT)
759 # endif /* !HAVE_DIRENT */
760 #endif /* _POSIX_VERSION || USGr3 || HAVE_DIRENT_H */
762 #if defined (HAVE_DIRENT)
763 # define D_NAMLEN(d) (strlen ((d)->d_name))
765 # define D_NAMLEN(d) ((d)->d_namlen)
766 #endif /* ! (_POSIX_VERSION || USGr3) */
768 #if defined (USG) || defined (USGr3)
769 # define d_fileno d_ino
772 #if !defined (alloca)
773 extern char *alloca ();
776 /* Get the pathname of the current working directory,
777 and put it in SIZE bytes of BUF. Returns NULL if the
778 directory couldn't be determined or SIZE was too small.
779 If successful, returns BUF. In GNU, if BUF is NULL,
780 an array is allocated with `malloc'; the array is SIZE
781 bytes long, unless SIZE <= 0, in which case it is as
783 #if defined (__STDC__)
785 getcwd (char *buf, size_t size)
786 #else /* !__STDC__ */
791 #endif /* !__STDC__ */
793 static CONST char dots[]
794 = "../../../../../../../../../../../../../../../../../../../../../../../\
795 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
796 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
797 CONST char *dotp, *dotlist;
799 dev_t rootdev, thisdev;
800 ino_t rootino, thisino;
801 char path[PATH_MAX + 1];
802 register char *pathp;
807 if (buf != NULL && size == 0)
810 return ((char *)NULL);
813 pathsize = sizeof (path);
814 pathp = &path[pathsize];
818 if (stat (".", &st) < 0)
819 return ((char *)NULL);
823 if (stat ("/", &st) < 0)
824 return ((char *)NULL);
828 dotsize = sizeof (dots) - 1;
829 dotp = &dots[sizeof (dots)];
831 while (!(thisdev == rootdev && thisino == rootino))
833 register DIR *dirstream;
834 register struct dirent *d;
840 /* Look at the parent directory. */
843 /* My, what a deep directory tree you have, Grandma. */
847 new = malloc (dotsize * 2 + 1);
850 memcpy (new, dots, dotsize);
854 new = realloc ((PTR) dotlist, dotsize * 2 + 1);
858 memcpy (&new[dotsize], new, dotsize);
859 dotp = &new[dotsize];
867 /* Figure out if this directory is a mount point. */
868 if (stat (dotp, &st) < 0)
872 mount_point = dotdev != thisdev;
874 /* Search for the last directory. */
875 dirstream = opendir(dotp);
876 if (dirstream == NULL)
878 while ((d = (struct dirent *)readdir(dirstream)) != NULL)
880 if (d->d_name[0] == '.' &&
881 (d->d_name[1] == '\0' ||
882 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
884 if (mount_point || d->d_fileno == thisino)
888 namlen = D_NAMLEN(d);
890 alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
891 memcpy (name, dotp, dotlist + dotsize - dotp);
892 name[dotlist + dotsize - dotp] = '/';
893 memcpy (&name[dotlist + dotsize - dotp + 1],
894 d->d_name, namlen + 1);
895 if (lstat (name, &st) < 0)
902 if (st.st_dev == thisdev && st.st_ino == thisino)
917 while ((space = pathp - pathbuf) <= namlen)
923 new = malloc (pathsize * 2);
929 new = realloc ((PTR) pathbuf, (pathsize * 2));
934 (void) memcpy (new + pathsize + space, pathp, pathsize - space);
935 pathp = new + pathsize + space;
941 (void) memcpy (pathp, d->d_name, namlen);
950 if (pathp == &path[sizeof(path) - 1])
954 free ((PTR) dotlist);
957 size_t len = pathbuf + pathsize - pathp;
960 if (len < (size_t) size)
962 buf = (char *) malloc (len);
966 else if ((size_t) size < len)
971 (void) memcpy((PTR) buf, (PTR) pathp, len);
980 if ((dotlist != dots) && dotlist)
983 free ((PTR) dotlist);
988 if ((pathbuf != path) && pathbuf)
991 free ((PTR) pathbuf);
994 return ((char *)NULL);