'The mother of all checkins' :-). Jeremy Allison (jallison@whistle.com)
[Samba.git] / source / smbd / dir.c
blob2437b8b17e8dd2f6165f45b72d0bebe7ccf2f0f6
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 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(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(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(char *buf1,unsigned int key)
350 unsigned char *buf = (unsigned char *)buf1;
351 void *p = dptr_get(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(char *buf,int *num)
378 unsigned int key = *(unsigned char *)buf;
379 void *p = dptr_get(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(char *params,int dptr_num)
398 void *p = dptr_get(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;
437 *path = *pathreal = *filename = 0;
439 isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
440 strequal(Connections[cnum].dirpath,".") ||
441 strequal(Connections[cnum].dirpath,"/"));
443 if (!Connections[cnum].dirptr)
444 return(False);
446 while (!found)
448 dname = ReadDirName(Connections[cnum].dirptr);
450 DEBUG(6,("readdir on dirptr 0x%x now at offset %d\n",
451 Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
453 if (dname == NULL)
454 return(False);
456 matched = False;
458 strcpy(filename,dname);
460 if ((strcmp(filename,mask) == 0) ||
461 (name_map_mangle(filename,True,SNUM(cnum)) &&
462 mask_match(filename,mask,False,False)))
464 if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
465 continue;
467 strcpy(fname,filename);
468 *path = 0;
469 strcpy(path,Connections[cnum].dirpath);
470 strcat(path,"/");
471 strcpy(pathreal,path);
472 strcat(path,fname);
473 strcat(pathreal,dname);
474 if (sys_stat(pathreal,&sbuf) != 0)
476 DEBUG(5,("Couldn't stat 1 [%s]\n",path));
477 continue;
480 if (check_descend &&
481 !strequal(fname,".") && !strequal(fname,".."))
482 continue;
484 *mode = dos_mode(cnum,pathreal,&sbuf);
486 if (!dir_check_ftype(cnum,*mode,&sbuf,dirtype)) {
487 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
488 continue;
491 *size = sbuf.st_size;
492 *date = sbuf.st_mtime;
494 DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
496 found = True;
500 return(found);
505 typedef struct
507 int pos;
508 int numentries;
509 int mallocsize;
510 char *data;
511 char *current;
512 } Dir;
515 /*******************************************************************
516 open a directory
517 ********************************************************************/
518 void *OpenDir(char *name)
520 Dir *dirp;
521 char *n;
522 void *p = sys_opendir(name);
523 int used=0;
525 if (!p) return(NULL);
526 dirp = (Dir *)malloc(sizeof(Dir));
527 if (!dirp) {
528 closedir(p);
529 return(NULL);
531 dirp->pos = dirp->numentries = dirp->mallocsize = 0;
532 dirp->data = dirp->current = NULL;
534 while ((n = readdirname(p))) {
535 int l = strlen(n)+1;
536 /* If it's a vetoed file, pretend it doesn't even exist */
537 if(is_vetoed_name(n))
538 continue;
539 if (used + l > dirp->mallocsize) {
540 int s = MAX(used+l,used+2000);
541 char *r;
542 r = (char *)Realloc(dirp->data,s);
543 if (!r) {
544 DEBUG(0,("Out of memory in OpenDir\n"));
545 break;
547 dirp->data = r;
548 dirp->mallocsize = s;
549 dirp->current = dirp->data;
551 strcpy(dirp->data+used,n);
552 used += l;
553 dirp->numentries++;
556 closedir(p);
557 return((void *)dirp);
561 /*******************************************************************
562 close a directory
563 ********************************************************************/
564 void CloseDir(void *p)
566 Dir *dirp = (Dir *)p;
567 if (!dirp) return;
568 if (dirp->data) free(dirp->data);
569 free(dirp);
572 /*******************************************************************
573 read from a directory
574 ********************************************************************/
575 char *ReadDirName(void *p)
577 char *ret;
578 Dir *dirp = (Dir *)p;
580 if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
582 ret = dirp->current;
583 dirp->current = skip_string(dirp->current,1);
584 dirp->pos++;
586 return(ret);
590 /*******************************************************************
591 seek a dir
592 ********************************************************************/
593 BOOL SeekDir(void *p,int pos)
595 Dir *dirp = (Dir *)p;
597 if (!dirp) return(False);
599 if (pos < dirp->pos) {
600 dirp->current = dirp->data;
601 dirp->pos = 0;
604 while (dirp->pos < pos && ReadDirName(p)) ;
606 return(dirp->pos == pos);
609 /*******************************************************************
610 tell a dir position
611 ********************************************************************/
612 int TellDir(void *p)
614 Dir *dirp = (Dir *)p;
616 if (!dirp) return(-1);
618 return(dirp->pos);
622 static int dir_cache_size = 0;
623 static struct dir_cache {
624 struct dir_cache *next;
625 struct dir_cache *prev;
626 char *path;
627 char *name;
628 char *dname;
629 int snum;
630 } *dir_cache = NULL;
632 /*******************************************************************
633 add an entry to the directory cache
634 ********************************************************************/
635 void DirCacheAdd(char *path,char *name,char *dname,int snum)
637 int count;
638 struct dir_cache *entry = (struct dir_cache *)malloc(sizeof(*entry));
639 if (!entry) return;
640 entry->path = strdup(path);
641 entry->name = strdup(name);
642 entry->dname = strdup(dname);
643 entry->snum = snum;
644 if (!entry->path || !entry->name || !entry->dname) return;
646 entry->next = dir_cache;
647 entry->prev = NULL;
648 if (entry->next) entry->next->prev = entry;
649 dir_cache = entry;
651 DEBUG(4,("Added dir cache entry %s %s -> %s\n",path,name,dname));
653 if (dir_cache_size == DIRCACHESIZE) {
654 for (entry=dir_cache, count=1;
655 entry->next && count < dir_cache_size + 1;
656 entry=entry->next, count++) ;
657 if (entry->next || count != dir_cache_size + 1) {
658 DEBUG(0,("DirCache bug - please report %d %d\n",dir_cache_size,count));
660 free(entry->path);
661 free(entry->name);
662 free(entry->dname);
663 if (entry->prev) entry->prev->next = entry->next;
664 free(entry);
665 } else {
666 dir_cache_size++;
671 /*******************************************************************
672 check for an entry in the directory cache
673 ********************************************************************/
674 char *DirCacheCheck(char *path,char *name,int snum)
676 struct dir_cache *entry;
678 for (entry=dir_cache; entry; entry=entry->next) {
679 if (entry->snum == snum &&
680 strcmp(path,entry->path) == 0 &&
681 strcmp(name,entry->name) == 0) {
682 DEBUG(4,("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
683 return(entry->dname);
687 return(NULL);
690 /*******************************************************************
691 flush entries in the dir_cache
692 ********************************************************************/
693 void DirCacheFlush(int snum)
695 struct dir_cache *entry,*next;
697 for (entry=dir_cache; entry; entry=next) {
698 if (entry->snum == snum) {
699 free(entry->path);
700 free(entry->dname);
701 free(entry->name);
702 next = entry->next;
703 if (entry->prev) entry->prev->next = entry->next;
704 if (entry->next) entry->next->prev = entry->prev;
705 if (dir_cache == entry) dir_cache = entry->next;
706 free(entry);
707 dir_cache_size--;
708 } else {
709 next = entry->next;
715 #ifdef REPLACE_GETWD
716 /* This is getcwd.c from bash. It is needed in Interactive UNIX. To
717 * add support for another OS you need to determine which of the
718 * conditional compilation macros you need to define. All the options
719 * are defined for Interactive UNIX.
721 #ifdef ISC
722 #define HAVE_UNISTD_H
723 #define USGr3
724 #define USG
725 #endif
727 #if defined (HAVE_UNISTD_H)
728 # include <unistd.h>
729 #endif
731 #if defined (__STDC__)
732 # define CONST const
733 # define PTR void *
734 #else /* !__STDC__ */
735 # define CONST
736 # define PTR char *
737 #endif /* !__STDC__ */
739 #if !defined (PATH_MAX)
740 # if defined (MAXPATHLEN)
741 # define PATH_MAX MAXPATHLEN
742 # else /* !MAXPATHLEN */
743 # define PATH_MAX 1024
744 # endif /* !MAXPATHLEN */
745 #endif /* !PATH_MAX */
747 #if defined (_POSIX_VERSION) || defined (USGr3) || defined (HAVE_DIRENT_H)
748 # if !defined (HAVE_DIRENT)
749 # define HAVE_DIRENT
750 # endif /* !HAVE_DIRENT */
751 #endif /* _POSIX_VERSION || USGr3 || HAVE_DIRENT_H */
753 #if defined (HAVE_DIRENT)
754 # define D_NAMLEN(d) (strlen ((d)->d_name))
755 #else
756 # define D_NAMLEN(d) ((d)->d_namlen)
757 #endif /* ! (_POSIX_VERSION || USGr3) */
759 #if defined (USG) || defined (USGr3)
760 # define d_fileno d_ino
761 #endif
763 #if !defined (alloca)
764 extern char *alloca ();
765 #endif /* alloca */
767 /* Get the pathname of the current working directory,
768 and put it in SIZE bytes of BUF. Returns NULL if the
769 directory couldn't be determined or SIZE was too small.
770 If successful, returns BUF. In GNU, if BUF is NULL,
771 an array is allocated with `malloc'; the array is SIZE
772 bytes long, unless SIZE <= 0, in which case it is as
773 big as necessary. */
774 #if defined (__STDC__)
775 char *
776 getcwd (char *buf, size_t size)
777 #else /* !__STDC__ */
778 char *
779 getcwd (buf, size)
780 char *buf;
781 int size;
782 #endif /* !__STDC__ */
784 static CONST char dots[]
785 = "../../../../../../../../../../../../../../../../../../../../../../../\
786 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
787 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
788 CONST char *dotp, *dotlist;
789 size_t dotsize;
790 dev_t rootdev, thisdev;
791 ino_t rootino, thisino;
792 char path[PATH_MAX + 1];
793 register char *pathp;
794 char *pathbuf;
795 size_t pathsize;
796 struct stat st;
798 if (buf != NULL && size == 0)
800 errno = EINVAL;
801 return ((char *)NULL);
804 pathsize = sizeof (path);
805 pathp = &path[pathsize];
806 *--pathp = '\0';
807 pathbuf = path;
809 if (stat (".", &st) < 0)
810 return ((char *)NULL);
811 thisdev = st.st_dev;
812 thisino = st.st_ino;
814 if (stat ("/", &st) < 0)
815 return ((char *)NULL);
816 rootdev = st.st_dev;
817 rootino = st.st_ino;
819 dotsize = sizeof (dots) - 1;
820 dotp = &dots[sizeof (dots)];
821 dotlist = dots;
822 while (!(thisdev == rootdev && thisino == rootino))
824 register DIR *dirstream;
825 register struct dirent *d;
826 dev_t dotdev;
827 ino_t dotino;
828 char mount_point;
829 int namlen;
831 /* Look at the parent directory. */
832 if (dotp == dotlist)
834 /* My, what a deep directory tree you have, Grandma. */
835 char *new;
836 if (dotlist == dots)
838 new = malloc (dotsize * 2 + 1);
839 if (new == NULL)
840 goto lose;
841 memcpy (new, dots, dotsize);
843 else
845 new = realloc ((PTR) dotlist, dotsize * 2 + 1);
846 if (new == NULL)
847 goto lose;
849 memcpy (&new[dotsize], new, dotsize);
850 dotp = &new[dotsize];
851 dotsize *= 2;
852 new[dotsize] = '\0';
853 dotlist = new;
856 dotp -= 3;
858 /* Figure out if this directory is a mount point. */
859 if (stat (dotp, &st) < 0)
860 goto lose;
861 dotdev = st.st_dev;
862 dotino = st.st_ino;
863 mount_point = dotdev != thisdev;
865 /* Search for the last directory. */
866 dirstream = opendir(dotp);
867 if (dirstream == NULL)
868 goto lose;
869 while ((d = (struct dirent *)readdir(dirstream)) != NULL)
871 if (d->d_name[0] == '.' &&
872 (d->d_name[1] == '\0' ||
873 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
874 continue;
875 if (mount_point || d->d_fileno == thisino)
877 char *name;
879 namlen = D_NAMLEN(d);
880 name = (char *)
881 alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
882 memcpy (name, dotp, dotlist + dotsize - dotp);
883 name[dotlist + dotsize - dotp] = '/';
884 memcpy (&name[dotlist + dotsize - dotp + 1],
885 d->d_name, namlen + 1);
886 if (lstat (name, &st) < 0)
888 int save = errno;
889 closedir(dirstream);
890 errno = save;
891 goto lose;
893 if (st.st_dev == thisdev && st.st_ino == thisino)
894 break;
897 if (d == NULL)
899 int save = errno;
900 closedir(dirstream);
901 errno = save;
902 goto lose;
904 else
906 size_t space;
908 while ((space = pathp - pathbuf) <= namlen)
910 char *new;
912 if (pathbuf == path)
914 new = malloc (pathsize * 2);
915 if (!new)
916 goto lose;
918 else
920 new = realloc ((PTR) pathbuf, (pathsize * 2));
921 if (!new)
922 goto lose;
923 pathp = new + space;
925 (void) memcpy (new + pathsize + space, pathp, pathsize - space);
926 pathp = new + pathsize + space;
927 pathbuf = new;
928 pathsize *= 2;
931 pathp -= namlen;
932 (void) memcpy (pathp, d->d_name, namlen);
933 *--pathp = '/';
934 closedir(dirstream);
937 thisdev = dotdev;
938 thisino = dotino;
941 if (pathp == &path[sizeof(path) - 1])
942 *--pathp = '/';
944 if (dotlist != dots)
945 free ((PTR) dotlist);
948 size_t len = pathbuf + pathsize - pathp;
949 if (buf == NULL)
951 if (len < (size_t) size)
952 len = size;
953 buf = (char *) malloc (len);
954 if (buf == NULL)
955 goto lose2;
957 else if ((size_t) size < len)
959 errno = ERANGE;
960 goto lose2;
962 (void) memcpy((PTR) buf, (PTR) pathp, len);
965 if (pathbuf != path)
966 free (pathbuf);
968 return (buf);
970 lose:
971 if ((dotlist != dots) && dotlist)
973 int e = errno;
974 free ((PTR) dotlist);
975 errno = e;
978 lose2:
979 if ((pathbuf != path) && pathbuf)
981 int e = errno;
982 free ((PTR) pathbuf);
983 errno = e;
985 return ((char *)NULL);
987 #endif