xref: /openbsd-src/gnu/usr.bin/cvs/src/filesubr.c (revision 2286d8ed900f26153a3cd5227a124b1c0adce72f)
1 /* filesubr.c --- subroutines for dealing with files
2    Jim Blandy <jimb@cyclic.com>
3 
4    This file is part of GNU CVS.
5 
6    GNU CVS is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.  */
15 
16 /* These functions were moved out of subr.c because they need different
17    definitions under operating systems (like, say, Windows NT) with different
18    file system semantics.  */
19 
20 #include "cvs.h"
21 
22 static int deep_remove_dir PROTO((const char *path));
23 
24 /*
25  * Copies "from" to "to".
26  */
27 void
28 copy_file (from, to)
29     const char *from;
30     const char *to;
31 {
32     struct stat sb;
33     struct utimbuf t;
34     int fdin, fdout;
35 
36     if (trace)
37 #ifdef SERVER_SUPPORT
38 	(void) fprintf (stderr, "%c-> copy(%s,%s)\n",
39 			(server_active) ? 'S' : ' ', from, to);
40 #else
41 	(void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
42 #endif
43     if (noexec)
44 	return;
45 
46     if ((fdin = open (from, O_RDONLY)) < 0)
47 	error (1, errno, "cannot open %s for copying", from);
48     if (fstat (fdin, &sb) < 0)
49 	error (1, errno, "cannot fstat %s", from);
50     if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
51 	error (1, errno, "cannot create %s for copying", to);
52     if (sb.st_size > 0)
53     {
54 	char buf[BUFSIZ];
55 	int n;
56 
57 	for (;;)
58 	{
59 	    n = read (fdin, buf, sizeof(buf));
60 	    if (n == -1)
61 	    {
62 #ifdef EINTR
63 		if (errno == EINTR)
64 		    continue;
65 #endif
66 		error (1, errno, "cannot read file %s for copying", from);
67 	    }
68             else if (n == 0)
69 		break;
70 
71 	    if (write(fdout, buf, n) != n) {
72 		error (1, errno, "cannot write file %s for copying", to);
73 	    }
74 	}
75 
76 #ifdef HAVE_FSYNC
77 	if (fsync (fdout))
78 	    error (1, errno, "cannot fsync file %s after copying", to);
79 #endif
80     }
81 
82     if (close (fdin) < 0)
83 	error (0, errno, "cannot close %s", from);
84     if (close (fdout) < 0)
85 	error (1, errno, "cannot close %s", to);
86 
87     /* now, set the times for the copied file to match those of the original */
88     memset ((char *) &t, 0, sizeof (t));
89     t.actime = sb.st_atime;
90     t.modtime = sb.st_mtime;
91     (void) utime (to, &t);
92 }
93 
94 /* FIXME-krp: these functions would benefit from caching the char * &
95    stat buf.  */
96 
97 /*
98  * Returns non-zero if the argument file is a directory, or is a symbolic
99  * link which points to a directory.
100  */
101 int
102 isdir (file)
103     const char *file;
104 {
105     struct stat sb;
106 
107     if (stat (file, &sb) < 0)
108 	return (0);
109     return (S_ISDIR (sb.st_mode));
110 }
111 
112 /*
113  * Returns non-zero if the argument file is a symbolic link.
114  */
115 int
116 islink (file)
117     const char *file;
118 {
119 #ifdef S_ISLNK
120     struct stat sb;
121 
122     if (lstat (file, &sb) < 0)
123 	return (0);
124     return (S_ISLNK (sb.st_mode));
125 #else
126     return (0);
127 #endif
128 }
129 
130 /*
131  * Returns non-zero if the argument file exists.
132  */
133 int
134 isfile (file)
135     const char *file;
136 {
137     return isaccessible(file, F_OK);
138 }
139 
140 /*
141  * Returns non-zero if the argument file is readable.
142  */
143 int
144 isreadable (file)
145     const char *file;
146 {
147     return isaccessible(file, R_OK);
148 }
149 
150 /*
151  * Returns non-zero if the argument file is writable.
152  */
153 int
154 iswritable (file)
155     const char *file;
156 {
157     return isaccessible(file, W_OK);
158 }
159 
160 /*
161  * Returns non-zero if the argument file is accessable according to
162  * mode.  If compiled with SETXID_SUPPORT also works if cvs has setxid
163  * bits set.
164  */
165 int
166 isaccessible (file, mode)
167     const char *file;
168     const int mode;
169 {
170 #ifdef SETXID_SUPPORT
171     struct stat sb;
172     int umask = 0;
173     int gmask = 0;
174     int omask = 0;
175     int uid;
176 
177     if (stat(file, &sb) == -1)
178 	return 0;
179     if (mode == F_OK)
180 	return 1;
181 
182     uid = geteuid();
183     if (uid == 0)		/* superuser */
184     {
185 	if (mode & X_OK)
186 	    return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
187 	else
188 	    return 1;
189     }
190 
191     if (mode & R_OK)
192     {
193 	umask |= S_IRUSR;
194 	gmask |= S_IRGRP;
195 	omask |= S_IROTH;
196     }
197     if (mode & W_OK)
198     {
199 	umask |= S_IWUSR;
200 	gmask |= S_IWGRP;
201 	omask |= S_IWOTH;
202     }
203     if (mode & X_OK)
204     {
205 	umask |= S_IXUSR;
206 	gmask |= S_IXGRP;
207 	omask |= S_IXOTH;
208     }
209 
210     if (sb.st_uid == uid)
211 	return (sb.st_mode & umask) == umask;
212     else if (sb.st_gid == getegid())
213 	return (sb.st_mode & gmask) == gmask;
214     else
215 	return (sb.st_mode & omask) == omask;
216 #else
217     return access(file, mode) == 0;
218 #endif
219 }
220 
221 /*
222  * Open a file and die if it fails
223  */
224 FILE *
225 open_file (name, mode)
226     const char *name;
227     const char *mode;
228 {
229     FILE *fp;
230 
231     if ((fp = fopen (name, mode)) == NULL)
232 	error (1, errno, "cannot open %s", name);
233     return (fp);
234 }
235 
236 /*
237  * Make a directory and die if it fails
238  */
239 void
240 make_directory (name)
241     const char *name;
242 {
243     struct stat sb;
244 
245     if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
246 	    error (0, 0, "%s already exists but is not a directory", name);
247     if (!noexec && mkdir (name, 0777) < 0)
248 	error (1, errno, "cannot make directory %s", name);
249 }
250 
251 /*
252  * Make a path to the argument directory, printing a message if something
253  * goes wrong.
254  */
255 void
256 make_directories (name)
257     const char *name;
258 {
259     char *cp;
260 
261     if (noexec)
262 	return;
263 
264     if (mkdir (name, 0777) == 0 || errno == EEXIST)
265 	return;
266     if (! existence_error (errno))
267     {
268 	error (0, errno, "cannot make path to %s", name);
269 	return;
270     }
271     if ((cp = strrchr (name, '/')) == NULL)
272 	return;
273     *cp = '\0';
274     make_directories (name);
275     *cp++ = '/';
276     if (*cp == '\0')
277 	return;
278     (void) mkdir (name, 0777);
279 }
280 
281 /* Create directory NAME if it does not already exist; fatal error for
282    other errors.  Returns 0 if directory was created; 1 if it already
283    existed.  */
284 int
285 mkdir_if_needed (name)
286     char *name;
287 {
288     if (mkdir (name, 0777) < 0)
289     {
290 	if (!(errno == EEXIST
291 	      || (errno == EACCES && isdir (name))))
292 	    error (1, errno, "cannot make directory %s", name);
293 	return 1;
294     }
295     return 0;
296 }
297 
298 /*
299  * Change the mode of a file, either adding write permissions, or removing
300  * all write permissions.  Either change honors the current umask setting.
301  */
302 void
303 xchmod (fname, writable)
304     char *fname;
305     int writable;
306 {
307     struct stat sb;
308     mode_t mode, oumask;
309 
310     if (stat (fname, &sb) < 0)
311     {
312 	if (!noexec)
313 	    error (0, errno, "cannot stat %s", fname);
314 	return;
315     }
316     oumask = umask (0);
317     (void) umask (oumask);
318     if (writable)
319     {
320 	mode = sb.st_mode | (~oumask
321 			     & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
322 				| ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
323 				| ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
324     }
325     else
326     {
327 	mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
328     }
329 
330     if (trace)
331 #ifdef SERVER_SUPPORT
332 	(void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
333 			(server_active) ? 'S' : ' ', fname,
334 			(unsigned int) mode);
335 #else
336 	(void) fprintf (stderr, "-> chmod(%s,%o)\n", fname,
337 			(unsigned int) mode);
338 #endif
339     if (noexec)
340 	return;
341 
342     if (chmod (fname, mode) < 0)
343 	error (0, errno, "cannot change mode of file %s", fname);
344 }
345 
346 /*
347  * Rename a file and die if it fails
348  */
349 void
350 rename_file (from, to)
351     const char *from;
352     const char *to;
353 {
354     if (trace)
355 #ifdef SERVER_SUPPORT
356 	(void) fprintf (stderr, "%c-> rename(%s,%s)\n",
357 			(server_active) ? 'S' : ' ', from, to);
358 #else
359 	(void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
360 #endif
361     if (noexec)
362 	return;
363 
364     if (rename (from, to) < 0)
365 	error (1, errno, "cannot rename file %s to %s", from, to);
366 }
367 
368 /*
369  * link a file, if possible.  Warning: the Windows NT version of this
370  * function just copies the file, so only use this function in ways
371  * that can deal with either a link or a copy.
372  */
373 int
374 link_file (from, to)
375     const char *from;
376     const char *to;
377 {
378     if (trace)
379 #ifdef SERVER_SUPPORT
380 	(void) fprintf (stderr, "%c-> link(%s,%s)\n",
381 			(server_active) ? 'S' : ' ', from, to);
382 #else
383 	(void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
384 #endif
385     if (noexec)
386 	return (0);
387 
388     return (link (from, to));
389 }
390 
391 /*
392  * unlink a file, if possible.
393  */
394 int
395 unlink_file (f)
396     const char *f;
397 {
398     if (trace)
399 #ifdef SERVER_SUPPORT
400 	(void) fprintf (stderr, "%c-> unlink(%s)\n",
401 			(server_active) ? 'S' : ' ', f);
402 #else
403 	(void) fprintf (stderr, "-> unlink(%s)\n", f);
404 #endif
405     if (noexec)
406 	return (0);
407 
408     return (unlink (f));
409 }
410 
411 /*
412  * Unlink a file or dir, if possible.  If it is a directory do a deep
413  * removal of all of the files in the directory.  Return -1 on error
414  * (in which case errno is set).
415  */
416 int
417 unlink_file_dir (f)
418     const char *f;
419 {
420     if (trace
421 #ifdef SERVER_SUPPORT
422 	/* This is called by the server parent process in contexts where
423 	   it is not OK to send output (e.g. after we sent "ok" to the
424 	   client).  */
425 	&& !server_active
426 #endif
427 	)
428 	(void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
429 
430     if (noexec)
431 	return (0);
432 
433     /* For at least some unices, if root tries to unlink() a directory,
434        instead of doing something rational like returning EISDIR,
435        the system will gleefully go ahead and corrupt the filesystem.
436        So we first call isdir() to see if it is OK to call unlink().  This
437        doesn't quite work--if someone creates a directory between the
438        call to isdir() and the call to unlink(), we'll still corrupt
439        the filesystem.  Where is the Unix Haters Handbook when you need
440        it?  */
441     if (isdir(f))
442 	return deep_remove_dir(f);
443     else
444     {
445 	if (unlink (f) != 0)
446 	    return -1;
447     }
448     /* We were able to remove the file from the disk */
449     return 0;
450 }
451 
452 /* Remove a directory and everything it contains.  Returns 0 for
453  * success, -1 for failure (in which case errno is set).
454  */
455 
456 static int
457 deep_remove_dir (path)
458     const char *path;
459 {
460     DIR		  *dirp;
461     struct dirent *dp;
462 
463     if (rmdir (path) != 0)
464     {
465 	if (errno == ENOTEMPTY
466 	    || errno == EEXIST
467 	    /* Ugly workaround for ugly AIX 4.1 (and 3.2) header bug
468 	       (it defines ENOTEMPTY and EEXIST to 17 but actually
469 	       returns 87).  */
470 	    || (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87))
471 	{
472 	    if ((dirp = opendir (path)) == NULL)
473 		/* If unable to open the directory return
474 		 * an error
475 		 */
476 		return -1;
477 
478 	    while ((dp = readdir (dirp)) != NULL)
479 	    {
480 		char *buf;
481 
482 		if (strcmp (dp->d_name, ".") == 0 ||
483 			    strcmp (dp->d_name, "..") == 0)
484 		    continue;
485 
486 		buf = xmalloc (strlen (path) + strlen (dp->d_name) + 5);
487 		sprintf (buf, "%s/%s", path, dp->d_name);
488 
489 		/* See comment in unlink_file_dir explanation of why we use
490 		   isdir instead of just calling unlink and checking the
491 		   status.  */
492 		if (isdir(buf))
493 		{
494 		    if (deep_remove_dir(buf))
495 		    {
496 			closedir(dirp);
497 			free (buf);
498 			return -1;
499 		    }
500 		}
501 		else
502 		{
503 		    if (unlink (buf) != 0)
504 		    {
505 			closedir(dirp);
506 			free (buf);
507 			return -1;
508 		    }
509 		}
510 		free (buf);
511 	    }
512 	    closedir (dirp);
513 	    return rmdir (path);
514 	}
515 	else
516 	    return -1;
517     }
518 
519     /* Was able to remove the directory return 0 */
520     return 0;
521 }
522 
523 /* Read NCHARS bytes from descriptor FD into BUF.
524    Return the number of characters successfully read.
525    The number returned is always NCHARS unless end-of-file or error.  */
526 static size_t
527 block_read (fd, buf, nchars)
528     int fd;
529     char *buf;
530     size_t nchars;
531 {
532     char *bp = buf;
533     size_t nread;
534 
535     do
536     {
537 	nread = read (fd, bp, nchars);
538 	if (nread == (size_t)-1)
539 	{
540 #ifdef EINTR
541 	    if (errno == EINTR)
542 		continue;
543 #endif
544 	    return (size_t)-1;
545 	}
546 
547 	if (nread == 0)
548 	    break;
549 
550 	bp += nread;
551 	nchars -= nread;
552     } while (nchars != 0);
553 
554     return bp - buf;
555 }
556 
557 
558 /*
559  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
560  */
561 int
562 xcmp (file1, file2)
563     const char *file1;
564     const char *file2;
565 {
566     char *buf1, *buf2;
567     struct stat sb1, sb2;
568     int fd1, fd2;
569     int ret;
570 
571     if ((fd1 = open (file1, O_RDONLY)) < 0)
572 	error (1, errno, "cannot open file %s for comparing", file1);
573     if ((fd2 = open (file2, O_RDONLY)) < 0)
574 	error (1, errno, "cannot open file %s for comparing", file2);
575     if (fstat (fd1, &sb1) < 0)
576 	error (1, errno, "cannot fstat %s", file1);
577     if (fstat (fd2, &sb2) < 0)
578 	error (1, errno, "cannot fstat %s", file2);
579 
580     /* A generic file compare routine might compare st_dev & st_ino here
581        to see if the two files being compared are actually the same file.
582        But that won't happen in CVS, so we won't bother. */
583 
584     if (sb1.st_size != sb2.st_size)
585 	ret = 1;
586     else if (sb1.st_size == 0)
587 	ret = 0;
588     else
589     {
590 	/* FIXME: compute the optimal buffer size by computing the least
591 	   common multiple of the files st_blocks field */
592 	size_t buf_size = 8 * 1024;
593 	size_t read1;
594 	size_t read2;
595 
596 	buf1 = xmalloc (buf_size);
597 	buf2 = xmalloc (buf_size);
598 
599 	do
600 	{
601 	    read1 = block_read (fd1, buf1, buf_size);
602 	    if (read1 == (size_t)-1)
603 		error (1, errno, "cannot read file %s for comparing", file1);
604 
605 	    read2 = block_read (fd2, buf2, buf_size);
606 	    if (read2 == (size_t)-1)
607 		error (1, errno, "cannot read file %s for comparing", file2);
608 
609 	    /* assert (read1 == read2); */
610 
611 	    ret = memcmp(buf1, buf2, read1);
612 	} while (ret == 0 && read1 == buf_size);
613 
614 	free (buf1);
615 	free (buf2);
616     }
617 
618     (void) close (fd1);
619     (void) close (fd2);
620     return (ret);
621 }
622 
623 /* Generate a unique temporary filename.  Returns a pointer to a newly
624    malloc'd string containing the name.  Returns successfully or not at
625    all.  */
626 /* There are at least three functions for generating temporary
627    filenames.  We use tempnam (SVID 3) if possible, else mktemp (BSD
628    4.3), and as last resort tmpnam (POSIX). Reason is that tempnam and
629    mktemp both allow to specify the directory in which the temporary
630    file will be created.  */
631 #ifdef HAVE_TEMPNAM
632 char *
633 cvs_temp_name ()
634 {
635     char *retval;
636 
637     retval = tempnam (Tmpdir, "cvs");
638     if (retval == NULL)
639 	error (1, errno, "cannot generate temporary filename");
640     /* tempnam returns a pointer to a newly malloc'd string, so there's
641        no need for a xstrdup  */
642     return retval;
643 }
644 #else
645 char *
646 cvs_temp_name ()
647 {
648 #  ifdef HAVE_MKTEMP
649     char *value;
650     char *retval;
651 
652     value = xmalloc (strlen (Tmpdir) + 40);
653     sprintf (value, "%s/%s", Tmpdir, "cvsXXXXXX" );
654     retval = mktemp (value);
655 
656     if (retval == NULL)
657 	error (1, errno, "cannot generate temporary filename");
658     return value;
659 #  else
660     char value[L_tmpnam + 1];
661     char *retval;
662 
663     retval = tmpnam (value);
664     if (retval == NULL)
665 	error (1, errno, "cannot generate temporary filename");
666     return xstrdup (value);
667 #  endif
668 }
669 #endif
670 
671 /* Return non-zero iff FILENAME is absolute.
672    Trivial under Unix, but more complicated under other systems.  */
673 int
674 isabsolute (filename)
675     const char *filename;
676 {
677     return filename[0] == '/';
678 }
679 
680 
681 /* Return a pointer into PATH's last component.  */
682 char *
683 last_component (path)
684     char *path;
685 {
686     char *last = strrchr (path, '/');
687 
688     if (last)
689         return last + 1;
690     else
691         return path;
692 }
693 
694 /* Return the home directory.  Returns a pointer to storage
695    managed by this function or its callees (currently getenv).
696    This function will return the same thing every time it is
697    called.  Returns NULL if there is no home directory.
698 
699    Note that for a pserver server, this may return root's home
700    directory.  What typically happens is that upon being started from
701    inetd, before switching users, the code in cvsrc.c calls
702    get_homedir which remembers root's home directory in the static
703    variable.  Then the switch happens and get_homedir might return a
704    directory that we don't even have read or execute permissions for
705    (which is bad, when various parts of CVS try to read there).  One
706    fix would be to make the value returned by get_homedir only good
707    until the next call (which would free the old value).  Another fix
708    would be to just always malloc our answer, and let the caller free
709    it (that is best, because some day we may need to be reentrant).
710 
711    The workaround is to put -f in inetd.conf which means that
712    get_homedir won't get called until after the switch in user ID.
713 
714    The whole concept of a "home directory" on the server is pretty
715    iffy, although I suppose some people probably are relying on it for
716    .cvsrc and such, in the cases where it works.  */
717 char *
718 get_homedir ()
719 {
720     static char *home = NULL;
721     char *env = getenv ("HOME");
722     struct passwd *pw;
723 
724     if (home != NULL)
725 	return home;
726 
727     if (env)
728 	home = env;
729     else if ((pw = (struct passwd *) getpwuid (getuid ()))
730 	     && pw->pw_dir)
731 	home = xstrdup (pw->pw_dir);
732     else
733 	return 0;
734 
735     return home;
736 }
737 
738 /* See cvs.h for description.  On unix this does nothing, because the
739    shell expands the wildcards.  */
740 void
741 expand_wild (argc, argv, pargc, pargv)
742     int argc;
743     char **argv;
744     int *pargc;
745     char ***pargv;
746 {
747     int i;
748     *pargc = argc;
749     *pargv = (char **) xmalloc (argc * sizeof (char *));
750     for (i = 0; i < argc; ++i)
751 	(*pargv)[i] = xstrdup (argv[i]);
752 }
753 
754 #ifdef SERVER_SUPPORT
755 /* Case-insensitive string compare.  I know that some systems
756    have such a routine, but I'm not sure I see any reasons for
757    dealing with the hair of figuring out whether they do (I haven't
758    looked into whether this is a performance bottleneck; I would guess
759    not).  */
760 int
761 cvs_casecmp (str1, str2)
762     char *str1;
763     char *str2;
764 {
765     char *p;
766     char *q;
767     int pqdiff;
768 
769     p = str1;
770     q = str2;
771     while ((pqdiff = tolower (*p) - tolower (*q)) == 0)
772     {
773 	if (*p == '\0')
774 	    return 0;
775 	++p;
776 	++q;
777     }
778     return pqdiff;
779 }
780 
781 /* Case-insensitive file open.  As you can see, this is an expensive
782    call.  We don't regard it as our main strategy for dealing with
783    case-insensitivity.  Returns errno code or 0 for success.  Puts the
784    new file in *FP.  NAME and MODE are as for fopen.  If PATHP is not
785    NULL, then put a malloc'd string containing the pathname as found
786    into *PATHP.  *PATHP is only set if the return value is 0.
787 
788    Might be cleaner to separate the file finding (which just gives
789    *PATHP) from the file opening (which the caller can do).  For one
790    thing, might make it easier to know whether to put NAME or *PATHP
791    into error messages.  */
792 int
793 fopen_case (name, mode, fp, pathp)
794     char *name;
795     char *mode;
796     FILE **fp;
797     char **pathp;
798 {
799     struct dirent *dp;
800     DIR *dirp;
801     char *dir;
802     char *fname;
803     char *found_name;
804     int retval;
805 
806     /* Separate NAME into directory DIR and filename within the directory
807        FNAME.  */
808     dir = xstrdup (name);
809     fname = strrchr (dir, '/');
810     if (fname == NULL)
811 	error (1, 0, "internal error: relative pathname in fopen_case");
812     *fname++ = '\0';
813 
814     found_name = NULL;
815     dirp = CVS_OPENDIR (dir);
816     if (dirp == NULL)
817     {
818 	if (existence_error (errno))
819 	{
820 	    /* This can happen if we are looking in the Attic and the Attic
821 	       directory does not exist.  Return the error to the caller;
822 	       they know what to do with it.  */
823 	    retval = errno;
824 	    goto out;
825 	}
826 	else
827 	{
828 	    /* Give a fatal error; that way the error message can be
829 	       more specific than if we returned the error to the caller.  */
830 	    error (1, errno, "cannot read directory %s", dir);
831 	}
832     }
833     errno = 0;
834     while ((dp = readdir (dirp)) != NULL)
835     {
836 	if (cvs_casecmp (dp->d_name, fname) == 0)
837 	{
838 	    if (found_name != NULL)
839 		error (1, 0, "%s is ambiguous; could mean %s or %s",
840 		       fname, dp->d_name, found_name);
841 	    found_name = xstrdup (dp->d_name);
842 	}
843     }
844     if (errno != 0)
845 	error (1, errno, "cannot read directory %s", dir);
846     closedir (dirp);
847 
848     if (found_name == NULL)
849     {
850 	*fp = NULL;
851 	retval = ENOENT;
852     }
853     else
854     {
855 	char *p;
856 
857 	/* Copy the found name back into DIR.  We are assuming that
858 	   found_name is the same length as fname, which is true as
859 	   long as the above code is just ignoring case and not other
860 	   aspects of filename syntax.  */
861 	p = dir + strlen (dir);
862 	*p++ = '/';
863 	strcpy (p, found_name);
864 	*fp = fopen (dir, mode);
865 	if (*fp == NULL)
866 	    retval = errno;
867 	else
868 	    retval = 0;
869     }
870 
871     if (pathp == NULL)
872 	free (dir);
873     else if (retval != 0)
874 	free (dir);
875     else
876 	*pathp = dir;
877     free (found_name);
878  out:
879     return retval;
880 }
881 #endif /* SERVER_SUPPORT */
882