예제 #1
0
static int
rd_ln_nm(ARCHD *arcn)
{
	/*
	 * check the length specified for bogus values
	 */
	if ((arcn->sb.st_size == 0) ||
	    (arcn->sb.st_size >= sizeof(arcn->ln_name))) {
		paxwarn(1, "Cpio link name length is invalid: %jd",
		    (intmax_t)arcn->sb.st_size);
		return(-1);
	}

	/*
	 * read in the link name and \0 terminate it
	 */
	if (rd_wrbuf(arcn->ln_name, (int)arcn->sb.st_size) !=
	    (int)arcn->sb.st_size) {
		paxwarn(1, "Cpio link name read error");
		return(-1);
	}
	arcn->ln_nlen = arcn->sb.st_size;
	arcn->ln_name[arcn->ln_nlen] = '\0';

	/*
	 * watch out for those empty link names
	 */
	if (arcn->ln_name[0] == '\0') {
		paxwarn(1, "Cpio link name is corrupt");
		return(-1);
	}
	return(0);
}
예제 #2
0
파일: cpio.c 프로젝트: jhbsz/FreeBSD-REP
static int
rd_nm(ARCHD *arcn, int nsz)
{
	/*
	 * do not even try bogus values
	 */
	if ((nsz == 0) || (nsz > (int)sizeof(arcn->name))) {
		paxwarn(1, "Cpio file name length %d is out of range", nsz);
		return(-1);
	}

	/*
	 * read the name and make sure it is not empty and is \0 terminated
	 */
	if ((rd_wrbuf(arcn->name,nsz) != nsz) || (arcn->name[nsz-1] != '\0') ||
	    (arcn->name[0] == '\0')) {
		paxwarn(1, "Cpio file name in header is corrupted");
		return(-1);
	}
	return(0);
}
예제 #3
0
파일: tar.c 프로젝트: aalm/obsd-src
int
ustar_rd(ARCHD *arcn, char *buf)
{
	HD_USTAR *hd = (HD_USTAR *)buf;
	char *dest;
	int cnt = 0;
	dev_t devmajor;
	dev_t devminor;
	unsigned long long val;

	/*
	 * we only get proper sized buffers
	 */
	if (ustar_id(buf, BLKMULT) < 0)
		return(-1);

#ifndef SMALL
reset:
#endif
	memset(arcn, 0, sizeof(*arcn));
	arcn->org_name = arcn->name;
	arcn->sb.st_nlink = 1;

#ifndef SMALL
	/* Process Extended headers. */
	if (hd->typeflag == XHDRTYPE || hd->typeflag == GHDRTYPE) {
		if (rd_xheader(arcn, hd->typeflag == GHDRTYPE,
		    (off_t)asc_ul(hd->size, sizeof(hd->size), OCT)) < 0)
			return (-1);

		/* Update and check the ustar header. */
		if (rd_wrbuf(buf, BLKMULT) != BLKMULT)
			return (-1);
		if (ustar_id(buf, BLKMULT) < 0)
			return(-1);

		/* if the next block is another extension, reset the values */
		if (hd->typeflag == XHDRTYPE || hd->typeflag == GHDRTYPE)
			goto reset;
	}
#endif

	if (!arcn->nlen) {
		/*
		 * See if the filename is split into two parts. if, so join
		 * the parts.  We copy the prefix first and add a / between
		 * the prefix and name.
		 */
		dest = arcn->name;
		if (*(hd->prefix) != '\0') {
			cnt = fieldcpy(dest, sizeof(arcn->name) - 1,
			    hd->prefix, sizeof(hd->prefix));
			dest += cnt;
			*dest++ = '/';
			cnt++;
		} else
			cnt = 0;

		if (hd->typeflag != LONGLINKTYPE &&
		    hd->typeflag != LONGNAMETYPE) {
			arcn->nlen = cnt + expandname(dest,
			    sizeof(arcn->name) - cnt, &gnu_name_string,
			    hd->name, sizeof(hd->name));
		}
	}

	if (!arcn->ln_nlen &&
	    hd->typeflag != LONGLINKTYPE && hd->typeflag != LONGNAMETYPE) {
		arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name),
		    &gnu_link_string, hd->linkname, sizeof(hd->linkname));
	}

	/*
	 * follow the spec to the letter. we should only have mode bits, strip
	 * off all other crud we may be passed.
	 */
	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
	    0xfff);
	arcn->sb.st_size = (off_t)asc_ull(hd->size, sizeof(hd->size), OCT);
	val = asc_ull(hd->mtime, sizeof(hd->mtime), OCT);
	if ((time_t)val < 0 || (time_t)val != val)
		arcn->sb.st_mtime = INT_MAX;                    /* XXX 2038 */
	else
		arcn->sb.st_mtime = val;
	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;

	/*
	 * If we can find the ascii names for gname and uname in the password
	 * and group files we will use the uid's and gid they bind. Otherwise
	 * we use the uid and gid values stored in the header. (This is what
	 * the posix spec wants).
	 */
	hd->gname[sizeof(hd->gname) - 1] = '\0';
	if (Nflag || gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)
		arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
	hd->uname[sizeof(hd->uname) - 1] = '\0';
	if (Nflag || uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
		arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);

	/*
	 * set the defaults, these may be changed depending on the file type
	 */
	arcn->pad = 0;
	arcn->skip = 0;
	arcn->sb.st_rdev = (dev_t)0;

	/*
	 * set the mode and PAX type according to the typeflag in the header
	 */
	switch (hd->typeflag) {
	case FIFOTYPE:
		arcn->type = PAX_FIF;
		arcn->sb.st_mode |= S_IFIFO;
		break;
	case DIRTYPE:
		arcn->type = PAX_DIR;
		arcn->sb.st_mode |= S_IFDIR;
		arcn->sb.st_nlink = 2;

		/*
		 * Some programs that create ustar archives append a '/'
		 * to the pathname for directories. This clearly violates
		 * ustar specs, but we will silently strip it off anyway.
		 */
		if (arcn->name[arcn->nlen - 1] == '/')
			arcn->name[--arcn->nlen] = '\0';
		break;
	case BLKTYPE:
	case CHRTYPE:
		/*
		 * this type requires the rdev field to be set.
		 */
		if (hd->typeflag == BLKTYPE) {
			arcn->type = PAX_BLK;
			arcn->sb.st_mode |= S_IFBLK;
		} else {
			arcn->type = PAX_CHR;
			arcn->sb.st_mode |= S_IFCHR;
		}
		devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
		devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
		arcn->sb.st_rdev = TODEV(devmajor, devminor);
		break;
	case SYMTYPE:
	case LNKTYPE:
		if (hd->typeflag == SYMTYPE) {
			arcn->type = PAX_SLK;
			arcn->sb.st_mode |= S_IFLNK;
		} else {
			arcn->type = PAX_HLK;
			/*
			 * so printing looks better
			 */
			arcn->sb.st_mode |= S_IFREG;
			arcn->sb.st_nlink = 2;
		}
		break;
	case LONGLINKTYPE:
	case LONGNAMETYPE:
		/*
		 * GNU long link/file; we tag these here and let the
		 * pax internals deal with it -- too ugly otherwise.
		 */
		arcn->type =
		    hd->typeflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF;
		arcn->pad = TAR_PAD(arcn->sb.st_size);
		arcn->skip = arcn->sb.st_size;
		break;
	case CONTTYPE:
	case AREGTYPE:
	case REGTYPE:
	default:
		/*
		 * these types have file data that follows. Set the skip and
		 * pad fields.
		 */
		arcn->type = PAX_REG;
		arcn->pad = TAR_PAD(arcn->sb.st_size);
		arcn->skip = arcn->sb.st_size;
		arcn->sb.st_mode |= S_IFREG;
		break;
	}
	return(0);
}
예제 #4
0
파일: tar.c 프로젝트: aalm/obsd-src
static int
rd_xheader(ARCHD *arcn, int global, off_t size)
{
	char buf[MAXXHDRSZ];
	unsigned long len;
	char *delim, *keyword;
	char *nextp, *p, *end;
	int pad, ret = 0;

	/* before we alter size, make note of how much we have to skip */
	pad = TAR_PAD((unsigned)size);

	p = end = buf;
	while (size > 0 || p < end) {
		if (size > 0) {
			int rdlen;

			/* shift stuff down */
			if (p > buf) {
				memmove(buf, p, end - p);
				end -= p - buf;
				p = buf;
			}

			/* fill starting at end */
			rdlen = MINIMUM(size, (buf + sizeof buf) - end);
			if (rd_wrbuf(end, rdlen) != rdlen) {
				ret = -1;
				break;
			}
			size -= rdlen;
			end += rdlen;
		}

		/* [p, end) is good */
		if (memchr(p, ' ', end - p) == NULL ||
		    !isdigit((unsigned char)*p)) {
			paxwarn(1, "Invalid extended header record");
			ret = -1;
			break;
		}
		errno = 0;
		len = strtoul(p, &delim, 10);
		if (*delim != ' ' || (errno == ERANGE && len == ULONG_MAX) ||
		    len < MINXHDRSZ) {
			paxwarn(1, "Invalid extended header record length");
			ret = -1;
			break;
		}
		if (len > end - p) {
			paxwarn(1, "Extended header record length %lu is "
			    "out of range", len);
			/* if we can just toss this record, do so */
			len -= end - p;
			if (len <= size && rd_skip(len) == 0) {
				size -= len;
				p = end = buf;
				continue;
			}
			ret = -1;
			break;
		}
		nextp = p + len;
		keyword = p = delim + 1;
		p = memchr(p, '=', len);
		if (!p || nextp[-1] != '\n') {
			paxwarn(1, "Malformed extended header record");
			ret = -1;
			break;
		}
		*p++ = nextp[-1] = '\0';
		if (!global) {
			if (!strcmp(keyword, "path")) {
				arcn->nlen = strlcpy(arcn->name, p,
				    sizeof(arcn->name));
			} else if (!strcmp(keyword, "linkpath")) {
				arcn->ln_nlen = strlcpy(arcn->ln_name, p,
				    sizeof(arcn->ln_name));
			}
		}
		p = nextp;
	}

	if (rd_skip(size + pad) < 0)
		return (-1);
	return (ret);
}
예제 #5
0
static int
get_arc(void)
{
	int i;
	int hdsz = 0;
	int res;
	int minhd = BLKMULT;
	char *hdend;
	int notice = 0;

	/*
	 * find the smallest header size in all archive formats and then set up
	 * to read the archive.
	 */
	for (i = 0; ford[i] >= 0; ++i) {
		if (fsub[ford[i]].hsz < minhd)
			minhd = fsub[ford[i]].hsz;
	}
	if (rd_start() < 0)
		return -1;
	res = BLKMULT;
	hdsz = 0;
	hdend = hdbuf;
	for(;;) {
		for (;;) {
			/*
			 * fill the buffer with at least the smallest header
			 */
			i = rd_wrbuf(hdend, res);
			if (i > 0)
				hdsz += i;
			if (hdsz >= minhd)
				break;

			/*
			 * if we cannot recover from a read error quit
			 */
			if ((i == 0) || (rd_sync() < 0))
				goto out;

			/*
			 * when we get an error none of the data we already
			 * have can be used to create a legal header (we just
			 * got an error in the middle), so we throw it all out
			 * and refill the buffer with fresh data.
			 */
			res = BLKMULT;
			hdsz = 0;
			hdend = hdbuf;
			if (!notice) {
				if (act == APPND)
					return -1;
				tty_warn(1,
				    "Cannot identify format. Searching...");
				++notice;
			}
		}

		/*
		 * we have at least the size of the smallest header in any
		 * archive format. Look to see if we have a match. The array
		 * ford[] is used to specify the header id order to reduce the
		 * chance of incorrectly id'ing a valid header (some formats
		 * may be subsets of each other and the order would then be
		 * important).
		 */
		for (i = 0; ford[i] >= 0; ++i) {
			if ((*fsub[ford[i]].id)(hdbuf, hdsz) < 0)
				continue;
			frmt = &(fsub[ford[i]]);
			/*
			 * yuck, to avoid slow special case code in the extract
			 * routines, just push this header back as if it was
			 * not seen. We have left extra space at start of the
			 * buffer for this purpose. This is a bit ugly, but
			 * adding all the special case code is far worse.
			 */
			pback(hdbuf, hdsz);
			return 0;
		}

		/*
		 * We have a flawed archive, no match. we start searching, but
		 * we never allow additions to flawed archives
		 */
		if (!notice) {
			if (act == APPND)
				return -1;
			tty_warn(1, "Cannot identify format. Searching...");
			++notice;
		}

		/*
		 * brute force search for a header that we can id.
		 * we shift through byte at a time. this is slow, but we cannot
		 * determine the nature of the flaw in the archive in a
		 * portable manner
		 */
		if (--hdsz > 0) {
			memmove(hdbuf, hdbuf+1, hdsz);
			res = BLKMULT - hdsz;
			hdend = hdbuf + hdsz;
		} else {
			res = BLKMULT;
			hdend = hdbuf;
			hdsz = 0;
		}
	}

    out:
	/*
	 * we cannot find a header, bow, apologize and quit
	 */
	tty_warn(1, "Sorry, unable to determine archive format.");
	return -1;
}
예제 #6
0
static int
next_head(ARCHD *arcn)
{
	int ret;
	char *hdend;
	int res;
	int shftsz;
	int hsz;
	int in_resync = 0;		/* set when we are in resync mode */
	int cnt = 0;			/* counter for trailer function */
	int first = 1;			/* on 1st read, EOF isn't premature. */

	/*
	 * set up initial conditions, we want a whole frmt->hsz block as we
	 * have no data yet.
	 */
	res = hsz = frmt->hsz;
	hdend = hdbuf;
	shftsz = hsz - 1;
	for(;;) {
		/*
		 * keep looping until we get a contiguous FULL buffer
		 * (frmt->hsz is the proper size)
		 */
		for (;;) {
			if ((ret = rd_wrbuf(hdend, res)) == res)
				break;

			/*
			 * If we read 0 bytes (EOF) from an archive when we
			 * expect to find a header, we have stepped upon
			 * an archive without the customary block of zeroes
			 * end marker.  It's just stupid to error out on
			 * them, so exit gracefully.
			 */
			if (first && ret == 0)
				return -1;
			first = 0;

			/*
			 * some kind of archive read problem, try to resync the
			 * storage device, better give the user the bad news.
			 */
			if ((ret == 0) || (rd_sync() < 0)) {
				tty_warn(1,
				    "Premature end of file on archive read");
				return -1;
			}
			if (!in_resync) {
				if (act == APPND) {
					tty_warn(1,
					  "Archive I/O error, cannot continue");
					return -1;
				}
				tty_warn(1,
				    "Archive I/O error. Trying to recover.");
				++in_resync;
			}

			/*
			 * oh well, throw it all out and start over
			 */
			res = hsz;
			hdend = hdbuf;
		}

		/*
		 * ok we have a contiguous buffer of the right size. Call the
		 * format read routine. If this was not a valid header and this
		 * format stores trailers outside of the header, call the
		 * format specific trailer routine to check for a trailer. We
		 * have to watch out that we do not mis-identify file data or
		 * block padding as a header or trailer. Format specific
		 * trailer functions must NOT check for the trailer while we
		 * are running in resync mode. Some trailer functions may tell
		 * us that this block cannot contain a valid header either, so
		 * we then throw out the entire block and start over.
		 */
		if ((*frmt->rd)(arcn, hdbuf) == 0)
			break;

		if (!frmt->inhead) {
			/*
			 * this format has trailers outside of valid headers
			 */
			if ((ret = (*frmt->trail)(hdbuf,in_resync,&cnt)) == 0){
				/*
				 * valid trailer found, drain input as required
				 */
				ar_drain();
				return -1;
			}

			if (ret == 1) {
				/*
				 * we are in resync and we were told to throw
				 * the whole block out because none of the
				 * bytes in this block can be used to form a
				 * valid header
				 */
				res = hsz;
				hdend = hdbuf;
				continue;
			}
		}

		/*
		 * Brute force section.
		 * not a valid header. We may be able to find a header yet. So
		 * we shift over by one byte, and set up to read one byte at a
		 * time from the archive and place it at the end of the buffer.
		 * We will keep moving byte at a time until we find a header or
		 * get a read error and have to start over.
		 */
		if (!in_resync) {
			if (act == APPND) {
				tty_warn(1,
				    "Unable to append, archive header flaw");
				return -1;
			}
			tty_warn(1,
			    "Invalid header, starting valid header search.");
			++in_resync;
		}
		memmove(hdbuf, hdbuf+1, shftsz);
		res = 1;
		hdend = hdbuf + shftsz;
	}

	/*
	 * ok got a valid header, check for trailer if format encodes it in the
	 * the header. NOTE: the parameters are different than trailer routines
	 * which encode trailers outside of the header!
	 */
	if (frmt->inhead && ((*frmt->subtrail)(arcn) == 0)) {
		/*
		 * valid trailer found, drain input as required
		 */
		ar_drain();
		return -1;
	}

	++flcnt;
	return 0;
}