made "hide files" and "veto files" into per-service parameter sections,
[Samba.git] / source / smbd / dir.c
blobf674c92804b09f4d27e07ae1e3de3cbf8cb4d158
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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.
22 #include "includes.h"
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
41 int pid;
42 int cnum;
43 uint32 lastused;
44 void *ptr;
45 BOOL valid;
46 BOOL finished;
47 BOOL expect_close;
48 char *wcard; /* Field only used for lanman2 trans2_findfirst/next searches */
49 uint16 attr; /* Field only used for lanman2 trans2_findfirst/next searches */
50 char *path;
52 dirptrs[NUMDIRPTRS];
55 static int dptrs_open = 0;
57 /****************************************************************************
58 initialise the dir array
59 ****************************************************************************/
60 void init_dptrs(void)
62 static BOOL dptrs_init=False;
63 int i;
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,"");
73 dptrs_init = True;
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));
83 dptrs_open--;
84 CloseDir(dirptrs[key].ptr);
85 dirptrs[key].ptr = NULL;
89 /****************************************************************************
90 idle the oldest dptr
91 ****************************************************************************/
92 static void dptr_idleoldest(void)
94 int i;
95 uint32 old=dircounter+1;
96 int oldi= -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;
100 oldi = i;
102 if (oldi != -1)
103 dptr_idle(oldi);
104 else
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 cnum, int key,uint32 lastused)
113 if (dirptrs[key].valid) {
114 if (lastused) dirptrs[key].lastused = lastused;
115 if (!dirptrs[key].ptr) {
116 if (dptrs_open >= MAXDIR)
117 dptr_idleoldest();
118 DEBUG(4,("Reopening dptr key %d\n",key));
119 if ((dirptrs[key].ptr = OpenDir(cnum, dirptrs[key].path)))
120 dptrs_open++;
122 return(dirptrs[key].ptr);
124 return(NULL);
127 /****************************************************************************
128 get the dir path for a dir index
129 ****************************************************************************/
130 char *dptr_path(int key)
132 if (dirptrs[key].valid)
133 return(dirptrs[key].path);
134 return(NULL);
137 /****************************************************************************
138 get the dir wcard for a dir index (lanman2 specific)
139 ****************************************************************************/
140 char *dptr_wcard(int key)
142 if (dirptrs[key].valid)
143 return(dirptrs[key].wcard);
144 return(NULL);
147 /****************************************************************************
148 set the dir wcard for a dir index (lanman2 specific)
149 Returns 0 on ok, 1 on fail.
150 ****************************************************************************/
151 BOOL dptr_set_wcard(int key, char *wcard)
153 if (dirptrs[key].valid) {
154 dirptrs[key].wcard = wcard;
155 return True;
157 return False;
160 /****************************************************************************
161 set the dir attrib for a dir index (lanman2 specific)
162 Returns 0 on ok, 1 on fail.
163 ****************************************************************************/
164 BOOL dptr_set_attr(int key, uint16 attr)
166 if (dirptrs[key].valid) {
167 dirptrs[key].attr = attr;
168 return True;
170 return False;
173 /****************************************************************************
174 get the dir attrib for a dir index (lanman2 specific)
175 ****************************************************************************/
176 uint16 dptr_attr(int key)
178 if (dirptrs[key].valid)
179 return(dirptrs[key].attr);
180 return(0);
183 /****************************************************************************
184 close a dptr
185 ****************************************************************************/
186 void dptr_close(int key)
188 /* OS/2 seems to use -1 to indicate "close all directories" */
189 if (key == -1) {
190 int i;
191 for (i=0;i<NUMDIRPTRS;i++)
192 dptr_close(i);
193 return;
196 if (key < 0 || key >= NUMDIRPTRS) {
197 DEBUG(3,("Invalid key %d given to dptr_close\n",key));
198 return;
201 if (dirptrs[key].valid) {
202 DEBUG(4,("closing dptr key %d\n",key));
203 if (dirptrs[key].ptr) {
204 CloseDir(dirptrs[key].ptr);
205 dptrs_open--;
207 /* Lanman 2 specific code */
208 if (dirptrs[key].wcard)
209 free(dirptrs[key].wcard);
210 dirptrs[key].valid = False;
211 string_set(&dirptrs[key].path,"");
215 /****************************************************************************
216 close all dptrs for a cnum
217 ****************************************************************************/
218 void dptr_closecnum(int cnum)
220 int i;
221 for (i=0;i<NUMDIRPTRS;i++)
222 if (dirptrs[i].valid && dirptrs[i].cnum == cnum)
223 dptr_close(i);
226 /****************************************************************************
227 idle all dptrs for a cnum
228 ****************************************************************************/
229 void dptr_idlecnum(int cnum)
231 int i;
232 for (i=0;i<NUMDIRPTRS;i++)
233 if (dirptrs[i].valid && dirptrs[i].cnum == cnum && dirptrs[i].ptr)
234 dptr_idle(i);
237 /****************************************************************************
238 close a dptr that matches a given path, only if it matches the pid also
239 ****************************************************************************/
240 void dptr_closepath(char *path,int pid)
242 int i;
243 for (i=0;i<NUMDIRPTRS;i++)
244 if (dirptrs[i].valid && pid == dirptrs[i].pid &&
245 strequal(dirptrs[i].path,path))
246 dptr_close(i);
249 /****************************************************************************
250 start a directory listing
251 ****************************************************************************/
252 static BOOL start_dir(int cnum,char *directory)
254 DEBUG(5,("start_dir cnum=%d dir=%s\n",cnum,directory));
256 if (!check_name(directory,cnum))
257 return(False);
259 if (! *directory)
260 directory = ".";
262 Connections[cnum].dirptr = OpenDir(cnum, directory);
263 if (Connections[cnum].dirptr) {
264 dptrs_open++;
265 string_set(&Connections[cnum].dirpath,directory);
266 return(True);
269 return(False);
273 /****************************************************************************
274 create a new dir ptr
275 ****************************************************************************/
276 int dptr_create(int cnum,char *path, BOOL expect_close,int pid)
278 int i;
279 uint32 old;
280 int oldi;
282 if (!start_dir(cnum,path))
283 return(-1);
285 if (dptrs_open >= MAXDIR)
286 dptr_idleoldest();
288 for (i=0;i<NUMDIRPTRS;i++)
289 if (!dirptrs[i].valid)
290 break;
291 if (i == NUMDIRPTRS) i = -1;
294 /* as a 2nd option, grab the oldest not marked for expect_close */
295 if (i == -1) {
296 old=dircounter+1;
297 oldi= -1;
298 for (i=0;i<NUMDIRPTRS;i++)
299 if (!dirptrs[i].expect_close && dirptrs[i].lastused < old) {
300 old = dirptrs[i].lastused;
301 oldi = i;
303 i = oldi;
306 /* a 3rd option - grab the oldest one */
307 if (i == -1) {
308 old=dircounter+1;
309 oldi= -1;
310 for (i=0;i<NUMDIRPTRS;i++)
311 if (dirptrs[i].lastused < old) {
312 old = dirptrs[i].lastused;
313 oldi = i;
315 i = oldi;
318 if (i == -1) {
319 DEBUG(0,("Error - all dirptrs in use??\n"));
320 return(-1);
323 if (dirptrs[i].valid)
324 dptr_close(i);
326 dirptrs[i].ptr = Connections[cnum].dirptr;
327 string_set(&dirptrs[i].path,path);
328 dirptrs[i].lastused = dircounter++;
329 dirptrs[i].finished = False;
330 dirptrs[i].cnum = cnum;
331 dirptrs[i].pid = pid;
332 dirptrs[i].expect_close = expect_close;
333 dirptrs[i].wcard = NULL; /* Only used in lanman2 searches */
334 dirptrs[i].attr = 0; /* Only used in lanman2 searches */
335 dirptrs[i].valid = True;
337 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
338 i,path,expect_close));
340 return(i);
343 #define DPTR_MASK ((uint32)(((uint32)1)<<31))
345 /****************************************************************************
346 fill the 5 byte server reserved dptr field
347 ****************************************************************************/
348 BOOL dptr_fill(int cnum, char *buf1,unsigned int key)
350 unsigned char *buf = (unsigned char *)buf1;
351 void *p = dptr_get(cnum, key,0);
352 uint32 offset;
353 if (!p) {
354 DEBUG(1,("filling null dirptr %d\n",key));
355 return(False);
357 offset = TellDir(p);
358 DEBUG(6,("fill on key %d dirptr 0x%x now at %d\n",key,p,offset));
359 buf[0] = key;
360 SIVAL(buf,1,offset | DPTR_MASK);
361 return(True);
365 /****************************************************************************
366 return True is the offset is at zero
367 ****************************************************************************/
368 BOOL dptr_zero(char *buf)
370 return((IVAL(buf,1)&~DPTR_MASK) == 0);
373 /****************************************************************************
374 fetch the dir ptr and seek it given the 5 byte server field
375 ****************************************************************************/
376 void *dptr_fetch(int cnum, char *buf,int *num)
378 unsigned int key = *(unsigned char *)buf;
379 void *p = dptr_get(cnum, key,dircounter++);
380 uint32 offset;
381 if (!p) {
382 DEBUG(3,("fetched null dirptr %d\n",key));
383 return(NULL);
385 *num = key;
386 offset = IVAL(buf,1)&~DPTR_MASK;
387 SeekDir(p,offset);
388 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
389 key,dptr_path(key),offset));
390 return(p);
393 /****************************************************************************
394 fetch the dir ptr and seek it given the lanman2 parameter block
395 ****************************************************************************/
396 void *dptr_fetch_lanman2(int cnum, char *params,int dptr_num)
398 void *p = dptr_get(cnum, dptr_num,dircounter++);
399 uint32 resume_key = SVAL(params,6);
400 BOOL uses_resume_key = BITSETW(params+10,2);
401 BOOL continue_bit = BITSETW(params+10,3);
403 if (!p) {
404 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
405 return(NULL);
407 if(uses_resume_key && !continue_bit)
408 SeekDir(p,resume_key);
409 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
410 return(p);
413 /****************************************************************************
414 check a filetype for being valid
415 ****************************************************************************/
416 BOOL dir_check_ftype(int cnum,int mode,struct stat *st,int dirtype)
418 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
419 return False;
420 return True;
423 /****************************************************************************
424 get a directory entry
425 ****************************************************************************/
426 BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend)
428 char *dname;
429 BOOL found = False;
430 struct stat sbuf;
431 pstring path;
432 pstring pathreal;
433 BOOL isrootdir;
434 pstring filename;
435 BOOL matched;
436 BOOL needslash;
438 *path = *pathreal = *filename = 0;
440 isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
441 strequal(Connections[cnum].dirpath,".") ||
442 strequal(Connections[cnum].dirpath,"/"));
444 needslash =
445 ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
447 if (!Connections[cnum].dirptr)
448 return(False);
450 while (!found)
452 dname = ReadDirName(Connections[cnum].dirptr);
454 DEBUG(6,("readdir on dirptr 0x%x now at offset %d\n",
455 Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
457 if (dname == NULL)
458 return(False);
460 matched = False;
462 strcpy(filename,dname);
464 if ((strcmp(filename,mask) == 0) ||
465 (name_map_mangle(filename,True,SNUM(cnum)) &&
466 mask_match(filename,mask,False,False)))
468 if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
469 continue;
471 strcpy(fname,filename);
472 *path = 0;
473 strcpy(path,Connections[cnum].dirpath);
474 if(needslash)
475 strcat(path,"/");
476 strcpy(pathreal,path);
477 strcat(path,fname);
478 strcat(pathreal,dname);
479 if (sys_stat(pathreal,&sbuf) != 0)
481 DEBUG(5,("Couldn't stat 1 [%s]\n",path));
482 continue;
485 if (check_descend &&
486 !strequal(fname,".") && !strequal(fname,".."))
487 continue;
489 *mode = dos_mode(cnum,pathreal,&sbuf);
491 if (!dir_check_ftype(cnum,*mode,&sbuf,dirtype)) {
492 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
493 continue;
496 *size = sbuf.st_size;
497 *date = sbuf.st_mtime;
499 DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
501 found = True;
505 return(found);
510 typedef struct
512 int pos;
513 int numentries;
514 int mallocsize;
515 char *data;
516 char *current;
517 } Dir;
520 /*******************************************************************
521 open a directory
522 ********************************************************************/
523 void *OpenDir(int cnum, char *name)
525 Dir *dirp;
526 char *n;
527 void *p = sys_opendir(name);
528 int used=0;
530 if (!p) return(NULL);
531 dirp = (Dir *)malloc(sizeof(Dir));
532 if (!dirp) {
533 closedir(p);
534 return(NULL);
536 dirp->pos = dirp->numentries = dirp->mallocsize = 0;
537 dirp->data = dirp->current = NULL;
539 while ((n = readdirname(p))) {
540 int l = strlen(n)+1;
541 /* If it's a vetoed file, pretend it doesn't even exist */
542 if(is_vetoed_name(cnum, n))
543 continue;
544 if (used + l > dirp->mallocsize) {
545 int s = MAX(used+l,used+2000);
546 char *r;
547 r = (char *)Realloc(dirp->data,s);
548 if (!r) {
549 DEBUG(0,("Out of memory in OpenDir\n"));
550 break;
552 dirp->data = r;
553 dirp->mallocsize = s;
554 dirp->current = dirp->data;
556 strcpy(dirp->data+used,n);
557 used += l;
558 dirp->numentries++;
561 closedir(p);
562 return((void *)dirp);
566 /*******************************************************************
567 close a directory
568 ********************************************************************/
569 void CloseDir(void *p)
571 Dir *dirp = (Dir *)p;
572 if (!dirp) return;
573 if (dirp->data) free(dirp->data);
574 free(dirp);
577 /*******************************************************************
578 read from a directory
579 ********************************************************************/
580 char *ReadDirName(void *p)
582 char *ret;
583 Dir *dirp = (Dir *)p;
585 if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
587 ret = dirp->current;
588 dirp->current = skip_string(dirp->current,1);
589 dirp->pos++;
591 return(ret);
595 /*******************************************************************
596 seek a dir
597 ********************************************************************/
598 BOOL SeekDir(void *p,int pos)
600 Dir *dirp = (Dir *)p;
602 if (!dirp) return(False);
604 if (pos < dirp->pos) {
605 dirp->current = dirp->data;
606 dirp->pos = 0;
609 while (dirp->pos < pos && ReadDirName(p)) ;
611 return(dirp->pos == pos);
614 /*******************************************************************
615 tell a dir position
616 ********************************************************************/
617 int TellDir(void *p)
619 Dir *dirp = (Dir *)p;
621 if (!dirp) return(-1);
623 return(dirp->pos);
627 static int dir_cache_size = 0;
628 static struct dir_cache {
629 struct dir_cache *next;
630 struct dir_cache *prev;
631 char *path;
632 char *name;
633 char *dname;
634 int snum;
635 } *dir_cache = NULL;
637 /*******************************************************************
638 add an entry to the directory cache
639 ********************************************************************/
640 void DirCacheAdd(char *path,char *name,char *dname,int snum)
642 int count;
643 struct dir_cache *entry = (struct dir_cache *)malloc(sizeof(*entry));
644 if (!entry) return;
645 entry->path = strdup(path);
646 entry->name = strdup(name);
647 entry->dname = strdup(dname);
648 entry->snum = snum;
649 if (!entry->path || !entry->name || !entry->dname) return;
651 entry->next = dir_cache;
652 entry->prev = NULL;
653 if (entry->next) entry->next->prev = entry;
654 dir_cache = entry;
656 DEBUG(4,("Added dir cache entry %s %s -> %s\n",path,name,dname));
658 if (dir_cache_size == DIRCACHESIZE) {
659 for (entry=dir_cache, count=1;
660 entry->next && count < dir_cache_size + 1;
661 entry=entry->next, count++) ;
662 if (entry->next || count != dir_cache_size + 1) {
663 DEBUG(0,("DirCache bug - please report %d %d\n",dir_cache_size,count));
665 free(entry->path);
666 free(entry->name);
667 free(entry->dname);
668 if (entry->prev) entry->prev->next = entry->next;
669 free(entry);
670 } else {
671 dir_cache_size++;
676 /*******************************************************************
677 check for an entry in the directory cache
678 ********************************************************************/
679 char *DirCacheCheck(char *path,char *name,int snum)
681 struct dir_cache *entry;
683 for (entry=dir_cache; entry; entry=entry->next) {
684 if (entry->snum == snum &&
685 strcmp(path,entry->path) == 0 &&
686 strcmp(name,entry->name) == 0) {
687 DEBUG(4,("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
688 return(entry->dname);
692 return(NULL);
695 /*******************************************************************
696 flush entries in the dir_cache
697 ********************************************************************/
698 void DirCacheFlush(int snum)
700 struct dir_cache *entry,*next;
702 for (entry=dir_cache; entry; entry=next) {
703 if (entry->snum == snum) {
704 free(entry->path);
705 free(entry->dname);
706 free(entry->name);
707 next = entry->next;
708 if (entry->prev) entry->prev->next = entry->next;
709 if (entry->next) entry->next->prev = entry->prev;
710 if (dir_cache == entry) dir_cache = entry->next;
711 free(entry);
712 dir_cache_size--;
713 } else {
714 next = entry->next;
720 #ifdef REPLACE_GETWD
721 /* This is getcwd.c from bash. It is needed in Interactive UNIX. To
722 * add support for another OS you need to determine which of the
723 * conditional compilation macros you need to define. All the options
724 * are defined for Interactive UNIX.
726 #ifdef ISC
727 #define HAVE_UNISTD_H
728 #define USGr3
729 #define USG
730 #endif
732 #if defined (HAVE_UNISTD_H)
733 # include <unistd.h>
734 #endif
736 #if defined (__STDC__)
737 # define CONST const
738 # define PTR void *
739 #else /* !__STDC__ */
740 # define CONST
741 # define PTR char *
742 #endif /* !__STDC__ */
744 #if !defined (PATH_MAX)
745 # if defined (MAXPATHLEN)
746 # define PATH_MAX MAXPATHLEN
747 # else /* !MAXPATHLEN */
748 # define PATH_MAX 1024
749 # endif /* !MAXPATHLEN */
750 #endif /* !PATH_MAX */
752 #if defined (_POSIX_VERSION) || defined (USGr3) || defined (HAVE_DIRENT_H)
753 # if !defined (HAVE_DIRENT)
754 # define HAVE_DIRENT
755 # endif /* !HAVE_DIRENT */
756 #endif /* _POSIX_VERSION || USGr3 || HAVE_DIRENT_H */
758 #if defined (HAVE_DIRENT)
759 # define D_NAMLEN(d) (strlen ((d)->d_name))
760 #else
761 # define D_NAMLEN(d) ((d)->d_namlen)
762 #endif /* ! (_POSIX_VERSION || USGr3) */
764 #if defined (USG) || defined (USGr3)
765 # define d_fileno d_ino
766 #endif
768 #if !defined (alloca)
769 extern char *alloca ();
770 #endif /* alloca */
772 /* Get the pathname of the current working directory,
773 and put it in SIZE bytes of BUF. Returns NULL if the
774 directory couldn't be determined or SIZE was too small.
775 If successful, returns BUF. In GNU, if BUF is NULL,
776 an array is allocated with `malloc'; the array is SIZE
777 bytes long, unless SIZE <= 0, in which case it is as
778 big as necessary. */
779 #if defined (__STDC__)
780 char *
781 getcwd (char *buf, size_t size)
782 #else /* !__STDC__ */
783 char *
784 getcwd (buf, size)
785 char *buf;
786 int size;
787 #endif /* !__STDC__ */
789 static CONST char dots[]
790 = "../../../../../../../../../../../../../../../../../../../../../../../\
791 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
792 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
793 CONST char *dotp, *dotlist;
794 size_t dotsize;
795 dev_t rootdev, thisdev;
796 ino_t rootino, thisino;
797 char path[PATH_MAX + 1];
798 register char *pathp;
799 char *pathbuf;
800 size_t pathsize;
801 struct stat st;
803 if (buf != NULL && size == 0)
805 errno = EINVAL;
806 return ((char *)NULL);
809 pathsize = sizeof (path);
810 pathp = &path[pathsize];
811 *--pathp = '\0';
812 pathbuf = path;
814 if (stat (".", &st) < 0)
815 return ((char *)NULL);
816 thisdev = st.st_dev;
817 thisino = st.st_ino;
819 if (stat ("/", &st) < 0)
820 return ((char *)NULL);
821 rootdev = st.st_dev;
822 rootino = st.st_ino;
824 dotsize = sizeof (dots) - 1;
825 dotp = &dots[sizeof (dots)];
826 dotlist = dots;
827 while (!(thisdev == rootdev && thisino == rootino))
829 register DIR *dirstream;
830 register struct dirent *d;
831 dev_t dotdev;
832 ino_t dotino;
833 char mount_point;
834 int namlen;
836 /* Look at the parent directory. */
837 if (dotp == dotlist)
839 /* My, what a deep directory tree you have, Grandma. */
840 char *new;
841 if (dotlist == dots)
843 new = malloc (dotsize * 2 + 1);
844 if (new == NULL)
845 goto lose;
846 memcpy (new, dots, dotsize);
848 else
850 new = realloc ((PTR) dotlist, dotsize * 2 + 1);
851 if (new == NULL)
852 goto lose;
854 memcpy (&new[dotsize], new, dotsize);
855 dotp = &new[dotsize];
856 dotsize *= 2;
857 new[dotsize] = '\0';
858 dotlist = new;
861 dotp -= 3;
863 /* Figure out if this directory is a mount point. */
864 if (stat (dotp, &st) < 0)
865 goto lose;
866 dotdev = st.st_dev;
867 dotino = st.st_ino;
868 mount_point = dotdev != thisdev;
870 /* Search for the last directory. */
871 dirstream = opendir(dotp);
872 if (dirstream == NULL)
873 goto lose;
874 while ((d = (struct dirent *)readdir(dirstream)) != NULL)
876 if (d->d_name[0] == '.' &&
877 (d->d_name[1] == '\0' ||
878 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
879 continue;
880 if (mount_point || d->d_fileno == thisino)
882 char *name;
884 namlen = D_NAMLEN(d);
885 name = (char *)
886 alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
887 memcpy (name, dotp, dotlist + dotsize - dotp);
888 name[dotlist + dotsize - dotp] = '/';
889 memcpy (&name[dotlist + dotsize - dotp + 1],
890 d->d_name, namlen + 1);
891 if (lstat (name, &st) < 0)
893 int save = errno;
894 closedir(dirstream);
895 errno = save;
896 goto lose;
898 if (st.st_dev == thisdev && st.st_ino == thisino)
899 break;
902 if (d == NULL)
904 int save = errno;
905 closedir(dirstream);
906 errno = save;
907 goto lose;
909 else
911 size_t space;
913 while ((space = pathp - pathbuf) <= namlen)
915 char *new;
917 if (pathbuf == path)
919 new = malloc (pathsize * 2);
920 if (!new)
921 goto lose;
923 else
925 new = realloc ((PTR) pathbuf, (pathsize * 2));
926 if (!new)
927 goto lose;
928 pathp = new + space;
930 (void) memcpy (new + pathsize + space, pathp, pathsize - space);
931 pathp = new + pathsize + space;
932 pathbuf = new;
933 pathsize *= 2;
936 pathp -= namlen;
937 (void) memcpy (pathp, d->d_name, namlen);
938 *--pathp = '/';
939 closedir(dirstream);
942 thisdev = dotdev;
943 thisino = dotino;
946 if (pathp == &path[sizeof(path) - 1])
947 *--pathp = '/';
949 if (dotlist != dots)
950 free ((PTR) dotlist);
953 size_t len = pathbuf + pathsize - pathp;
954 if (buf == NULL)
956 if (len < (size_t) size)
957 len = size;
958 buf = (char *) malloc (len);
959 if (buf == NULL)
960 goto lose2;
962 else if ((size_t) size < len)
964 errno = ERANGE;
965 goto lose2;
967 (void) memcpy((PTR) buf, (PTR) pathp, len);
970 if (pathbuf != path)
971 free (pathbuf);
973 return (buf);
975 lose:
976 if ((dotlist != dots) && dotlist)
978 int e = errno;
979 free ((PTR) dotlist);
980 errno = e;
983 lose2:
984 if ((pathbuf != path) && pathbuf)
986 int e = errno;
987 free ((PTR) pathbuf);
988 errno = e;
990 return ((char *)NULL);
992 #endif