11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1992 Keith Muller.
31556Srgrimes * Copyright (c) 1992, 1993
41556Srgrimes *	The Regents of the University of California.  All rights reserved.
51556Srgrimes *
61556Srgrimes * This code is derived from software contributed to Berkeley by
71556Srgrimes * Keith Muller of the University of California, San Diego.
81556Srgrimes *
91556Srgrimes * Redistribution and use in source and binary forms, with or without
101556Srgrimes * modification, are permitted provided that the following conditions
111556Srgrimes * are met:
121556Srgrimes * 1. Redistributions of source code must retain the above copyright
131556Srgrimes *    notice, this list of conditions and the following disclaimer.
141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151556Srgrimes *    notice, this list of conditions and the following disclaimer in the
161556Srgrimes *    documentation and/or other materials provided with the distribution.
171556Srgrimes * 4. Neither the name of the University nor the names of its contributors
181556Srgrimes *    may be used to endorse or promote products derived from this software
191556Srgrimes *    without specific prior written permission.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311556Srgrimes * SUCH DAMAGE.
321556Srgrimes */
331556Srgrimes
341556Srgrimes#ifndef lint
3536049Scharnier#if 0
3636049Scharnierstatic char sccsid[] = "@(#)gen_subs.c	8.1 (Berkeley) 5/31/93";
3736049Scharnier#endif
381556Srgrimes#endif /* not lint */
3999110Sobrien#include <sys/cdefs.h>
4099110Sobrien__FBSDID("$FreeBSD$");
411556Srgrimes
421556Srgrimes#include <sys/types.h>
431556Srgrimes#include <sys/time.h>
441556Srgrimes#include <sys/stat.h>
4574567Sache#include <langinfo.h>
46104548Stjr#include <stdint.h>
471556Srgrimes#include <stdio.h>
481556Srgrimes#include <string.h>
491556Srgrimes#include "pax.h"
501556Srgrimes#include "extern.h"
511556Srgrimes
521556Srgrimes/*
531556Srgrimes * a collection of general purpose subroutines used by pax
541556Srgrimes */
551556Srgrimes
561556Srgrimes/*
571556Srgrimes * constants used by ls_list() when printing out archive members
581556Srgrimes */
591556Srgrimes#define MODELEN 20
601556Srgrimes#define DATELEN 64
619987Swollman#define SIXMONTHS	 ((365 / 2) * 86400)
6274567Sache#define CURFRMTM	"%b %e %H:%M"
6374567Sache#define OLDFRMTM	"%b %e  %Y"
6474567Sache#define CURFRMTD	"%e %b %H:%M"
6574567Sache#define OLDFRMTD	"%e %b  %Y"
661556Srgrimes
6774567Sachestatic int d_first = -1;
6874567Sache
691556Srgrimes/*
701556Srgrimes * ls_list()
711556Srgrimes *	list the members of an archive in ls format
721556Srgrimes */
731556Srgrimes
741556Srgrimesvoid
7590113Simpls_list(ARCHD *arcn, time_t now, FILE *fp)
761556Srgrimes{
7790113Simp	struct stat *sbp;
781556Srgrimes	char f_mode[MODELEN];
791556Srgrimes	char f_date[DATELEN];
80114583Smarkm	const char *timefrmt;
811556Srgrimes
821556Srgrimes	/*
831556Srgrimes	 * if not verbose, just print the file name
841556Srgrimes	 */
851556Srgrimes	if (!vflag) {
8676351Skris		(void)fprintf(fp, "%s\n", arcn->name);
8776351Skris		(void)fflush(fp);
881556Srgrimes		return;
891556Srgrimes	}
901556Srgrimes
9174567Sache	if (d_first < 0)
9274567Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
931556Srgrimes	/*
941556Srgrimes	 * user wants long mode
951556Srgrimes	 */
961556Srgrimes	sbp = &(arcn->sb);
971556Srgrimes	strmode(sbp->st_mode, f_mode);
981556Srgrimes
9973345Sru	/*
10073345Sru	 * time format based on age compared to the time pax was started.
10173345Sru	 */
10273345Sru	if ((sbp->st_mtime + SIXMONTHS) <= now)
10374567Sache		timefrmt = d_first ? OLDFRMTD : OLDFRMTM;
10473345Sru	else
10574567Sache		timefrmt = d_first ? CURFRMTD : CURFRMTM;
1061556Srgrimes
1071556Srgrimes	/*
1081556Srgrimes	 * print file mode, link count, uid, gid and time
1091556Srgrimes	 */
1101556Srgrimes	if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0)
1111556Srgrimes		f_date[0] = '\0';
112202193Sed	(void)fprintf(fp, "%s%2u %-12s %-12s ", f_mode, sbp->st_nlink,
113202193Sed		name_uid(sbp->st_uid, 1), name_gid(sbp->st_gid, 1));
1141556Srgrimes
1151556Srgrimes	/*
1161556Srgrimes	 * print device id's for devices, or sizes for other nodes
1171556Srgrimes	 */
1181556Srgrimes	if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
1191556Srgrimes#		ifdef NET2_STAT
12076351Skris		(void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev),
12120420Ssteve		    MINOR(sbp->st_rdev));
1221556Srgrimes#		else
12376351Skris		(void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev),
12420420Ssteve		    (unsigned long)MINOR(sbp->st_rdev));
1251556Srgrimes#		endif
1261556Srgrimes	else {
1271556Srgrimes#		ifdef NET2_STAT
12876351Skris		(void)fprintf(fp, "%9lu ", sbp->st_size);
1291556Srgrimes#		else
130104548Stjr		(void)fprintf(fp, "%9ju ", (uintmax_t)sbp->st_size);
1311556Srgrimes#		endif
1321556Srgrimes	}
1331556Srgrimes
1341556Srgrimes	/*
1351556Srgrimes	 * print name and link info for hard and soft links
1361556Srgrimes	 */
13776351Skris	(void)fprintf(fp, "%s %s", f_date, arcn->name);
1381556Srgrimes	if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
13976351Skris		(void)fprintf(fp, " == %s\n", arcn->ln_name);
1401556Srgrimes	else if (arcn->type == PAX_SLK)
14176351Skris		(void)fprintf(fp, " => %s\n", arcn->ln_name);
1421556Srgrimes	else
14376351Skris		(void)putc('\n', fp);
14476351Skris	(void)fflush(fp);
1451556Srgrimes	return;
1461556Srgrimes}
1471556Srgrimes
1481556Srgrimes/*
1491556Srgrimes * tty_ls()
1501556Srgrimes * 	print a short summary of file to tty.
1511556Srgrimes */
1521556Srgrimes
1531556Srgrimesvoid
15490113Simpls_tty(ARCHD *arcn)
1551556Srgrimes{
1561556Srgrimes	char f_date[DATELEN];
1571556Srgrimes	char f_mode[MODELEN];
158114583Smarkm	const char *timefrmt;
1591556Srgrimes
16074567Sache	if (d_first < 0)
16174567Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
16274567Sache
16376017Skris	if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL))
16474567Sache		timefrmt = d_first ? OLDFRMTD : OLDFRMTM;
16573345Sru	else
16674567Sache		timefrmt = d_first ? CURFRMTD : CURFRMTM;
1671556Srgrimes
1681556Srgrimes	/*
1691556Srgrimes	 * convert time to string, and print
1701556Srgrimes	 */
1711556Srgrimes	if (strftime(f_date, DATELEN, timefrmt,
1721556Srgrimes	    localtime(&(arcn->sb.st_mtime))) == 0)
1731556Srgrimes		f_date[0] = '\0';
1741556Srgrimes	strmode(arcn->sb.st_mode, f_mode);
1751556Srgrimes	tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
1761556Srgrimes	return;
1771556Srgrimes}
1781556Srgrimes
1791556Srgrimes/*
1801556Srgrimes * l_strncpy()
18176351Skris *	copy src to dest up to len chars (stopping at first '\0').
18276351Skris *	when src is shorter than len, pads to len with '\0'.
1831556Srgrimes * Return:
1841556Srgrimes *	number of chars copied. (Note this is a real performance win over
18576351Skris *	doing a strncpy(), a strlen(), and then a possible memset())
1861556Srgrimes */
1871556Srgrimes
1881556Srgrimesint
189114583Smarkml_strncpy(char *dest, const char *src, int len)
1901556Srgrimes{
19190113Simp	char *stop;
19290113Simp	char *start;
1931556Srgrimes
1941556Srgrimes	stop = dest + len;
1951556Srgrimes	start = dest;
1961556Srgrimes	while ((dest < stop) && (*src != '\0'))
1971556Srgrimes		*dest++ = *src++;
19876351Skris	len = dest - start;
19976351Skris	while (dest < stop)
20076351Skris		*dest++ = '\0';
20176351Skris	return(len);
2021556Srgrimes}
2031556Srgrimes
2041556Srgrimes/*
2051556Srgrimes * asc_ul()
2061556Srgrimes *	convert hex/octal character string into a u_long. We do not have to
2071556Srgrimes *	check for overflow! (the headers in all supported formats are not large
2081556Srgrimes *	enough to create an overflow).
2091556Srgrimes *	NOTE: strings passed to us are NOT TERMINATED.
2101556Srgrimes * Return:
2111556Srgrimes *	unsigned long value
2121556Srgrimes */
2131556Srgrimes
2141556Srgrimesu_long
21590113Simpasc_ul(char *str, int len, int base)
2161556Srgrimes{
21790113Simp	char *stop;
2181556Srgrimes	u_long tval = 0;
2191556Srgrimes
2201556Srgrimes	stop = str + len;
2211556Srgrimes
2221556Srgrimes	/*
2231556Srgrimes	 * skip over leading blanks and zeros
2241556Srgrimes	 */
2251556Srgrimes	while ((str < stop) && ((*str == ' ') || (*str == '0')))
2261556Srgrimes		++str;
2271556Srgrimes
2281556Srgrimes	/*
2291556Srgrimes	 * for each valid digit, shift running value (tval) over to next digit
2301556Srgrimes	 * and add next digit
2311556Srgrimes	 */
2321556Srgrimes	if (base == HEX) {
2331556Srgrimes		while (str < stop) {
2341556Srgrimes			if ((*str >= '0') && (*str <= '9'))
2351556Srgrimes				tval = (tval << 4) + (*str++ - '0');
2361556Srgrimes			else if ((*str >= 'A') && (*str <= 'F'))
2371556Srgrimes				tval = (tval << 4) + 10 + (*str++ - 'A');
2381556Srgrimes			else if ((*str >= 'a') && (*str <= 'f'))
2391556Srgrimes				tval = (tval << 4) + 10 + (*str++ - 'a');
2401556Srgrimes			else
2411556Srgrimes				break;
2421556Srgrimes		}
2431556Srgrimes	} else {
2441556Srgrimes 		while ((str < stop) && (*str >= '0') && (*str <= '7'))
2451556Srgrimes			tval = (tval << 3) + (*str++ - '0');
2461556Srgrimes	}
2471556Srgrimes	return(tval);
2481556Srgrimes}
2491556Srgrimes
2501556Srgrimes/*
2511556Srgrimes * ul_asc()
2521556Srgrimes *	convert an unsigned long into an hex/oct ascii string. pads with LEADING
2531556Srgrimes *	ascii 0's to fill string completely
2541556Srgrimes *	NOTE: the string created is NOT TERMINATED.
2551556Srgrimes */
2561556Srgrimes
2571556Srgrimesint
25890113Simpul_asc(u_long val, char *str, int len, int base)
2591556Srgrimes{
26090113Simp	char *pt;
2611556Srgrimes	u_long digit;
2628855Srgrimes
2631556Srgrimes	/*
2641556Srgrimes	 * WARNING str is not '\0' terminated by this routine
2651556Srgrimes	 */
2661556Srgrimes	pt = str + len - 1;
2671556Srgrimes
2681556Srgrimes	/*
2691556Srgrimes	 * do a tailwise conversion (start at right most end of string to place
2701556Srgrimes	 * least significant digit). Keep shifting until conversion value goes
2711556Srgrimes	 * to zero (all digits were converted)
2721556Srgrimes	 */
2731556Srgrimes	if (base == HEX) {
2741556Srgrimes		while (pt >= str) {
2751556Srgrimes			if ((digit = (val & 0xf)) < 10)
2761556Srgrimes				*pt-- = '0' + (char)digit;
2778855Srgrimes			else
2781556Srgrimes				*pt-- = 'a' + (char)(digit - 10);
2791556Srgrimes			if ((val = (val >> 4)) == (u_long)0)
2801556Srgrimes				break;
2811556Srgrimes		}
2821556Srgrimes	} else {
2831556Srgrimes		while (pt >= str) {
2841556Srgrimes			*pt-- = '0' + (char)(val & 0x7);
2851556Srgrimes			if ((val = (val >> 3)) == (u_long)0)
2861556Srgrimes				break;
2871556Srgrimes		}
2881556Srgrimes	}
2891556Srgrimes
2901556Srgrimes	/*
2911556Srgrimes	 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
2921556Srgrimes	 */
2931556Srgrimes	while (pt >= str)
2941556Srgrimes		*pt-- = '0';
2951556Srgrimes	if (val != (u_long)0)
2961556Srgrimes		return(-1);
2971556Srgrimes	return(0);
2981556Srgrimes}
2991556Srgrimes
3001556Srgrimes#ifndef NET2_STAT
3011556Srgrimes/*
3021556Srgrimes * asc_uqd()
3031556Srgrimes *	convert hex/octal character string into a u_quad_t. We do not have to
3041556Srgrimes *	check for overflow! (the headers in all supported formats are not large
3051556Srgrimes *	enough to create an overflow).
3061556Srgrimes *	NOTE: strings passed to us are NOT TERMINATED.
3071556Srgrimes * Return:
3081556Srgrimes *	u_quad_t value
3091556Srgrimes */
3101556Srgrimes
3111556Srgrimesu_quad_t
31290113Simpasc_uqd(char *str, int len, int base)
3131556Srgrimes{
31490113Simp	char *stop;
3151556Srgrimes	u_quad_t tval = 0;
3161556Srgrimes
3171556Srgrimes	stop = str + len;
3181556Srgrimes
3191556Srgrimes	/*
3201556Srgrimes	 * skip over leading blanks and zeros
3211556Srgrimes	 */
3221556Srgrimes	while ((str < stop) && ((*str == ' ') || (*str == '0')))
3231556Srgrimes		++str;
3241556Srgrimes
3251556Srgrimes	/*
3261556Srgrimes	 * for each valid digit, shift running value (tval) over to next digit
3271556Srgrimes	 * and add next digit
3281556Srgrimes	 */
3291556Srgrimes	if (base == HEX) {
3301556Srgrimes		while (str < stop) {
3311556Srgrimes			if ((*str >= '0') && (*str <= '9'))
3321556Srgrimes				tval = (tval << 4) + (*str++ - '0');
3331556Srgrimes			else if ((*str >= 'A') && (*str <= 'F'))
3341556Srgrimes				tval = (tval << 4) + 10 + (*str++ - 'A');
3351556Srgrimes			else if ((*str >= 'a') && (*str <= 'f'))
3361556Srgrimes				tval = (tval << 4) + 10 + (*str++ - 'a');
3371556Srgrimes			else
3381556Srgrimes				break;
3391556Srgrimes		}
3401556Srgrimes	} else {
3411556Srgrimes 		while ((str < stop) && (*str >= '0') && (*str <= '7'))
3421556Srgrimes			tval = (tval << 3) + (*str++ - '0');
3431556Srgrimes	}
3441556Srgrimes	return(tval);
3451556Srgrimes}
3461556Srgrimes
3471556Srgrimes/*
3481556Srgrimes * uqd_asc()
3491556Srgrimes *	convert an u_quad_t into a hex/oct ascii string. pads with LEADING
3501556Srgrimes *	ascii 0's to fill string completely
3511556Srgrimes *	NOTE: the string created is NOT TERMINATED.
3521556Srgrimes */
3531556Srgrimes
3541556Srgrimesint
35590113Simpuqd_asc(u_quad_t val, char *str, int len, int base)
3561556Srgrimes{
35790113Simp	char *pt;
3581556Srgrimes	u_quad_t digit;
3598855Srgrimes
3601556Srgrimes	/*
3611556Srgrimes	 * WARNING str is not '\0' terminated by this routine
3621556Srgrimes	 */
3631556Srgrimes	pt = str + len - 1;
3641556Srgrimes
3651556Srgrimes	/*
3661556Srgrimes	 * do a tailwise conversion (start at right most end of string to place
3671556Srgrimes	 * least significant digit). Keep shifting until conversion value goes
3681556Srgrimes	 * to zero (all digits were converted)
3691556Srgrimes	 */
3701556Srgrimes	if (base == HEX) {
3711556Srgrimes		while (pt >= str) {
3721556Srgrimes			if ((digit = (val & 0xf)) < 10)
3731556Srgrimes				*pt-- = '0' + (char)digit;
3748855Srgrimes			else
3751556Srgrimes				*pt-- = 'a' + (char)(digit - 10);
3761556Srgrimes			if ((val = (val >> 4)) == (u_quad_t)0)
3771556Srgrimes				break;
3781556Srgrimes		}
3791556Srgrimes	} else {
3801556Srgrimes		while (pt >= str) {
3811556Srgrimes			*pt-- = '0' + (char)(val & 0x7);
3821556Srgrimes			if ((val = (val >> 3)) == (u_quad_t)0)
3831556Srgrimes				break;
3841556Srgrimes		}
3851556Srgrimes	}
3861556Srgrimes
3871556Srgrimes	/*
3881556Srgrimes	 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
3891556Srgrimes	 */
3901556Srgrimes	while (pt >= str)
3911556Srgrimes		*pt-- = '0';
3921556Srgrimes	if (val != (u_quad_t)0)
3931556Srgrimes		return(-1);
3941556Srgrimes	return(0);
3951556Srgrimes}
3961556Srgrimes#endif
397