Home | History | Annotate | Line # | Download | only in patch
util.c revision 1.22.12.1
      1  1.22.12.1      matt /*	$NetBSD: util.c,v 1.22.12.1 2007/11/06 23:36:10 matt Exp $	*/
      2       1.16    itojun 
      3       1.16    itojun /*
      4       1.16    itojun  * Copyright (c) 1988, Larry Wall
      5       1.16    itojun  *
      6       1.16    itojun  * Redistribution and use in source and binary forms, with or without
      7       1.16    itojun  * modification, are permitted provided that the following condition
      8       1.16    itojun  * is met:
      9       1.16    itojun  *  1. Redistributions of source code must retain the above copyright
     10       1.16    itojun  *     notice, this condition and the following disclaimer.
     11       1.16    itojun  *
     12       1.16    itojun  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     13       1.16    itojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     14       1.16    itojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     15       1.16    itojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     16       1.16    itojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     17       1.16    itojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     18       1.16    itojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     19       1.16    itojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     20       1.16    itojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     21       1.16    itojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     22       1.16    itojun  * SUCH DAMAGE.
     23       1.16    itojun  */
     24       1.16    itojun 
     25        1.5  christos #include <sys/cdefs.h>
     26        1.2   mycroft #ifndef lint
     27  1.22.12.1      matt __RCSID("$NetBSD: util.c,v 1.22.12.1 2007/11/06 23:36:10 matt Exp $");
     28        1.2   mycroft #endif /* not lint */
     29        1.2   mycroft 
     30       1.12  kristerw #include <sys/param.h>
     31       1.12  kristerw 
     32        1.1       cgd #include "EXTERN.h"
     33        1.1       cgd #include "common.h"
     34        1.1       cgd #include "INTERN.h"
     35        1.1       cgd #include "util.h"
     36        1.1       cgd #include "backupfile.h"
     37       1.10  kristerw 
     38        1.5  christos #include <stdarg.h>
     39        1.5  christos #include <stdlib.h>
     40        1.5  christos #include <unistd.h>
     41        1.5  christos #include <fcntl.h>
     42        1.1       cgd 
     43       1.11  kristerw /*
     44       1.11  kristerw  * Rename a file, copying it if necessary.
     45       1.11  kristerw  */
     46        1.1       cgd int
     47        1.9  kristerw move_file(char *from, char *to)
     48        1.1       cgd {
     49       1.12  kristerw 	char bakname[MAXPATHLEN];
     50       1.11  kristerw 	char *s;
     51       1.22  christos 	ssize_t i;
     52       1.11  kristerw 	int fromfd;
     53        1.1       cgd 
     54       1.21       skd 	if ( check_only == TRUE )
     55       1.21       skd 		return(0);
     56       1.21       skd 
     57       1.11  kristerw 	/* to stdout? */
     58        1.1       cgd 
     59       1.11  kristerw 	if (strEQ(to, "-")) {
     60        1.1       cgd #ifdef DEBUGGING
     61       1.11  kristerw 		if (debug & 4)
     62       1.11  kristerw 			say("Moving %s to stdout.\n", from);
     63        1.1       cgd #endif
     64       1.11  kristerw 		fromfd = open(from, 0);
     65       1.11  kristerw 		if (fromfd < 0)
     66       1.11  kristerw 			pfatal("internal error, can't reopen %s", from);
     67       1.11  kristerw 		while ((i = read(fromfd, buf, sizeof buf)) > 0)
     68       1.11  kristerw 			if (write(1, buf, i) != 1)
     69       1.11  kristerw 				pfatal("write failed");
     70       1.11  kristerw 		Close(fromfd);
     71       1.11  kristerw 		return 0;
     72       1.11  kristerw 	}
     73        1.1       cgd 
     74       1.11  kristerw 	if (origprae) {
     75       1.18    itojun 		strlcpy(bakname, origprae, sizeof(bakname));
     76       1.18    itojun 		strlcat(bakname, to, sizeof(bakname));
     77       1.11  kristerw 	} else {
     78        1.1       cgd #ifndef NODIR
     79       1.11  kristerw 		char *backupname = find_backup_file_name(to);
     80       1.18    itojun 		strlcpy(bakname, backupname, sizeof(bakname));
     81       1.11  kristerw 		free(backupname);
     82        1.1       cgd #else /* NODIR */
     83       1.18    itojun 		strlcpy(bakname, to, sizeof(bakname));
     84       1.18    itojun     		strlcat(bakname, simple_backup_suffix, sizeof(bakname));
     85        1.1       cgd #endif /* NODIR */
     86       1.11  kristerw 	}
     87        1.1       cgd 
     88       1.11  kristerw 	if (stat(to, &filestat) == 0) {	/* output file exists */
     89       1.11  kristerw 		dev_t to_device = filestat.st_dev;
     90       1.11  kristerw 		ino_t to_inode  = filestat.st_ino;
     91       1.11  kristerw 		char *simplename = bakname;
     92        1.1       cgd 
     93       1.11  kristerw 		for (s = bakname; *s; s++) {
     94       1.11  kristerw 			if (*s == '/')
     95       1.11  kristerw 				simplename = s + 1;
     96       1.11  kristerw 		}
     97       1.11  kristerw 		/*
     98       1.11  kristerw 		 * Find a backup name that is not the same file.
     99       1.11  kristerw 		 * Change the first lowercase char into uppercase;
    100       1.11  kristerw 		 * if that isn't sufficient, chop off the first char
    101       1.11  kristerw 		 * and try again.
    102       1.11  kristerw 		 */
    103       1.11  kristerw 		while (stat(bakname, &filestat) == 0 &&
    104       1.11  kristerw 		       to_device == filestat.st_dev &&
    105       1.11  kristerw 		       to_inode == filestat.st_ino) {
    106       1.11  kristerw 			/* Skip initial non-lowercase chars. */
    107       1.11  kristerw 			for (s = simplename;
    108       1.20       dsl 			     *s && *s == toupper((unsigned char)*s);
    109       1.11  kristerw 			     s++)
    110       1.11  kristerw 				;
    111       1.11  kristerw 			if (*s)
    112       1.20       dsl 				*s = toupper((unsigned char)*s);
    113       1.11  kristerw 			else
    114       1.19    itojun 				strcpy(simplename, simplename + 1);
    115       1.11  kristerw 		}
    116       1.11  kristerw 		while (unlink(bakname) >= 0)
    117       1.11  kristerw 			;	/* while() is for benefit of Eunice */
    118       1.11  kristerw #ifdef DEBUGGING
    119       1.11  kristerw 		if (debug & 4)
    120       1.11  kristerw 			say("Moving %s to %s.\n", to, bakname);
    121       1.11  kristerw #endif
    122       1.11  kristerw 		if (link(to, bakname) < 0) {
    123       1.11  kristerw 			/*
    124       1.11  kristerw 			 * Maybe `to' is a symlink into a different file
    125       1.11  kristerw 			 * system. Copying replaces the symlink with a file;
    126       1.11  kristerw 			 * using rename would be better.
    127       1.11  kristerw 			 */
    128       1.11  kristerw 			int tofd;
    129       1.11  kristerw 			int bakfd;
    130       1.11  kristerw 
    131       1.11  kristerw 			bakfd = creat(bakname, 0666);
    132       1.11  kristerw 			if (bakfd < 0) {
    133       1.11  kristerw 				say("Can't backup %s, output is in %s: %s\n",
    134       1.11  kristerw 				    to, from, strerror(errno));
    135       1.11  kristerw 				return -1;
    136       1.11  kristerw 			}
    137       1.11  kristerw 			tofd = open(to, 0);
    138       1.11  kristerw 			if (tofd < 0)
    139       1.11  kristerw 				pfatal("internal error, can't open %s", to);
    140       1.11  kristerw 			while ((i = read(tofd, buf, sizeof buf)) > 0)
    141       1.11  kristerw 				if (write(bakfd, buf, i) != i)
    142       1.11  kristerw 					pfatal("write failed");
    143       1.11  kristerw 			Close(tofd);
    144       1.11  kristerw 			Close(bakfd);
    145       1.11  kristerw 		}
    146       1.11  kristerw 		while (unlink(to) >= 0) ;
    147        1.1       cgd 	}
    148        1.1       cgd #ifdef DEBUGGING
    149        1.1       cgd 	if (debug & 4)
    150       1.11  kristerw 		say("Moving %s to %s.\n", from, to);
    151        1.1       cgd #endif
    152       1.11  kristerw 	if (link(from, to) < 0) {		/* different file system? */
    153       1.11  kristerw 		int tofd;
    154       1.11  kristerw 
    155       1.11  kristerw 		tofd = creat(to, 0666);
    156       1.11  kristerw 		if (tofd < 0) {
    157       1.11  kristerw 			say("Can't create %s, output is in %s: %s\n",
    158       1.11  kristerw 			    to, from, strerror(errno));
    159       1.11  kristerw 			return -1;
    160       1.11  kristerw 		}
    161       1.11  kristerw 		fromfd = open(from, 0);
    162       1.11  kristerw 		if (fromfd < 0)
    163       1.11  kristerw 			pfatal("internal error, can't reopen %s", from);
    164       1.11  kristerw 		while ((i = read(fromfd, buf, sizeof buf)) > 0)
    165       1.11  kristerw 			if (write(tofd, buf, i) != i)
    166       1.11  kristerw 				pfatal("write failed");
    167       1.11  kristerw 		Close(fromfd);
    168       1.11  kristerw 		Close(tofd);
    169        1.1       cgd 	}
    170       1.11  kristerw 	Unlink(from);
    171       1.11  kristerw 	return 0;
    172       1.11  kristerw }
    173       1.11  kristerw 
    174       1.11  kristerw /*
    175       1.11  kristerw  * Copy a file.
    176       1.11  kristerw  */
    177       1.11  kristerw void
    178       1.11  kristerw copy_file(char *from, char *to)
    179       1.11  kristerw {
    180        1.9  kristerw 	int tofd;
    181       1.11  kristerw 	int fromfd;
    182       1.14  kristerw 	size_t i;
    183       1.11  kristerw 
    184        1.1       cgd 	tofd = creat(to, 0666);
    185       1.11  kristerw 	if (tofd < 0)
    186       1.11  kristerw 		pfatal("can't create %s", to);
    187        1.1       cgd 	fromfd = open(from, 0);
    188        1.1       cgd 	if (fromfd < 0)
    189       1.11  kristerw 		pfatal("internal error, can't reopen %s", from);
    190       1.11  kristerw 	while ((i = read(fromfd, buf, sizeof buf)) > 0)
    191       1.11  kristerw 		if (write(tofd, buf, i) != i)
    192       1.11  kristerw 			pfatal("write to %s failed", to);
    193        1.1       cgd 	Close(fromfd);
    194        1.1       cgd 	Close(tofd);
    195        1.1       cgd }
    196        1.1       cgd 
    197       1.11  kristerw /*
    198       1.12  kristerw  * malloc with result test.
    199       1.12  kristerw  */
    200       1.12  kristerw void *
    201       1.12  kristerw xmalloc(size_t size)
    202       1.12  kristerw {
    203       1.12  kristerw 	void *p;
    204       1.12  kristerw 
    205       1.12  kristerw 	if ((p = malloc(size)) == NULL)
    206       1.12  kristerw 		fatal("out of memory\n");
    207       1.12  kristerw 	return p;
    208       1.12  kristerw }
    209       1.12  kristerw 
    210       1.12  kristerw /*
    211       1.15  kristerw  * realloc with result test.
    212       1.12  kristerw  */
    213       1.15  kristerw void *
    214       1.15  kristerw xrealloc(void *ptr, size_t size)
    215       1.12  kristerw {
    216       1.15  kristerw 	void *p;
    217       1.12  kristerw 
    218       1.15  kristerw 	if ((p = realloc(ptr, size)) == NULL)
    219       1.12  kristerw 		fatal("out of memory\n");
    220       1.12  kristerw 	return p;
    221       1.12  kristerw }
    222       1.12  kristerw 
    223       1.12  kristerw /*
    224       1.15  kristerw  * strdup with result test.
    225       1.11  kristerw  */
    226        1.1       cgd char *
    227       1.15  kristerw xstrdup(const char *s)
    228        1.1       cgd {
    229       1.15  kristerw 	char *p;
    230        1.1       cgd 
    231       1.15  kristerw 	if ((p = strdup(s)) == NULL)
    232       1.15  kristerw 		fatal("out of memory\n");
    233       1.15  kristerw 	return p;
    234        1.1       cgd }
    235        1.1       cgd 
    236       1.11  kristerw /*
    237       1.12  kristerw  * Vanilla terminal output.
    238       1.11  kristerw  */
    239        1.1       cgd void
    240        1.5  christos say(const char *pat, ...)
    241        1.1       cgd {
    242       1.11  kristerw 	va_list ap;
    243       1.11  kristerw 	va_start(ap, pat);
    244        1.5  christos 
    245       1.11  kristerw 	vfprintf(stderr, pat, ap);
    246       1.11  kristerw 	va_end(ap);
    247       1.11  kristerw 	Fflush(stderr);
    248        1.1       cgd }
    249        1.1       cgd 
    250       1.11  kristerw /*
    251       1.11  kristerw  * Terminal output, pun intended.
    252       1.11  kristerw  */
    253        1.1       cgd void				/* very void */
    254        1.5  christos fatal(const char *pat, ...)
    255        1.1       cgd {
    256       1.11  kristerw 	va_list ap;
    257       1.11  kristerw 	va_start(ap, pat);
    258        1.5  christos 
    259       1.11  kristerw 	fprintf(stderr, "patch: **** ");
    260       1.11  kristerw 	vfprintf(stderr, pat, ap);
    261       1.11  kristerw 	va_end(ap);
    262       1.11  kristerw 	my_exit(1);
    263        1.1       cgd }
    264        1.1       cgd 
    265       1.11  kristerw /*
    266       1.11  kristerw  * Say something from patch, something from the system, then silence...
    267       1.11  kristerw  */
    268        1.1       cgd void				/* very void */
    269        1.5  christos pfatal(const char *pat, ...)
    270        1.1       cgd {
    271       1.11  kristerw 	va_list ap;
    272       1.11  kristerw 	int errnum = errno;
    273       1.11  kristerw 	va_start(ap, pat);
    274        1.5  christos 
    275       1.11  kristerw 	fprintf(stderr, "patch: **** ");
    276       1.11  kristerw 	vfprintf(stderr, pat, ap);
    277       1.11  kristerw 	fprintf(stderr, ": %s\n", strerror(errnum));
    278       1.11  kristerw 	va_end(ap);
    279       1.11  kristerw 	my_exit(1);
    280        1.1       cgd }
    281        1.1       cgd 
    282       1.11  kristerw /*
    283       1.11  kristerw  * Get a response from the user, somehow or other.
    284       1.11  kristerw  */
    285        1.1       cgd void
    286        1.5  christos ask(const char *pat, ...)
    287        1.1       cgd {
    288       1.11  kristerw 	int ttyfd;
    289       1.11  kristerw 	int r;
    290       1.11  kristerw 	bool tty2 = isatty(2);
    291       1.11  kristerw 	va_list ap;
    292       1.11  kristerw 	va_start(ap, pat);
    293       1.11  kristerw 
    294       1.11  kristerw 	(void)vsprintf(buf, pat, ap);
    295       1.11  kristerw 	va_end(ap);
    296       1.11  kristerw 	Fflush(stderr);
    297       1.11  kristerw 	write(2, buf, strlen(buf));
    298       1.11  kristerw 	if (tty2) {			/* might be redirected to a file */
    299       1.11  kristerw 		r = read(2, buf, sizeof buf);
    300       1.11  kristerw 	} else if (isatty(1)) {		/* this may be new file output */
    301       1.11  kristerw 		Fflush(stdout);
    302       1.11  kristerw 		write(1, buf, strlen(buf));
    303       1.11  kristerw 		r = read(1, buf, sizeof buf);
    304       1.11  kristerw 	} else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
    305       1.13       wiz 					/* might be deleted or unwritable */
    306       1.11  kristerw 		write(ttyfd, buf, strlen(buf));
    307       1.11  kristerw 		r = read(ttyfd, buf, sizeof buf);
    308       1.11  kristerw 		Close(ttyfd);
    309       1.11  kristerw 	} else if (isatty(0)) {		/* this is probably patch input */
    310       1.11  kristerw 		Fflush(stdin);
    311       1.11  kristerw 		write(0, buf, strlen(buf));
    312       1.11  kristerw 		r = read(0, buf, sizeof buf);
    313       1.11  kristerw 	} else {			/* no terminal at all--default it */
    314       1.11  kristerw 		buf[0] = '\n';
    315       1.11  kristerw 		r = 1;
    316       1.11  kristerw 	}
    317       1.11  kristerw 	if (r <= 0)
    318       1.11  kristerw 		buf[0] = 0;
    319       1.11  kristerw 	else
    320       1.11  kristerw 		buf[r] = '\0';
    321       1.11  kristerw 	if (!tty2)
    322       1.11  kristerw 		say("%s", buf);
    323        1.1       cgd }
    324        1.1       cgd 
    325       1.11  kristerw /*
    326       1.11  kristerw  * How to handle certain events when not in a critical region.
    327       1.11  kristerw  */
    328        1.1       cgd void
    329        1.9  kristerw set_signals(int reset)
    330        1.1       cgd {
    331       1.11  kristerw 	static void (*hupval)(int);
    332       1.11  kristerw 	static void (*intval)(int);
    333        1.1       cgd 
    334       1.11  kristerw 	if (!reset) {
    335       1.11  kristerw 		hupval = signal(SIGHUP, SIG_IGN);
    336       1.11  kristerw 		if (hupval != SIG_IGN)
    337  1.22.12.1      matt 			hupval = my_sig_exit;
    338       1.11  kristerw 		intval = signal(SIGINT, SIG_IGN);
    339       1.11  kristerw 		if (intval != SIG_IGN)
    340  1.22.12.1      matt 			intval = my_sig_exit;
    341       1.11  kristerw 	}
    342       1.11  kristerw 	Signal(SIGHUP, hupval);
    343       1.11  kristerw 	Signal(SIGINT, intval);
    344        1.1       cgd }
    345        1.1       cgd 
    346       1.11  kristerw /*
    347       1.11  kristerw  * How to handle certain events when in a critical region.
    348       1.11  kristerw  */
    349        1.1       cgd void
    350        1.1       cgd ignore_signals()
    351        1.1       cgd {
    352       1.11  kristerw 	Signal(SIGHUP, SIG_IGN);
    353       1.11  kristerw 	Signal(SIGINT, SIG_IGN);
    354        1.1       cgd }
    355        1.1       cgd 
    356       1.11  kristerw /*
    357       1.11  kristerw  * Make sure we'll have the directories to create a file.
    358       1.11  kristerw  * If `striplast' is TRUE, ignore the last element of `filename'.
    359       1.11  kristerw  */
    360        1.1       cgd void
    361        1.9  kristerw makedirs(char *filename, bool striplast)
    362        1.1       cgd {
    363       1.12  kristerw 	char tmpbuf[MAXPATHLEN];
    364       1.11  kristerw 	char *s = tmpbuf;
    365       1.12  kristerw 	char *dirv[MAXPATHLEN];	/* Point to the NULs between elements.  */
    366       1.11  kristerw 	int i;
    367       1.11  kristerw 	int dirvp = 0;		/* Number of finished entries in dirv. */
    368       1.11  kristerw 
    369       1.11  kristerw 	/*
    370       1.11  kristerw 	 * Copy `filename' into `tmpbuf' with a NUL instead of a slash
    371       1.11  kristerw 	 * between the directories.
    372       1.11  kristerw 	 */
    373       1.11  kristerw 	while (*filename) {
    374       1.11  kristerw 		if (*filename == '/') {
    375       1.11  kristerw 			filename++;
    376       1.11  kristerw 			dirv[dirvp++] = s;
    377       1.11  kristerw 			*s++ = '\0';
    378       1.11  kristerw 		} else {
    379       1.11  kristerw 			*s++ = *filename++;
    380       1.11  kristerw 		}
    381       1.11  kristerw 	}
    382       1.11  kristerw 	*s = '\0';
    383       1.11  kristerw 	dirv[dirvp] = s;
    384       1.11  kristerw 	if (striplast)
    385       1.11  kristerw 		dirvp--;
    386       1.11  kristerw 	if (dirvp < 0)
    387       1.11  kristerw 		return;
    388       1.11  kristerw 
    389       1.18    itojun 	strlcpy(buf, "mkdir", sizeof(buf));
    390       1.11  kristerw 	s = buf;
    391       1.11  kristerw 	for (i = 0; i <= dirvp; i++) {
    392       1.11  kristerw 		struct stat sbuf;
    393       1.11  kristerw 
    394       1.11  kristerw 		if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
    395       1.11  kristerw 			while (*s)
    396       1.11  kristerw 				s++;
    397       1.11  kristerw 			*s++ = ' ';
    398       1.18    itojun 			strlcpy(s, tmpbuf, sizeof(buf) - (s - buf));
    399       1.11  kristerw 		}
    400       1.11  kristerw 		*dirv[i] = '/';
    401       1.11  kristerw 	}
    402       1.11  kristerw 	if (s != buf)
    403       1.11  kristerw 		system(buf);
    404        1.1       cgd }
    405        1.1       cgd 
    406       1.11  kristerw /*
    407       1.11  kristerw  * Make filenames more reasonable.
    408       1.11  kristerw  */
    409        1.1       cgd char *
    410        1.9  kristerw fetchname(char *at, int strip_leading, int assume_exists)
    411        1.1       cgd {
    412       1.11  kristerw 	char *fullname;
    413       1.11  kristerw 	char *name;
    414       1.11  kristerw 	char *t;
    415       1.12  kristerw 	char tmpbuf[MAXPATHLEN];
    416       1.11  kristerw 	int sleading = strip_leading;
    417       1.11  kristerw 
    418       1.11  kristerw 	if (!at)
    419       1.11  kristerw 		return NULL;
    420       1.11  kristerw 	while (isspace((unsigned char)*at))
    421       1.11  kristerw 		at++;
    422        1.1       cgd #ifdef DEBUGGING
    423       1.11  kristerw 	if (debug & 128)
    424       1.11  kristerw 		say("fetchname %s %d %d\n", at, strip_leading, assume_exists);
    425        1.1       cgd #endif
    426       1.11  kristerw 	filename_is_dev_null = FALSE;
    427       1.11  kristerw 	if (strnEQ(at, "/dev/null", 9)) {
    428       1.11  kristerw 		/* So files can be created by diffing against /dev/null. */
    429       1.11  kristerw 		filename_is_dev_null = TRUE;
    430       1.11  kristerw 		return NULL;
    431       1.11  kristerw 	}
    432       1.12  kristerw 	name = fullname = t = xstrdup(at);
    433       1.11  kristerw 
    434       1.11  kristerw 	/* Strip off up to `sleading' leading slashes and null terminate. */
    435       1.11  kristerw 	for (; *t && !isspace((unsigned char)*t); t++)
    436       1.11  kristerw 		if (*t == '/')
    437       1.11  kristerw 			if (--sleading >= 0)
    438       1.11  kristerw 				name = t + 1;
    439       1.11  kristerw 	*t = '\0';
    440       1.11  kristerw 
    441       1.11  kristerw 	/*
    442       1.11  kristerw 	 * If no -p option was given (957 is the default value!),
    443       1.11  kristerw 	 * we were given a relative pathname,
    444       1.11  kristerw 	 * and the leading directories that we just stripped off all exist,
    445       1.11  kristerw 	 * put them back on.
    446       1.11  kristerw 	 */
    447       1.11  kristerw 	if (strip_leading == 957 && name != fullname && *fullname != '/') {
    448       1.11  kristerw 		name[-1] = '\0';
    449       1.11  kristerw 		if (stat(fullname, &filestat) == 0 &&
    450       1.11  kristerw 		    S_ISDIR(filestat.st_mode)) {
    451       1.11  kristerw 			name[-1] = '/';
    452       1.11  kristerw 			name = fullname;
    453       1.11  kristerw 		}
    454       1.11  kristerw 	}
    455       1.11  kristerw 
    456       1.12  kristerw 	name = xstrdup(name);
    457       1.11  kristerw 	free(fullname);
    458       1.11  kristerw 
    459       1.11  kristerw 	if (stat(name, &filestat) && !assume_exists) {
    460       1.11  kristerw 		char *filebase = basename(name);
    461       1.14  kristerw 		size_t pathlen = filebase - name;
    462       1.11  kristerw 
    463       1.11  kristerw 		/* Put any leading path into `tmpbuf'. */
    464       1.17    itojun 		if (pathlen >= sizeof(tmpbuf))
    465       1.17    itojun 			return NULL;
    466       1.11  kristerw 		strncpy(tmpbuf, name, pathlen);
    467       1.17    itojun 		tmpbuf[pathlen] = '\0';
    468       1.11  kristerw 
    469       1.11  kristerw #define try(f, a1, a2) \
    470       1.18    itojun     (snprintf(tmpbuf + pathlen, sizeof(tmpbuf) - pathlen, f, a1, a2), \
    471       1.18    itojun      stat(tmpbuf, &filestat) == 0)
    472       1.11  kristerw #define try1(f, a1) \
    473       1.18    itojun     (snprintf(tmpbuf + pathlen, sizeof(tmpbuf) - pathlen, f, a1), \
    474       1.18    itojun      stat(tmpbuf, &filestat) == 0)
    475       1.11  kristerw 		if (try("RCS/%s%s", filebase, RCSSUFFIX) ||
    476       1.11  kristerw 		    try1("RCS/%s"  , filebase) ||
    477       1.11  kristerw 		    try(    "%s%s", filebase, RCSSUFFIX) ||
    478       1.11  kristerw 		    try("SCCS/%s%s", SCCSPREFIX, filebase) ||
    479       1.11  kristerw 		    try(     "%s%s", SCCSPREFIX, filebase))
    480       1.11  kristerw 			return name;
    481       1.11  kristerw 		free(name);
    482       1.11  kristerw 		name = NULL;
    483       1.11  kristerw 	}
    484        1.1       cgd 
    485       1.11  kristerw 	return name;
    486        1.1       cgd }
    487