Home | History | Annotate | Line # | Download | only in patch
util.c revision 1.29.2.1
      1      1.24     joerg /*
      2      1.24     joerg  * $OpenBSD: util.c,v 1.32 2006/03/11 19:41:30 otto Exp $
      3      1.24     joerg  * $DragonFly: src/usr.bin/patch/util.c,v 1.9 2007/09/29 23:11:10 swildner Exp $
      4  1.29.2.1      cjep  * $NetBSD: util.c,v 1.29.2.1 2021/05/31 22:15:25 cjep Exp $
      5      1.24     joerg  */
      6      1.16    itojun 
      7      1.16    itojun /*
      8      1.24     joerg  * patch - a program to apply diffs to original files
      9      1.24     joerg  *
     10      1.24     joerg  * Copyright 1986, Larry Wall
     11      1.24     joerg  *
     12      1.16    itojun  * Redistribution and use in source and binary forms, with or without
     13      1.24     joerg  * modification, are permitted provided that the following condition is met:
     14      1.24     joerg  * 1. Redistributions of source code must retain the above copyright notice,
     15      1.24     joerg  * this condition and the following disclaimer.
     16      1.24     joerg  *
     17      1.24     joerg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
     18      1.24     joerg  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19      1.24     joerg  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20      1.24     joerg  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
     21      1.24     joerg  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22      1.24     joerg  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     23      1.24     joerg  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     24      1.24     joerg  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25      1.16    itojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26      1.16    itojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27      1.16    itojun  * SUCH DAMAGE.
     28      1.24     joerg  *
     29      1.24     joerg  * -C option added in 1998, original code by Marc Espie, based on FreeBSD
     30      1.24     joerg  * behaviour
     31      1.16    itojun  */
     32      1.16    itojun 
     33       1.5  christos #include <sys/cdefs.h>
     34  1.29.2.1      cjep __RCSID("$NetBSD: util.c,v 1.29.2.1 2021/05/31 22:15:25 cjep Exp $");
     35       1.2   mycroft 
     36      1.12  kristerw #include <sys/param.h>
     37      1.24     joerg #include <sys/stat.h>
     38      1.24     joerg 
     39      1.24     joerg #include <ctype.h>
     40      1.24     joerg #include <errno.h>
     41      1.24     joerg #include <fcntl.h>
     42      1.24     joerg #include <libgen.h>
     43      1.24     joerg #include <signal.h>
     44      1.24     joerg #include <stdarg.h>
     45      1.24     joerg #include <stdlib.h>
     46      1.24     joerg #include <stdio.h>
     47      1.24     joerg #include <string.h>
     48      1.24     joerg #include <unistd.h>
     49      1.12  kristerw 
     50       1.1       cgd #include "common.h"
     51       1.1       cgd #include "util.h"
     52       1.1       cgd #include "backupfile.h"
     53      1.24     joerg #include "pathnames.h"
     54      1.10  kristerw 
     55      1.24     joerg /* Rename a file, copying it if necessary. */
     56       1.1       cgd 
     57       1.1       cgd int
     58      1.24     joerg move_file(const char *from, const char *to)
     59       1.1       cgd {
     60      1.24     joerg 	int	fromfd;
     61      1.24     joerg 	ssize_t	i;
     62      1.21       skd 
     63      1.11  kristerw 	/* to stdout? */
     64       1.1       cgd 
     65      1.11  kristerw 	if (strEQ(to, "-")) {
     66       1.1       cgd #ifdef DEBUGGING
     67      1.11  kristerw 		if (debug & 4)
     68      1.11  kristerw 			say("Moving %s to stdout.\n", from);
     69       1.1       cgd #endif
     70      1.24     joerg 		fromfd = open(from, O_RDONLY);
     71      1.11  kristerw 		if (fromfd < 0)
     72      1.11  kristerw 			pfatal("internal error, can't reopen %s", from);
     73  1.29.2.1      cjep 		while ((i = read(fromfd, buf, bufsz)) > 0)
     74      1.24     joerg 			if (write(STDOUT_FILENO, buf, i) != i)
     75      1.11  kristerw 				pfatal("write failed");
     76      1.24     joerg 		close(fromfd);
     77      1.11  kristerw 		return 0;
     78      1.11  kristerw 	}
     79      1.24     joerg 	if (backup_file(to) < 0) {
     80      1.24     joerg 		say("Can't backup %s, output is in %s: %s\n", to, from,
     81      1.24     joerg 		    strerror(errno));
     82      1.24     joerg 		return -1;
     83       1.1       cgd 	}
     84       1.1       cgd #ifdef DEBUGGING
     85       1.1       cgd 	if (debug & 4)
     86      1.11  kristerw 		say("Moving %s to %s.\n", from, to);
     87       1.1       cgd #endif
     88      1.24     joerg 	if (rename(from, to) < 0) {
     89      1.24     joerg 		if (errno != EXDEV || copy_file(from, to) < 0) {
     90      1.11  kristerw 			say("Can't create %s, output is in %s: %s\n",
     91      1.11  kristerw 			    to, from, strerror(errno));
     92      1.11  kristerw 			return -1;
     93      1.11  kristerw 		}
     94       1.1       cgd 	}
     95      1.24     joerg 	return 0;
     96      1.24     joerg }
     97      1.24     joerg 
     98      1.24     joerg /* Backup the original file.  */
     99      1.24     joerg 
    100      1.24     joerg int
    101      1.24     joerg backup_file(const char *orig)
    102      1.24     joerg {
    103      1.24     joerg 	struct stat	filestat;
    104      1.24     joerg 	char		bakname[MAXPATHLEN], *s, *simplename;
    105      1.24     joerg 	dev_t		orig_device;
    106      1.24     joerg 	ino_t		orig_inode;
    107      1.24     joerg 
    108      1.24     joerg 	if (backup_type == none || stat(orig, &filestat) != 0)
    109      1.24     joerg 		return 0;			/* nothing to do */
    110      1.24     joerg 	/*
    111      1.24     joerg 	 * If the user used zero prefixes or suffixes, then
    112      1.24     joerg 	 * he doesn't want backups.  Yet we have to remove
    113      1.24     joerg 	 * orig to break possible hardlinks.
    114      1.24     joerg 	 */
    115      1.24     joerg 	if ((origprae && *origprae == 0) || *simple_backup_suffix == 0) {
    116      1.24     joerg 		unlink(orig);
    117      1.24     joerg 		return 0;
    118      1.24     joerg 	}
    119      1.24     joerg 	orig_device = filestat.st_dev;
    120      1.24     joerg 	orig_inode = filestat.st_ino;
    121      1.24     joerg 
    122      1.24     joerg 	if (origprae) {
    123      1.24     joerg 		if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||
    124      1.24     joerg 		    strlcat(bakname, orig, sizeof(bakname)) >= sizeof(bakname))
    125      1.24     joerg 			fatal("filename %s too long for buffer\n", origprae);
    126      1.24     joerg 	} else {
    127      1.24     joerg 		if ((s = find_backup_file_name(orig)) == NULL)
    128      1.24     joerg 			fatal("out of memory\n");
    129      1.24     joerg 		if (strlcpy(bakname, s, sizeof(bakname)) >= sizeof(bakname))
    130      1.24     joerg 			fatal("filename %s too long for buffer\n", s);
    131      1.24     joerg 		free(s);
    132      1.24     joerg 	}
    133      1.24     joerg 
    134      1.24     joerg 	if ((simplename = strrchr(bakname, '/')) != NULL)
    135      1.24     joerg 		simplename = simplename + 1;
    136      1.24     joerg 	else
    137      1.24     joerg 		simplename = bakname;
    138      1.24     joerg 
    139      1.24     joerg 	/*
    140      1.24     joerg 	 * Find a backup name that is not the same file. Change the
    141      1.24     joerg 	 * first lowercase char into uppercase; if that isn't
    142      1.24     joerg 	 * sufficient, chop off the first char and try again.
    143      1.24     joerg 	 */
    144      1.24     joerg 	while (stat(bakname, &filestat) == 0 &&
    145      1.24     joerg 	    orig_device == filestat.st_dev && orig_inode == filestat.st_ino) {
    146      1.24     joerg 		/* Skip initial non-lowercase chars.  */
    147      1.24     joerg 		for (s = simplename; *s && !islower((unsigned char)*s); s++)
    148      1.24     joerg 			;
    149      1.24     joerg 		if (*s)
    150      1.24     joerg 			*s = toupper((unsigned char)*s);
    151      1.24     joerg 		else
    152      1.24     joerg 			memmove(simplename, simplename + 1,
    153      1.24     joerg 			    strlen(simplename + 1) + 1);
    154      1.24     joerg 	}
    155      1.24     joerg #ifdef DEBUGGING
    156      1.24     joerg 	if (debug & 4)
    157      1.24     joerg 		say("Moving %s to %s.\n", orig, bakname);
    158      1.24     joerg #endif
    159      1.24     joerg 	if (rename(orig, bakname) < 0) {
    160      1.24     joerg 		if (errno != EXDEV || copy_file(orig, bakname) < 0)
    161      1.24     joerg 			return -1;
    162      1.24     joerg 	}
    163      1.11  kristerw 	return 0;
    164      1.11  kristerw }
    165      1.11  kristerw 
    166      1.11  kristerw /*
    167      1.11  kristerw  * Copy a file.
    168      1.11  kristerw  */
    169      1.24     joerg int
    170      1.24     joerg copy_file(const char *from, const char *to)
    171      1.11  kristerw {
    172      1.24     joerg 	int	tofd, fromfd;
    173      1.24     joerg 	ssize_t	i;
    174      1.11  kristerw 
    175      1.24     joerg 	tofd = open(to, O_CREAT|O_TRUNC|O_WRONLY, 0666);
    176      1.11  kristerw 	if (tofd < 0)
    177      1.24     joerg 		return -1;
    178      1.24     joerg 	fromfd = open(from, O_RDONLY, 0);
    179       1.1       cgd 	if (fromfd < 0)
    180      1.11  kristerw 		pfatal("internal error, can't reopen %s", from);
    181  1.29.2.1      cjep 	while ((i = read(fromfd, buf, bufsz)) > 0)
    182      1.11  kristerw 		if (write(tofd, buf, i) != i)
    183      1.11  kristerw 			pfatal("write to %s failed", to);
    184      1.24     joerg 	close(fromfd);
    185      1.24     joerg 	close(tofd);
    186      1.24     joerg 	return 0;
    187      1.12  kristerw }
    188      1.12  kristerw 
    189      1.12  kristerw /*
    190      1.24     joerg  * Allocate a unique area for a string.
    191      1.11  kristerw  */
    192       1.1       cgd char *
    193      1.24     joerg savestr(const char *s)
    194       1.1       cgd {
    195      1.24     joerg 	char	*rv;
    196       1.1       cgd 
    197      1.24     joerg 	if (!s)
    198      1.24     joerg 		s = "Oops";
    199      1.24     joerg 	rv = strdup(s);
    200      1.24     joerg 	if (rv == NULL) {
    201      1.24     joerg 		if (using_plan_a)
    202      1.24     joerg 			out_of_mem = true;
    203      1.24     joerg 		else
    204      1.24     joerg 			fatal("out of memory\n");
    205      1.24     joerg 	}
    206      1.24     joerg 	return rv;
    207       1.1       cgd }
    208       1.1       cgd 
    209      1.11  kristerw /*
    210      1.24     joerg  * Vanilla terminal output (buffered).
    211      1.11  kristerw  */
    212       1.1       cgd void
    213      1.24     joerg say(const char *fmt, ...)
    214       1.1       cgd {
    215      1.24     joerg 	va_list	ap;
    216      1.24     joerg 
    217      1.24     joerg 	va_start(ap, fmt);
    218      1.24     joerg 	vfprintf(stderr, fmt, ap);
    219      1.11  kristerw 	va_end(ap);
    220      1.24     joerg 	fflush(stderr);
    221       1.1       cgd }
    222       1.1       cgd 
    223      1.11  kristerw /*
    224      1.11  kristerw  * Terminal output, pun intended.
    225      1.11  kristerw  */
    226      1.24     joerg void
    227      1.24     joerg fatal(const char *fmt, ...)
    228       1.1       cgd {
    229      1.24     joerg 	va_list	ap;
    230      1.24     joerg 
    231      1.24     joerg 	va_start(ap, fmt);
    232      1.11  kristerw 	fprintf(stderr, "patch: **** ");
    233      1.24     joerg 	vfprintf(stderr, fmt, ap);
    234      1.11  kristerw 	va_end(ap);
    235      1.24     joerg 	my_exit(2);
    236       1.1       cgd }
    237       1.1       cgd 
    238      1.11  kristerw /*
    239      1.24     joerg  * Say something from patch, something from the system, then silence . . .
    240      1.11  kristerw  */
    241      1.24     joerg void
    242      1.24     joerg pfatal(const char *fmt, ...)
    243       1.1       cgd {
    244      1.24     joerg 	va_list	ap;
    245      1.24     joerg 	int	errnum = errno;
    246      1.24     joerg 
    247      1.11  kristerw 	fprintf(stderr, "patch: **** ");
    248      1.24     joerg 	va_start(ap, fmt);
    249      1.24     joerg 	vfprintf(stderr, fmt, ap);
    250      1.24     joerg 	va_end(ap);
    251      1.11  kristerw 	fprintf(stderr, ": %s\n", strerror(errnum));
    252      1.24     joerg 	my_exit(2);
    253       1.1       cgd }
    254       1.1       cgd 
    255      1.11  kristerw /*
    256      1.24     joerg  * Get a response from the user via /dev/tty
    257      1.11  kristerw  */
    258       1.1       cgd void
    259      1.24     joerg ask(const char *fmt, ...)
    260       1.1       cgd {
    261      1.24     joerg 	va_list	ap;
    262      1.24     joerg 	ssize_t	nr = 0;
    263      1.24     joerg 	static	int ttyfd = -1;
    264      1.11  kristerw 
    265      1.24     joerg 	va_start(ap, fmt);
    266      1.24     joerg 	vfprintf(stdout, fmt, ap);
    267      1.11  kristerw 	va_end(ap);
    268      1.24     joerg 	fflush(stdout);
    269      1.24     joerg 	if (ttyfd < 0)
    270      1.24     joerg 		ttyfd = open(_PATH_TTY, O_RDONLY);
    271      1.24     joerg 	if (ttyfd >= 0) {
    272  1.29.2.1      cjep 		if ((nr = read(ttyfd, buf, bufsz)) > 0 &&
    273      1.24     joerg 		    buf[nr - 1] == '\n')
    274      1.24     joerg 			buf[nr - 1] = '\0';
    275      1.24     joerg 	}
    276      1.24     joerg 	if (ttyfd < 0 || nr <= 0) {
    277      1.24     joerg 		/* no tty or error reading, pretend user entered 'return' */
    278      1.24     joerg 		putchar('\n');
    279      1.24     joerg 		buf[0] = '\0';
    280      1.11  kristerw 	}
    281       1.1       cgd }
    282       1.1       cgd 
    283      1.11  kristerw /*
    284      1.11  kristerw  * How to handle certain events when not in a critical region.
    285      1.11  kristerw  */
    286       1.1       cgd void
    287       1.9  kristerw set_signals(int reset)
    288       1.1       cgd {
    289      1.24     joerg 	static sig_t	hupval, intval;
    290       1.1       cgd 
    291      1.11  kristerw 	if (!reset) {
    292      1.11  kristerw 		hupval = signal(SIGHUP, SIG_IGN);
    293      1.11  kristerw 		if (hupval != SIG_IGN)
    294      1.24     joerg 			hupval = my_exit;
    295      1.11  kristerw 		intval = signal(SIGINT, SIG_IGN);
    296      1.11  kristerw 		if (intval != SIG_IGN)
    297      1.24     joerg 			intval = my_exit;
    298      1.11  kristerw 	}
    299      1.24     joerg 	signal(SIGHUP, hupval);
    300      1.24     joerg 	signal(SIGINT, intval);
    301       1.1       cgd }
    302       1.1       cgd 
    303      1.11  kristerw /*
    304      1.11  kristerw  * How to handle certain events when in a critical region.
    305      1.11  kristerw  */
    306       1.1       cgd void
    307      1.24     joerg ignore_signals(void)
    308       1.1       cgd {
    309      1.24     joerg 	signal(SIGHUP, SIG_IGN);
    310      1.24     joerg 	signal(SIGINT, SIG_IGN);
    311       1.1       cgd }
    312       1.1       cgd 
    313      1.11  kristerw /*
    314      1.24     joerg  * Make sure we'll have the directories to create a file. If `striplast' is
    315      1.24     joerg  * true, ignore the last element of `filename'.
    316      1.11  kristerw  */
    317      1.24     joerg 
    318       1.1       cgd void
    319      1.24     joerg makedirs(const char *filename, bool striplast)
    320       1.1       cgd {
    321      1.24     joerg 	char	*tmpbuf;
    322      1.24     joerg 
    323      1.24     joerg 	if ((tmpbuf = strdup(filename)) == NULL)
    324      1.24     joerg 		fatal("out of memory\n");
    325      1.11  kristerw 
    326      1.24     joerg 	if (striplast) {
    327      1.24     joerg 		char	*s = strrchr(tmpbuf, '/');
    328      1.25     joerg 		if (s == NULL) {
    329      1.25     joerg 			free(tmpbuf);
    330      1.24     joerg 			return;	/* nothing to be done */
    331      1.25     joerg 		}
    332      1.24     joerg 		*s = '\0';
    333      1.24     joerg 	}
    334      1.24     joerg 	if (mkpath(tmpbuf) != 0)
    335      1.24     joerg 		pfatal("creation of %s failed", tmpbuf);
    336      1.24     joerg 	free(tmpbuf);
    337       1.1       cgd }
    338       1.1       cgd 
    339      1.11  kristerw /*
    340      1.11  kristerw  * Make filenames more reasonable.
    341      1.11  kristerw  */
    342       1.1       cgd char *
    343      1.24     joerg fetchname(const char *at, bool *exists, int strip_leading)
    344       1.1       cgd {
    345      1.24     joerg 	char		*fullname, *name, *t;
    346      1.24     joerg 	int		sleading, tab;
    347      1.24     joerg 	struct stat	filestat;
    348      1.11  kristerw 
    349      1.24     joerg 	if (at == NULL || *at == '\0')
    350      1.11  kristerw 		return NULL;
    351      1.11  kristerw 	while (isspace((unsigned char)*at))
    352      1.11  kristerw 		at++;
    353       1.1       cgd #ifdef DEBUGGING
    354      1.11  kristerw 	if (debug & 128)
    355      1.24     joerg 		say("fetchname %s %d\n", at, strip_leading);
    356       1.1       cgd #endif
    357      1.24     joerg 	/* So files can be created by diffing against /dev/null.  */
    358      1.24     joerg 	if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1))
    359      1.11  kristerw 		return NULL;
    360      1.24     joerg 	name = fullname = t = savestr(at);
    361      1.11  kristerw 
    362      1.24     joerg 	tab = strchr(t, '\t') != NULL;
    363      1.24     joerg 	/* Strip off up to `strip_leading' path components and NUL terminate. */
    364      1.24     joerg 	for (sleading = strip_leading; *t != '\0' && ((tab && *t != '\t') ||
    365      1.24     joerg 	    !isspace((unsigned char)*t)); t++) {
    366      1.24     joerg 		if (t[0] == '/' && t[1] != '/' && t[1] != '\0')
    367      1.11  kristerw 			if (--sleading >= 0)
    368      1.11  kristerw 				name = t + 1;
    369      1.24     joerg 	}
    370      1.11  kristerw 	*t = '\0';
    371      1.11  kristerw 
    372      1.11  kristerw 	/*
    373      1.24     joerg 	 * If no -p option was given (957 is the default value!), we were
    374      1.24     joerg 	 * given a relative pathname, and the leading directories that we
    375      1.24     joerg 	 * just stripped off all exist, put them back on.
    376      1.11  kristerw 	 */
    377      1.11  kristerw 	if (strip_leading == 957 && name != fullname && *fullname != '/') {
    378      1.11  kristerw 		name[-1] = '\0';
    379      1.24     joerg 		if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
    380      1.11  kristerw 			name[-1] = '/';
    381      1.11  kristerw 			name = fullname;
    382      1.11  kristerw 		}
    383      1.11  kristerw 	}
    384      1.24     joerg 	name = savestr(name);
    385      1.24     joerg 	free(fullname);
    386      1.24     joerg 
    387      1.24     joerg 	*exists = stat(name, &filestat) == 0;
    388      1.24     joerg 	return name;
    389      1.24     joerg }
    390      1.24     joerg 
    391      1.24     joerg /*
    392      1.24     joerg  * Takes the name returned by fetchname and looks in RCS/SCCS directories
    393      1.24     joerg  * for a checked in version.
    394      1.24     joerg  */
    395      1.24     joerg char *
    396      1.24     joerg checked_in(char *file)
    397      1.24     joerg {
    398      1.24     joerg 	char		*filebase, *filedir, tmpbuf[MAXPATHLEN];
    399      1.24     joerg 	struct stat	filestat;
    400      1.11  kristerw 
    401      1.24     joerg 	filebase = basename(file);
    402      1.24     joerg 	filedir = dirname(file);
    403      1.24     joerg 
    404      1.24     joerg #define try(f, a1, a2, a3) \
    405      1.24     joerg (snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0)
    406      1.24     joerg 
    407      1.24     joerg 	if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
    408      1.24     joerg 	    try("%s/RCS/%s%s", filedir, filebase, "") ||
    409      1.24     joerg 	    try("%s/%s%s", filedir, filebase, RCSSUFFIX) ||
    410      1.24     joerg 	    try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
    411      1.24     joerg 	    try("%s/%s%s", filedir, SCCSPREFIX, filebase))
    412      1.24     joerg 		return file;
    413      1.24     joerg 
    414      1.24     joerg 	return NULL;
    415      1.24     joerg }
    416      1.11  kristerw 
    417      1.24     joerg void
    418      1.24     joerg version(void)
    419      1.24     joerg {
    420      1.29   rhialto 	printf("Patch version 2.0-12u9-NetBSD\n");
    421      1.24     joerg 	my_exit(EXIT_SUCCESS);
    422      1.24     joerg }
    423       1.1       cgd 
    424      1.24     joerg /*
    425      1.24     joerg  * Exit with cleanup.
    426      1.24     joerg  */
    427      1.24     joerg void
    428      1.24     joerg my_exit(int status)
    429      1.24     joerg {
    430      1.24     joerg 	unlink(TMPINNAME);
    431      1.24     joerg 	if (!toutkeep)
    432      1.24     joerg 		unlink(TMPOUTNAME);
    433      1.24     joerg 	if (!trejkeep)
    434      1.24     joerg 		unlink(TMPREJNAME);
    435      1.24     joerg 	unlink(TMPPATNAME);
    436      1.24     joerg 	exit(status);
    437       1.1       cgd }
    438      1.28  christos 
    439      1.28  christos void *
    440      1.28  christos pch_realloc(void *ptr, size_t number, size_t size)
    441      1.28  christos {
    442      1.28  christos 	if (number > SIZE_MAX / size) {
    443      1.28  christos 		errno = EOVERFLOW;
    444      1.28  christos 		return NULL;
    445      1.28  christos 	}
    446      1.28  christos 	return realloc(ptr, number * size);
    447      1.28  christos }
    448