diff -ruN star-1.3.1/star/Makefile star-1.4/star/Makefile --- star-1.3.1/star/Makefile Sun Nov 14 18:22:25 1999 +++ star-1.4/star/Makefile Mon Jan 14 21:00:40 2002 @@ -10,15 +10,20 @@ HARDLINKS= ustar CPPOPTS += -DSET_CTIME -DFIFO -DUSE_MMAP -DUSE_REMOTE #CPPOPTS += -DFIFO -DUSE_MMAP -CFILES= star.c header.c list.c extract.c create.c append.c diff.c \ - star_unix.c \ +CPPOPTS += -DUSE_LARGEFILES +CPPOPTS += -DUSE_ACL +CPPOPTS += -DUSE_FFLAGS +CFILES= star.c header.c xheader.c \ + list.c extract.c create.c append.c diff.c \ + remove.c star_unix.c acl_unix.c fflags.c \ buffer.c dirtime.c lhash.c \ hole.c longnames.c names.c remote.c \ - table.c props.c \ + movearch.c table.c props.c \ + unicode.c \ fifo.c device.c HFILES= star.h starsubs.h dirtime.h xutimes.h \ - table.h props.h fifo.h diff.h mtio.h -LIBS= -lschily $(LIB_SOCKET) + remote.h movearch.h table.h props.h fifo.h diff.h mtio.h +LIBS= -lschily $(LIB_ACL) $(LIB_SOCKET) XMK_FILE= Makefile.man ########################################################################### diff -ruN star-1.3.1/star/acl_unix.c star-1.4/star/acl_unix.c --- star-1.3.1/star/acl_unix.c Thu Jan 1 01:00:00 1970 +++ star-1.4/star/acl_unix.c Sat Apr 20 20:13:47 2002 @@ -0,0 +1,827 @@ +/* @(#)acl_unix.c 1.8 02/04/20 Copyright 2001 J. Schilling */ +#ifndef lint +static char sccsid[] = + "@(#)acl_unix.c 1.8 02/04/20 Copyright 2001 J. Schilling"; +#endif +/* + * ACL get and set routines for unix like operating systems. + * + * Copyright (c) 2001 J. Schilling + * + * This implementation currently supports POSIX.1e and Solaris ACLs. + * Thanks to Andreas Gruenbacher for the first POSIX ACL + * implementation. + * + * As True64 does not like ACL "mask" entries and this version of the + * ACL code does not generate "mask" entries on True64, ACl support for + * True64 is currently broken. You cannot read back archives created + * on true64. + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#ifdef USE_ACL +/* + * HAVE_ANY_ACL currently includes HAVE_POSIX_ACL and HAVE_SUN_ACL. + * This definition must be in sync with the definition in star_unix.c + * As USE_ACL is used in star.h, we are not allowed to change the + * value of USE_ACL before we did include star.h or we may not include + * star.h at all. + * HAVE_HP_ACL is currently not included in HAVE_ANY_ACL. + */ +# ifndef HAVE_ANY_ACL +# undef USE_ACL /* Do not try to get or set ACLs */ +# endif +#endif + +#ifdef USE_ACL +#include +#include +#include "star.h" +#include "props.h" +#include "table.h" +#include +#include /* Needed for Solaris ACL code (malloc/free) */ +#include +#include +#include +#include +#include +#include "starsubs.h" + +#ifdef HAVE_SYS_ACL_H +# include +#endif + +#define ROOT_UID 0 + +extern int uid; +extern BOOL nochown; +extern BOOL numeric; + +/* + * XXX acl_access_text/acl_default_text are a bad idea. (see xheader.c) + * XXX Note that in 'dirmode' dir ACLs get hosed because getinfo() is + * XXX called for the directory before the directrory content is written + * XXX and the directory itself is archived after the dir content. + */ +LOCAL char acl_access_text[PATH_MAX+1]; +LOCAL char acl_default_text[PATH_MAX+1]; + +EXPORT BOOL get_acls __PR((FINFO *info)); +EXPORT void set_acls __PR((FINFO *info)); + +#ifdef HAVE_POSIX_ACL +LOCAL BOOL acl_to_info __PR((char *name, int type, char *acltext)); +LOCAL BOOL acl_add_ids __PR((char *infotext, char *acltext)); +#endif + +#ifdef HAVE_SUN_ACL +LOCAL char *acl_add_ids __PR((char *dst, char *from, char *end, int *sizep)); +#endif + +LOCAL char *base_acl __PR((int mode)); +LOCAL void acl_check_ids __PR((char *acltext, char *infotext)); + + +#ifdef HAVE_POSIX_ACL + +/* + * Get the access control list for a file and convert it into the format used by star. + */ +EXPORT BOOL +get_acls(info) + register FINFO *info; +{ + info->f_acl_access = NULL; + info->f_acl_default = NULL; + + /* + * Symlinks don't have ACLs + */ + if (is_symlink(info)) + return (TRUE); + + if (!acl_to_info(info->f_name, ACL_TYPE_ACCESS, acl_access_text)) + return (FALSE); + if (*acl_access_text != '\0') { + info->f_xflags |= XF_ACL_ACCESS; + info->f_acl_access = acl_access_text; + } + if (!is_dir(info)) + return (TRUE); + if (!acl_to_info(info->f_name, ACL_TYPE_DEFAULT, acl_default_text)) + return (FALSE); + if (*acl_default_text != '\0') { + info->f_xflags |= XF_ACL_DEFAULT; + info->f_acl_default = acl_default_text; + } + return (TRUE); +} + +LOCAL BOOL +acl_to_info(name, type, acltext) + char *name; + int type; + char *acltext; +{ + acl_t acl; + char *text, *c; + int entries = 1; + + acltext[0] = '\0'; + if ((acl = acl_get_file(name, type)) == NULL) { + register int err = geterrno(); +#ifdef ENOTSUP + /* + * This FS does not support ACLs. + */ + if (err == ENOTSUP) + return (TRUE); +#endif +#ifdef ENOSYS + if (err == ENOSYS) + return (TRUE); +#endif + errmsg("Cannot get %sACL for '%s'.\n", + type==ACL_TYPE_DEFAULT?"default ":"", name); + xstats.s_getaclerrs++; + return (FALSE); + } + seterrno(0); + text = acl_to_text(acl, NULL); + acl_free(acl); + if (text == NULL) { + if (geterrno() == 0) + seterrno(EX_BAD); + errmsg("Cannot convert %sACL entries to text for '%s'.\n", + type==ACL_TYPE_DEFAULT?"default ":"", name); + xstats.s_badacl++; + return (FALSE); + } + + /* remove trailing newlines */ + c = strrchr(text, '\0'); + while (c > text && *(c-1) == '\n') + *(--c) = '\0'; + + /* count fields */ + for (c = text; *c != '\0'; c++) { + if (*c == '\n') { + *c = ','; + entries++; + } + } + if (entries > 3) { /* > 4 on Solaris? */ + if (!acl_add_ids(acltext, text)) { + acl_free((acl_t)text); + return (FALSE); + } + } + /* + * XXX True64 prints a compile time warning when we use + * XXX acl_free(text) but it is standard... + * XXX we need to check whether we really have to call + * XXX free() instead of acl_free() if we are on True64. + * XXX Cast the string to acl_t to supress the warning. + */ +/* free(text);*/ + acl_free((acl_t)text); + return (TRUE); +} + +LOCAL BOOL +acl_add_ids(infotext, acltext) + char *infotext; + char *acltext; +{ + int size = PATH_MAX; + int len; + char *token; + Ulong id; + + /* + * Add final nul to guarantee that the string is nul terminated. + */ + infotext[PATH_MAX] = '\0'; + + token = strtok(acltext, ", \t\n\r"); + while (token) { + strncpy(infotext, token, size); + infotext += strlen(token); + size -= strlen(token); + if (size < 0) + size = 0; + + if (!strncmp(token, "user:", 5) && + !strchr(":, \t\n\r", token[5])) { + char *username = &token[5], *c = username+1; + + while (!strchr(":, \t\n\r", *c)) + c++; + *c = '\0'; + /* check for all-numeric user name */ + while (c > username && isdigit(*(c-1))) + c--; + if (c > username && + uidname(username, c-username, &id)) { + len = js_snprintf(infotext, size, + ":%ld", id); + infotext += len; + size -= len; + } + } else if (!strncmp(token, "group:", 6) && + !strchr(":, \t\n\r", token[6])) { + char *groupname = &token[6], *c = groupname+1; + + while (!strchr(":, \t\n\r", *c)) + c++; + *c = '\0'; + /* check for all-numeric group name */ + while (c > groupname && isdigit(*(c-1))) + c--; + if (c > groupname && + gidname(groupname, c-groupname, &id)) { + len = js_snprintf(infotext, size, + ":%ld", id); + infotext += len; + size -= len; + } + } + if (size > 0) { + *infotext++ = ','; + size--; + } + + token = strtok(NULL, ", \t\n\r"); + } + if (size >= 0) { + *(--infotext) = '\0'; + } else { + errmsgno(EX_BAD, "Cannot convert ACL entries (string too long).\n"); + xstats.s_badacl++; + return (FALSE); + } + return (TRUE); +} + +/* + * Use ACL info from archive to set access control list for the file if needed. + */ +EXPORT void +set_acls(info) + register FINFO *info; +{ + char acltext[PATH_MAX+1]; + acl_t acl; + + if (info->f_xflags & XF_ACL_ACCESS) { + acl_check_ids(acltext, info->f_acl_access); + } else { + /* + * We may need to delete an inherited ACL. + */ + strcpy(acltext, base_acl(info->f_mode)); + } + if ((acl = acl_from_text(acltext)) == NULL) { + errmsg("Cannot convert ACL '%s' to internal format for '%s'.\n", + acltext, info->f_name); + xstats.s_badacl++; + } else { + if (acl_set_file(info->f_name, ACL_TYPE_ACCESS, acl) < 0) { + /* + * XXX What should we do if errno is ENOTSUP/ENOSYS? + */ + errmsg("Cannot set ACL '%s' for '%s'.\n", + acltext, info->f_name); + xstats.s_setacl++; + + /* Fall back to chmod */ +/* XXX chmod has already been done! */ +/* chmod(info->f_name, (int)info->f_mode);*/ + } + acl_free(acl); + } + + /* + * Only directories can have Default ACLs + */ + if (!is_dir(info)) + return; + + if (info->f_xflags & XF_ACL_DEFAULT) { + acl_check_ids(acltext, info->f_acl_default); + } else { + acltext[0] = '\0'; +#ifdef HAVE_ACL_DELETE_DEF_FILE + /* + * FreeBSD does not like acl_from_text("") + */ + if (acl_delete_def_file(info->f_name) < 0) { + /* + * XXX What should we do if errno is ENOTSUP/ENOSYS? + */ + errmsg("Cannot remove default ACL from '%s'.\n", info->f_name); + xstats.s_setacl++; + } + return; +#endif + } + if ((acl = acl_from_text(acltext)) == NULL) { + errmsg("Cannot convert default ACL '%s' to internal format for '%s'.\n", + acltext, info->f_name); + xstats.s_badacl++; + } else { + if (acl_set_file(info->f_name, ACL_TYPE_DEFAULT, acl) < 0) { + /* + * XXX What should we do if errno is ENOTSUP/ENOSYS? + */ + errmsg("Cannot set default ACL '%s' for '%s'.\n", + acltext, info->f_name); + xstats.s_setacl++; + } + acl_free(acl); + } +} + +#endif /* HAVE_POSIX_ACL */ + +#ifdef HAVE_SUN_ACL /* Solaris */ + +/* + * Get the access control list for a file and convert it into the format used by star. + */ +EXPORT BOOL +get_acls(info) + register FINFO *info; +{ + int aclcount; + aclent_t *aclp; + register char *acltext; + register char *ap; + register char *dp; + register char *cp; + register char *ep; + int asize; + int dsize; + + info->f_acl_access = NULL; + info->f_acl_default = NULL; + + /* + * Symlinks don't have ACLs + */ + if (is_symlink(info)) + return (TRUE); + + if ((aclcount = acl(info->f_name, GETACLCNT, 0, NULL)) < 0) { + errmsg("Cannot get ACL count for '%s'.\n", info->f_name); + xstats.s_getaclerrs++; + return (FALSE); + } +#ifdef ACL_DEBUG + error("'%s' acl count %d\n", info->f_name, aclcount); +#endif + if (aclcount <= MIN_ACL_ENTRIES) { + /* + * This file has only the traditional UNIX access list. + * This case includes a filesystem that does not support ACLs + * like the tmpfs. + */ + return (TRUE); + } + if ((aclp = (aclent_t *)malloc(sizeof(aclent_t) * aclcount)) == NULL) { + errmsg("Cannot malloc ACL buffer for '%s'.\n", info->f_name); + xstats.s_getaclerrs++; + return (FALSE); + } + if (acl(info->f_name, GETACL, aclcount, aclp) < 0) { + errmsg("Cannot get ACL entries for '%s'.\n", info->f_name); + xstats.s_getaclerrs++; + return (FALSE); + } + seterrno(0); + acltext = acltotext(aclp, aclcount); + free(aclp); + if (acltext == NULL) { + if (geterrno() == 0) + seterrno(EX_BAD); + errmsg("Cannot convert ACL entries to text for '%s'.\n", info->f_name); + xstats.s_badacl++; + return (FALSE); + } +#ifdef ACL_DEBUG + error("acltext '%s'\n", acltext); +#endif + + ap = acl_access_text; + dp = acl_default_text; + asize = PATH_MAX; + dsize = PATH_MAX; + + for (cp = acltext; *cp; cp = ep) { + if (*cp == ',') + cp++; + ep = strchr(cp, ','); + if (ep == NULL) + ep = strchr(cp, '\0'); + + if (*cp == 'd' && strncmp(cp, "default", 7) == 0) { + cp += 7; + dp = acl_add_ids(dp, cp, ep, &dsize); + if (dp == NULL) + break; + } else { + ap = acl_add_ids(ap, cp, ep, &asize); + if (ap == NULL) + break; + } + } + if (ap == NULL || dp == NULL) { + acl_access_text[0] = '\0'; + acl_default_text[0] = '\0'; + errmsgno(EX_BAD, "Cannot convert ACL entries (string too long).\n"); + xstats.s_badacl++; + return (FALSE); + } + + if (ap > acl_access_text && ap[-1] == ',') + --ap; + *ap = '\0'; + if (dp > acl_default_text && dp[-1] == ',') + --dp; + *dp = '\0'; + + if (*acl_access_text != '\0') { + info->f_xflags |= XF_ACL_ACCESS; + info->f_acl_access = acl_access_text; + } + if (*acl_default_text != '\0') { + info->f_xflags |= XF_ACL_DEFAULT; + info->f_acl_default = acl_default_text; + } + +#ifdef ACL_DEBUG +error("access: '%s'\n", acl_access_text); +error("default: '%s'\n", acl_default_text); +#endif + + return (TRUE); +} + +/* + * Convert Solaris ACL text into POSIX ACL text and add numerical user/group + * ids. + * + * Solaris uses only one colon in the ACL text format for "other" and "mask". + * Solaris ACL text is: "user::rwx,group::rwx,mask:rwx,other:rwx" + * while POSIX text is: "user::rwx,group::rwx,mask::rwx,other::rwx" + */ +LOCAL char * +acl_add_ids(dst, from, end, sizep) + char *dst; + char *from; + char *end; + int *sizep; +{ + register char *cp = from; + register char *ep = end; + register char *np = dst; + register int size = *sizep; + register int amt; + Ulong id; + + if (cp[0] == 'u' && + strncmp(cp, "user:", 5) == 0) { + if (size <= (ep - cp +1)) { + *sizep = 0; + return (NULL); + } + size -= ep - cp +1; + strncpy(np, cp, ep - cp +1); + np += ep - cp + 1; + + cp += 5; + ep = strchr(cp, ':'); + if (ep) + *ep = '\0'; + if (*cp) { + if (uidname(cp, 1000, &id)) { + if (np[-1] == ',') { + --np; + size++; + } + amt = js_snprintf(np, size, + ":%ld,", id); + np += amt; + size -= amt; + } + } + if (ep) + *ep = ':'; + + } else if (cp[0] == 'g' && + strncmp(cp, "group:", 6) == 0) { + if (size <= (ep - cp +1)) { + *sizep = 0; + return (NULL); + } + size -= ep - cp +1; + strncpy(np, cp, ep - cp + 1); + np += ep - cp + 1; + + cp += 6; + ep = strchr(cp, ':'); + if (ep) + *ep = '\0'; + if (*cp) { + if (gidname(cp, 1000, &id)) { + if (np[-1] == ',') { + --np; + size++; + } + amt = js_snprintf(np, size, + ":%ld,", id); + np += amt; + size -= amt; + } + } + if (ep) + *ep = ':'; + + } else if (cp[0] == 'm' && + strncmp(cp, "mask:", 5) == 0) { + cp += 4; + if (size < 5) { + *sizep = 0; + return (NULL); + } + /* + * Add one additional ':' to the string for POSIX compliance. + */ + strcpy(np, "mask:"); + np += 5; + if (size <= (ep - cp +1)) { + *sizep = 0; + return (NULL); + } + strncpy(np, cp, ep - cp + 1); + np += ep - cp + 1; + + } else if (cp[0] == 'o' && + strncmp(cp, "other:", 6) == 0) { + cp += 5; + if (size < 6) { + *sizep = 0; + return (NULL); + } + /* + * Add one additional ':' to the string for POSIX compliance. + */ + strcpy(np, "other:"); + np += 6; + if (size <= (ep - cp +1)) { + *sizep = 0; + return (NULL); + } + strncpy(np, cp, ep - cp + 1); + np += ep - cp + 1; + } + if (size <= 0) { + size = 0; + np = NULL; + } + *sizep = size; + return (np); +} + +/* + * Convert ACL info from archive into Sun's format and set access control list + * for the file if needed. + */ +EXPORT void +set_acls(info) + register FINFO *info; +{ + int aclcount; + aclent_t *aclp; + char acltext[PATH_MAX+1]; + char aclbuf[8192]; + + aclbuf[0] = '\0'; + if (info->f_xflags & XF_ACL_ACCESS) { + acl_check_ids(aclbuf, info->f_acl_access); + } + if (info->f_xflags & XF_ACL_DEFAULT) { + register char *cp; + register char *dp; + register char *ep; + + acl_check_ids(acltext, info->f_acl_default); + + dp = aclbuf + strlen(aclbuf); + if (dp > aclbuf) + *dp++ = ','; + for (cp = acltext; *cp; cp = ep) { + /* + * XXX Eigentlich muesste man hier bei den Eintraegen + * XXX "mask" und "other" jeweils ein ':' beseitigten + * XXX aber es sieht so aus, als ob es bei Solaris 9 + * XXX auch funktionert wenn man das nicht tut. + * XXX Nach Solaris 7 "libsec" Source kann es nicht + * XXX mehr funktionieren wenn man das ':' beseitigt. + * XXX Moeglicherweise ist das der Grund warum + * XXX Solaris immer Probleme mit den ACLs hatte. + */ + if (*cp == ',') + cp++; + ep = strchr(cp, ','); + if (ep == NULL) + ep = strchr(cp, '\0'); + strcpy(dp, "default"); + dp += 7; + strncpy(dp, cp, ep - cp + 1); + dp += ep - cp + 1; + } + } +#ifdef ACL_DEBUG + error("aclbuf: '%s'\n", aclbuf); +#endif + + if (aclbuf[0] == '\0') { + /* + * We may need to delete an inherited ACL. + */ + strcpy(aclbuf, base_acl(info->f_mode)); + } + + seterrno(0); + if ((aclp = aclfromtext(aclbuf, &aclcount)) == NULL) { + if (geterrno() == 0) + seterrno(EX_BAD); + errmsg("Cannot convert ACL '%s' to internal format for '%s'.\n", + aclbuf, info->f_name); + xstats.s_badacl++; + } else { + if (acl(info->f_name, SETACL, aclcount, aclp) < 0) { + /* + * XXX What should we do if errno is ENOSYS? + */ + errmsg("Cannot set ACL '%s' for '%s'.\n", + aclbuf, info->f_name); + xstats.s_setacl++; + } + free(aclp); + } +} + +#endif /* HAVE_SUN_ACL Solaris */ + + +/* + * Convert UNIX sdtandard mode bits into base ACL + */ +LOCAL char * +base_acl(mode) + int mode; +{ + static char _acltxt[] = "user::***,group::***,other::***"; + + _acltxt[ 6] = (mode & 0400) ? 'r' : '-'; + _acltxt[ 7] = (mode & 0200) ? 'w' : '-'; + _acltxt[ 8] = (mode & 0100) ? 'x' : '-'; + _acltxt[17] = (mode & 0040) ? 'r' : '-'; + _acltxt[18] = (mode & 0020) ? 'w' : '-'; + _acltxt[19] = (mode & 0010) ? 'x' : '-'; + _acltxt[28] = (mode & 0004) ? 'r' : '-'; + _acltxt[29] = (mode & 0002) ? 'w' : '-'; + _acltxt[30] = (mode & 0001) ? 'x' : '-'; + + return (_acltxt); +} + +/* + * If we are in -numeric mode, we replace the user and groups names by the + * user and group numbers from our internal format. + * + * If we are non non numeric mode, we check whether a user name or group name + * is present on our current system. It the user/group name is known, then we + * remove the numeric value from out internal format. If the user/group name + * is not known, then we replace the name by the numeric value. + */ +LOCAL void +acl_check_ids(acltext, infotext) + char *acltext; + char *infotext; +{ + char entry_buffer[PATH_MAX]; + char *token = strtok(infotext, ", \t\n\r"); + + if (!token) + return; + + while (token) { + + if (!strncmp(token, "user:", 5) && + !strchr(":, \t\n\r", token[5])) { + char *username = &token[5], *c = username+1; + char *perms, *auid; + Ulong dummy; + /* uidname does not check for NULL! */ + + /* user name */ + while (!strchr(":, \t\n\r", *c)) + c++; + if (*c) + *c++ = '\0'; + + /* permissions */ + perms = c; + while (!strchr(":, \t\n\r", *c)) + c++; + if (*c) + *c++ = '\0'; + + /* identifier */ + auid = c; + while (!strchr(":, \t\n\r", *c)) + c++; + if (*c) + *c++ = '\0'; + + /* + * XXX We use strlen(username)+1 to tell uidname not + * XXX to stop comparing before the end of the + * XXX username has been reached. Otherwise "joe" and + * XXX "joeuser" would be compared as identical. + */ + if (*auid && (numeric || + !uidname(username, strlen(username)+1, &dummy))) + username = auid; + js_snprintf(entry_buffer, PATH_MAX, "user:%s:%s", + username, perms); + token = entry_buffer; + + } else if (!strncmp(token, "group:", 6) && + !strchr(":, \t\n\r", token[6])) { + char *groupname = &token[6], *c = groupname+1; + char *perms, *agid; + Ulong dummy; + /* gidname does not check for NULL! */ + + /* group name */ + while (!strchr(":, \t\n\r", *c)) + c++; + if (*c) + *c++ = '\0'; + + /* permissions */ + perms = c; + while (!strchr(":, \t\n\r", *c)) + c++; + if (*c) + *c++ = '\0'; + + /* identifier */ + agid = c; + while (!strchr(":, \t\n\r", *c)) + c++; + if (*c) + *c++ = '\0'; + + /* + * XXX We use strlen(groupname)+1 to tell gidname not + * XXX to stop comparing before the end of the + * XXX groupname has been reached. Otherwise "joe" and + * XXX "joeuser" would be compared as identical. + */ + if (*agid && (numeric || + !gidname(groupname, strlen(groupname)+1, &dummy))) + groupname = agid; + js_snprintf(entry_buffer, PATH_MAX, "group:%s:%s", + groupname, perms); + token = entry_buffer; + } + strcpy(acltext, token); + acltext += strlen(token); + + token = strtok(NULL, ", \t\n\r"); + } + *(--acltext) = '\0'; +} + +#endif /* USE_ACL */ diff -ruN star-1.3.1/star/append.c star-1.4/star/append.c --- star-1.3.1/star/append.c Sat Apr 7 11:06:03 2001 +++ star-1.4/star/append.c Fri May 17 11:26:29 2002 @@ -1,13 +1,13 @@ -/* @(#)append.c 1.12 01/04/07 Copyright 1992 J. Schilling */ +/* @(#)append.c 1.17 02/05/17 Copyright 1992, 2001 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)append.c 1.12 01/04/07 Copyright 1992 J. Schilling"; + "@(#)append.c 1.17 02/05/17 Copyright 1992, 2001 J. Schilling"; #endif /* * Routines used to append files to an existing * tape archive * - * Copyright (c) 1992 J. Schilling + * Copyright (c) 1992, 2001 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify @@ -27,11 +27,14 @@ #include #include +#include #include -#include #include "star.h" +#include #include "starsubs.h" +extern FILE *vpr; + extern BOOL debug; extern BOOL cflag; extern BOOL uflag; @@ -42,16 +45,20 @@ */ static struct h_elem { struct h_elem *h_next; - Ulong h_time; + time_t h_time; + Ulong h_nsec; short h_len; + char h_flags; char h_data[1]; /* Variable size. */ } **h_tab; +#define HF_NSEC 0x01 /* have nsecs */ + static unsigned h_size; LOCAL int cachesize; EXPORT void skipall __PR((void)); -LOCAL void hash_new __PR((unsigned size)); +LOCAL void hash_new __PR((size_t size)); LOCAL struct h_elem * uhash_lookup __PR((FINFO *info)); LOCAL void hash_add __PR((FINFO *info)); EXPORT BOOL update_newer __PR((FINFO *info)); @@ -83,7 +90,7 @@ return; if (debug) - printf("R %s\n", finfo.f_name); + fprintf(vpr, "R %s\n", finfo.f_name); if (uflag) hash_add(&finfo); @@ -95,12 +102,12 @@ LOCAL void hash_new(size) - unsigned size; + size_t size; { register int i; h_size = size; - h_tab = (struct h_elem **)__malloc(size * sizeof (struct h_elem *)); + h_tab = (struct h_elem **)__malloc(size * sizeof (struct h_elem *), "new hash"); for (i=0; ih_time < info->f_mtime) + if (hp->h_time < info->f_mtime) { hp->h_time = info->f_mtime; + hp->h_nsec = info->f_mnsec; + } else if (hp->h_time == info->f_mtime) { + /* + * If the current archive entry holds extended + * time imformation, honor it. + */ + if (info->f_xflags & XF_MTIME) + hp->h_flags |= HF_NSEC; + else + hp->h_flags &= ~HF_NSEC; + + if ((hp->h_flags & HF_NSEC) && + (hp->h_nsec < info->f_mnsec)) + hp->h_nsec = info->f_mnsec; + } return; } len = strlen(info->f_name); - hp = __malloc((unsigned)len + sizeof (struct h_elem)); + hp = __malloc((size_t)len + sizeof (struct h_elem), "add hash"); cachesize += len + sizeof (struct h_elem); strcpy(hp->h_data, info->f_name); hp->h_time = info->f_mtime; + hp->h_nsec = info->f_mnsec; + hp->h_flags = 0; + if (info->f_xflags & XF_MTIME) + hp->h_flags |= HF_NSEC; hv = hashval((unsigned char *)info->f_name, h_size); hp->h_next = h_tab[hv]; h_tab[hv] = hp; @@ -156,10 +182,13 @@ register struct h_elem *hp; /* - * XXX nsec beachten wenn im Archiv! + * XXX nsec korrekt implementiert? */ if ((hp = uhash_lookup(info)) != 0) { if (info->f_mtime > hp->h_time) + return (TRUE); + if ((hp->h_flags & HF_NSEC) && (info->f_flags & F_NSECS) && + info->f_mtime == hp->h_time && info->f_mnsec > hp->h_nsec) return (TRUE); return (FALSE); } diff -ruN star-1.3.1/star/buffer.c star-1.4/star/buffer.c --- star-1.3.1/star/buffer.c Fri Apr 6 23:36:46 2001 +++ star-1.4/star/buffer.c Mon May 20 13:59:36 2002 @@ -1,12 +1,12 @@ -/* @(#)buffer.c 1.46 01/04/07 Copyright 1985, 1995 J. Schilling */ +/* @(#)buffer.c 1.73 02/05/20 Copyright 1985, 1995, 2001 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)buffer.c 1.46 01/04/07 Copyright 1985, 1995 J. Schilling"; + "@(#)buffer.c 1.73 02/05/20 Copyright 1985, 1995, 2001 J. Schilling"; #endif /* * Buffer handling routines * - * Copyright (c) 1985, 1995 J. Schilling + * Copyright (c) 1985, 1995, 2001 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify @@ -25,17 +25,21 @@ */ #include + +#if !defined(HAVE_NETDB_H) || !defined(HAVE_RCMD) +#undef USE_REMOTE /* There is no rcmd() */ +#endif + #include +#include +#include #include -#include #include #include #include "star.h" #include #include #include "fifo.h" -#include -#include #include #include #include @@ -53,6 +57,7 @@ char *bigbuf = NULL; char *bigptr = NULL; char *eofptr = NULL; +Llong curblockno; m_stats bstat; m_stats *stats = &bstat; @@ -66,15 +71,19 @@ LOCAL BOOL isremote = FALSE; LOCAL int remfd = -1; LOCAL char *remfn; -LOCAL char host[128]; extern FILE *tarf; extern FILE *tty; extern FILE *vpr; -extern char *tarfile; +extern char *tarfiles[]; +extern int ntarfiles; +extern int tarfindex; +LOCAL int lastremote = -1; +extern char *newvol_script; extern BOOL use_fifo; extern int swapflg; extern BOOL debug; +extern BOOL silent; extern BOOL showtime; extern BOOL no_stats; extern BOOL do_fifostats; @@ -103,6 +112,8 @@ LOCAL int readtblock __PR((char* buf, int amount)); LOCAL void readbuf __PR((void)); EXPORT int readtape __PR((char* buf, int amount)); +EXPORT void filltcb __PR((TCB *ptb)); +EXPORT void movetcb __PR((TCB *from_ptb, TCB *to_ptb)); EXPORT void *get_block __PR((void)); EXPORT void put_block __PR((void)); EXPORT void writeblock __PR((char* buf)); @@ -120,8 +131,8 @@ EXPORT void buf_resume __PR((void)); EXPORT void backtape __PR((void)); EXPORT int mtioctl __PR((int cmd, int count)); -EXPORT long mtseek __PR((long offset, int whence)); -EXPORT int tblocks __PR((void)); +EXPORT off_t mtseek __PR((off_t offset, int whence)); +EXPORT Llong tblocks __PR((void)); EXPORT void prstats __PR((void)); EXPORT BOOL checkerrs __PR((void)); EXPORT void exprstats __PR((int ret)); @@ -133,31 +144,38 @@ EXPORT BOOL openremote() { - register char *hp; - register char *fp; - register int i; + char host[128]; + char lasthost[128]; - if ((!nullout || (uflag || rflag)) && strchr(tarfile, ':')) { + if ((!nullout || (uflag || rflag)) && + (remfn = rmtfilename(tarfiles[tarfindex])) != NULL) { #ifdef USE_REMOTE isremote = TRUE; - remfn = strchr(tarfile, ':'); - for (fp = tarfile, hp = host, i = 1; - fp < remfn && i < sizeof(host); i++) { - *hp++ = *fp++; - } - *hp = '\0'; - remfn++; + rmtdebug(debug); + rmthostname(host, tarfiles[tarfindex], sizeof(host)); if (debug) errmsgno(EX_BAD, "Remote: %s Host: %s file: %s\n", - tarfile, host, remfn); + tarfiles[tarfindex], host, remfn); - if ((remfd = rmtgetconn(host, bigsize)) < 0) + if (lastremote >= 0) { + rmthostname(lasthost, tarfiles[lastremote], + sizeof(lasthost)); + if (!streql(host, lasthost)) { + close(remfd); + remfd = -1; + lastremote = -1; + } + } + if (remfd < 0 && (remfd = rmtgetconn(host, bigsize)) < 0) comerrno(EX_BAD, "Cannot get connection to '%s'.\n", /* errno not valid !! */ host); + lastremote = tarfindex; #else comerrno(EX_BAD, "Remote tape support not present.\n"); #endif + } else { + isremote = FALSE; } return (isremote); } @@ -166,16 +184,19 @@ opentape() { int n = 0; + extern dev_t tape_dev; + extern ino_t tape_ino; + extern BOOL tape_isreg; if (nullout && !(uflag || rflag)) { - tarfile = "null"; + tarfiles[tarfindex] = "null"; tarf = (FILE *)NULL; - } else if (streql(tarfile, "-")) { + } else if (streql(tarfiles[tarfindex], "-")) { if (cflag) { - tarfile = "stdout"; +/* tarfiles[tarfindex] = "stdout";*/ tarf = stdout; } else { - tarfile = "stdin"; +/* tarfiles[tarfindex] = "stdin";*/ tarf = stdin; multblk = TRUE; } @@ -192,13 +213,17 @@ * whether the current /etc/rmt server supports symbolic * open flags. If there is no symbolic support in the * remote server, our rmt client code will mask off all - * non portable bits. + * non portable bits. The remote rmt server defaults to + * O_BINARY as the client (we) may not know about O_BINARY. + * XXX Should we add an option that allows to specify O_TRUNC? */ while (rmtopen(remfd, remfn, (cflag ? O_RDWR|O_CREAT:O_RDONLY)|O_BINARY) < 0) { - if (!wready || n++ > 6 || geterrno() != EIO) - comerr("Cannot open remote '%s'.\n", tarfile); - else + if (!wready || n++ > 6 || geterrno() != EIO) { + comerr("Cannot open remote '%s'.\n", + tarfiles[tarfindex]); + } else { sleep(10); + } } #endif } else { @@ -215,21 +240,27 @@ * XXX What if we implement 'r' & 'u' ??? */ follow++; - n = getinfo(tarfile, &finfo); + n = getinfo(tarfiles[tarfindex], &finfo); follow--; - if (n >= 0 && is_file(&finfo) && finfo.f_size > 0L) { + if (n >= 0 && is_file(&finfo) && finfo.f_size > (off_t)0) { comerrno(EX_BAD, "Will not overwrite non empty plain files in compat mode.\n"); } } n = 0; - while ((tarf = fileopen(tarfile, cflag?"rwcub":"rub")) == + /* + * XXX Should we add an option that allows to specify O_TRUNC? + */ + while ((tarf = fileopen(tarfiles[tarfindex], + cflag?"rwcub":"rub")) == (FILE *)NULL) { - if (!wready || n++ > 6 || geterrno() != EIO) - comerr("Cannot open '%s'.\n", tarfile); - else + if (!wready || n++ > 6 || geterrno() != EIO) { + comerr("Cannot open '%s'.\n", + tarfiles[tarfindex]); + } else { sleep(10); + } } } if (!isremote && (!nullout || (uflag || rflag))) { @@ -238,12 +269,42 @@ } vpr = tarf == stdout ? stderr : stdout; + /* + * If the archive is a plain file and thus seekable + * do automatic compression detection. + */ + if (tape_isreg && !cflag && (!zflag && !bzflag)) { + long htype; + char zbuf[TBLOCK]; + TCB *ptb; + + readtblock(zbuf, TBLOCK); + ptb = (TCB *)zbuf; + htype = get_hdrtype(ptb, FALSE); + + if (htype == H_UNDEF) { + switch (get_compression(ptb)) { + + case C_GZIP: + if (!silent) errmsgno(EX_BAD, + "WARNING: Archive is compressed, trying to use the -z option.\n"); + zflag = TRUE; + break; + case C_BZIP2: + if (!silent) errmsgno(EX_BAD, + "WARNING: Archive is bzip2 compressed, trying to use the -bz option.\n"); + bzflag = TRUE; + break; + } + } + mtseek((off_t)0, SEEK_SET); + } if (zflag || bzflag) { - extern long tape_dev; - extern long tape_ino; - if (isremote) comerrno(EX_BAD, "Cannot compress remote archives (yet).\n"); + /* + * If both values are zero, this is a device and thus may be a tape. + */ if (tape_dev || tape_ino) compressopen(); else @@ -277,6 +338,7 @@ changetape() { char ans[2]; + int nextindex; prstats(); stats->Tblocks += stats->blocks; @@ -284,10 +346,32 @@ stats->blocks = 0L; stats->parts = 0L; closetape(); - errmsgno(EX_BAD, "Mount volume #%d and hit ", ++stats->volno); - fgetline(tty, ans, sizeof(ans)); - if (feof(tty)) - exit(1); + /* + * XXX Was passiert, wenn wir das 2. Mal bei einem Band vorbeikommen? + * XXX Zur Zeit wird gnadenlos ueberschrieben. + */ + nextindex = tarfindex + 1; + if (nextindex >= ntarfiles) + nextindex = 0; + /* + * XXX We need to add something like the -l & -o option from + * XXX ufsdump. + */ + if (newvol_script) { + /* + * XXX Sould we give the script volume # and volume name + * XXX as argument? + */ + system(newvol_script); + } else { + errmsgno(EX_BAD, "Mount volume #%d on '%s' and hit ", + ++stats->volno, tarfiles[nextindex]); + fgetline(tty, ans, sizeof(ans)); + if (feof(tty)) + exit(1); + } + tarfindex = nextindex; + openremote(); opentape(); } @@ -317,10 +401,10 @@ } else #endif { - if ((bigptr = bigbuf = malloc((unsigned) bufsize)) == NULL) - comerr("Cannot alloc buf.\n"); + bigptr = bigbuf = __malloc((size_t) bufsize, "buffer"); fillbytes(bigbuf, bufsize, '\0'); } + stats->nblocks = nblocks; stats->blocksize = bigsize; stats->volno = 1; stats->swapflg = -1; @@ -334,14 +418,17 @@ /* * Remember current FIFO status. */ + /* EMPTY */ } #endif eofptr = bigptr - TBLOCK; if (debug) { - error("Blocks: %d\n", tblocks()); - error("bigptr - bigbuff: %d %p %p %p lastsize: %ld\n", - bigptr - bigbuf, bigbuf, bigptr, eofptr, stats->lastsize); + error("Blocks: %lld\n", tblocks()); + error("bigptr - bigbuff: %lld %p %p %p lastsize: %ld\n", + (Llong)(bigptr - bigbuf), + (void *)bigbuf, (void *)bigptr, (void *)eofptr, + stats->lastsize); } } @@ -366,7 +453,7 @@ { if (buf_rwait(TBLOCK) == 0) return (EOF); - movebytes(bigptr, buf, TBLOCK); + movetcb((TCB *)bigptr, (TCB *)buf); buf_rwake(TBLOCK); return TBLOCK; } @@ -385,11 +472,11 @@ * isremote will always be FALSE if USE_REMOTE is not defined. */ if ((cnt = rmtread(remfd, buf, amount)) < 0) - excomerr("Error reading '%s'.\n", tarfile); + excomerr("Error reading '%s'.\n", tarfiles[tarfindex]); #endif } else { - if ((cnt = ffileread(tarf, buf, amount)) < 0) - excomerr("Error reading '%s'.\n", tarfile); + if ((cnt = _niread(fileno(tarf), buf, amount)) < 0) + excomerr("Error reading '%s'.\n", tarfiles[tarfindex]); } return (cnt); } @@ -427,7 +514,7 @@ return (amt); if (amt < TBLOCK) excomerrno(EX_BAD, "Error reading '%s' size (%d) too small.\n", - tarfile, amt); + tarfiles[tarfindex], amt); /* * First block */ @@ -480,6 +567,34 @@ } #endif +#define DO16(a) a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a; + +EXPORT void +filltcb(ptb) + register TCB *ptb; +{ + register int i; + register long *lp = ptb->ldummy; + + for (i=512/sizeof(long)/16; --i >= 0;) { + DO16(*lp++ = 0L) + } +} + +EXPORT void +movetcb(from_ptb, to_ptb) + register TCB *from_ptb; + register TCB *to_ptb; +{ + register int i; + register long *from = from_ptb->ldummy; + register long *to = to_ptb->ldummy; + + for (i=512/sizeof(long)/16; --i >= 0;) { + DO16(*to++ = *from++) + } +} + EXPORT void * get_block() { @@ -498,7 +613,7 @@ char *buf; { buf_wait(TBLOCK); - movebytes(buf, bigptr, TBLOCK); + movetcb((TCB *)buf, (TCB *)bigptr); buf_wake(TBLOCK); } @@ -519,7 +634,7 @@ cnt = rmtwrite(remfd, buf, amount); #endif } else { - cnt = ffilewrite(tarf, buf, amount); + cnt = _niwrite(fileno(tarf), buf, amount); } if (cnt == 0) { err = EFBIG; @@ -527,7 +642,7 @@ err = geterrno(); } if (cnt <= 0) - excomerrno(err, "Error writing '%s'.\n", tarfile); + excomerrno(err, "Error writing '%s'.\n", tarfiles[tarfindex]); if (cnt == stats->blocksize) stats->blocks++; @@ -566,10 +681,10 @@ EXPORT void writeempty() { - char buf[TBLOCK]; + TCB tb; - fillbytes(buf, TBLOCK, '\0'); - writeblock(buf); + filltcb(&tb); + writeblock((char *)&tb); } EXPORT void @@ -684,12 +799,13 @@ EXPORT void backtape() { - long ret; + Llong ret; if (debug) { - error("Blocks: %d\n", tblocks()); - error("filepos: %ld seeking to: %ld bigsize: %d\n", - mtseek(0L, SEEK_CUR), mtseek(0L, SEEK_CUR)-stats->lastsize, bigsize); + error("Blocks: %lld\n", tblocks()); + error("filepos: %lld seeking to: %lld bigsize: %d\n", + (Llong)mtseek((off_t)0, SEEK_CUR), + (Llong)mtseek((off_t)0, SEEK_CUR) - (Llong)stats->lastsize, bigsize); } if (mtioctl(MTNOP, 0) >= 0) { @@ -701,7 +817,7 @@ error("Is a file: lseek()\n"); ret = mtseek(-stats->lastsize, SEEK_CUR); } - if (ret < 0) + if (ret == (Llong)-1) excomerr("Cannot backspace tape.\n"); if (stats->lastsize == stats->blocksize) @@ -735,14 +851,16 @@ return (-1); #endif } - if (ret < 0 && debug) - errmsg("Error sending mtioctl(%d, %d) to '%s'.\n", cmd, count, tarfile); + if (ret < 0 && debug) { + errmsg("Error sending mtioctl(%d, %d) to '%s'.\n", + cmd, count, tarfiles[tarfindex]); + } return (ret); } -EXPORT long +EXPORT off_t mtseek(offset, whence) - long offset; + off_t offset; int whence; { if (nullout && !(uflag || rflag)) { @@ -752,39 +870,39 @@ return (rmtseek(remfd, offset, whence)); #endif } else { - return (fseek(tarf, offset, whence)); + return (lseek(fileno(tarf), offset, whence)); } } -EXPORT int +EXPORT Llong tblocks() { long fifo_cnt = 0; + Llong ret; #ifdef FIFO if (use_fifo) fifo_cnt = fifo_amount()/TBLOCK; #endif - if (debug) { - error("blocks: %ld blocksize: %ld parts: %ld bigcnt: %ld fifo_cnt: %ld\n", - stats->blocks, stats->blocksize, stats->parts, bigcnt, fifo_cnt); - } if (stats->reading) - return (-fifo_cnt + (stats->blocks * stats->blocksize + - stats->parts - (bigcnt+TBLOCK))/TBLOCK); + ret = (-fifo_cnt + stats->blocks * stats->nblocks + + (stats->parts - (bigcnt+TBLOCK))/TBLOCK); else - return (fifo_cnt + (stats->blocks * stats->blocksize + - stats->parts + bigcnt)/TBLOCK); + ret = (fifo_cnt + stats->blocks * stats->nblocks + + (stats->parts + bigcnt)/TBLOCK); + if (debug) { + error("tblocks: %lld blocks: %lld blocksize: %ld parts: %lld bigcnt: %ld fifo_cnt: %ld\n", + ret, stats->blocks, stats->blocksize, stats->parts, bigcnt, fifo_cnt); + } + curblockno = ret; + return (ret); } EXPORT void prstats() { Llong bytes; - long kbytes; - long hibytes; - long lobytes; - char cbytes[32]; + Llong kbytes; int per; #ifdef timerclear int sec; @@ -806,39 +924,23 @@ fifo_stats(); #endif - bytes = (Llong)stats->blocks * (Llong)stats->blocksize + stats->parts; + bytes = stats->blocks * (Llong)stats->blocksize + stats->parts; kbytes = bytes >> 10; per = ((bytes&1023)<<10)/10485; - cbytes[0] = '\0'; - hibytes = bytes / 1000000000; - lobytes = bytes % 1000000000; - if (hibytes) - sprintf(cbytes, "%ld%09ld", hibytes, lobytes); - else - sprintf(cbytes, "%ld", lobytes); - errmsgno(EX_BAD, - "%ld blocks + %ld bytes (total of %s bytes = %ld.%02dk).\n", - stats->blocks, stats->parts, cbytes, kbytes, per); + "%lld blocks + %lld bytes (total of %lld bytes = %lld.%02dk).\n", + stats->blocks, stats->parts, bytes, kbytes, per); if (stats->Tblocks + stats->Tparts) { - bytes = (Llong)stats->Tblocks * (Llong)stats->blocksize + + bytes = stats->Tblocks * (Llong)stats->blocksize + stats->Tparts; kbytes = bytes >> 10; per = ((bytes&1023)<<10)/10485; - cbytes[0] = '\0'; - hibytes = bytes / 1000000000; - lobytes = bytes % 1000000000; - if (hibytes) - sprintf(cbytes, "%ld%09ld", hibytes, lobytes); - else - sprintf(cbytes, "%ld", lobytes); - errmsgno(EX_BAD, - "Total %ld blocks + %ld bytes (total of %s bytes = %ld.%02dk).\n", - stats->Tblocks, stats->Tparts, cbytes, kbytes, per); + "Total %lld blocks + %lld bytes (total of %lld bytes = %lld.%02dk).\n", + stats->Tblocks, stats->Tparts, bytes, kbytes, per); } #ifdef timerclear if (showtime) { @@ -854,11 +956,10 @@ if (tmsec == 0) tmsec++; - kbs = (Llong)kbytes*(Llong)1000/tmsec; - lobytes = kbs; + kbs = kbytes*(Llong)1000/tmsec; - errmsgno(EX_BAD, "Total time %d.%03dsec (%ld kBytes/sec)\n", - sec, usec/1000, lobytes); + errmsgno(EX_BAD, "Total time %d.%03dsec (%lld kBytes/sec)\n", + sec, usec/1000, kbs); } #endif } @@ -867,13 +968,24 @@ checkerrs() { if (xstats.s_staterrs || +#ifdef USE_ACL + xstats.s_getaclerrs || +#endif xstats.s_openerrs || xstats.s_rwerrs || xstats.s_misslinks || xstats.s_toolong || xstats.s_toobig || xstats.s_isspecial || - xstats.s_sizeerrs) { + xstats.s_sizeerrs || + + xstats.s_settime || +#ifdef USE_ACL + xstats.s_badacl || + xstats.s_setacl || +#endif + xstats.s_setmodes + ) { if (nowarn || no_stats || (pid == 0)/* child */) return (TRUE); @@ -888,6 +1000,17 @@ xstats.s_toolong, xstats.s_toobig, xstats.s_isspecial); + if (xstats.s_settime || xstats.s_setmodes) + errmsgno(EX_BAD, "Cannot set: time %d, modes %d.\n", + xstats.s_settime, + xstats.s_setmodes); +#ifdef USE_ACL + if (xstats.s_getaclerrs || xstats.s_badacl || xstats.s_setacl) + errmsgno(EX_BAD, "Cannot get ACL: %d set ACL: %d. Bad ACL %d.\n", + xstats.s_getaclerrs, + xstats.s_setacl, + xstats.s_badacl); +#endif return (TRUE); } return (FALSE); @@ -898,6 +1021,7 @@ int ret; { prstats(); + checkerrs(); exit(ret); } @@ -974,6 +1098,7 @@ LOCAL void compressopen() { +#ifdef HAVE_FORK FILE *pp[2]; int mypid; char *zip_prog = "gzip"; @@ -1023,4 +1148,7 @@ tarf = pp[0]; fclose(pp[1]); } +#else + comerrno(EX_BAD, "Inline compression not available.\n"); +#endif } diff -ruN star-1.3.1/star/create.c star-1.4/star/create.c --- star-1.3.1/star/create.c Sat Apr 7 11:06:04 2001 +++ star-1.4/star/create.c Fri May 17 11:26:30 2002 @@ -1,10 +1,10 @@ -/* @(#)create.c 1.40 01/04/07 Copyright 1985, 1995 J. Schilling */ +/* @(#)create.c 1.65 02/05/17 Copyright 1985, 1995, 2001 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)create.c 1.40 01/04/07 Copyright 1985, 1995 J. Schilling"; + "@(#)create.c 1.65 02/05/17 Copyright 1985, 1995, 2001 J. Schilling"; #endif /* - * Copyright (c) 1985, 1995 J. Schilling + * Copyright (c) 1985, 1995, 2001 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify @@ -38,34 +38,42 @@ typedef struct links { struct links *l_next; - long l_ino; - long l_dev; + ino_t l_ino; + dev_t l_dev; long l_nlink; short l_namlen; + Uchar l_flags; char l_name[1]; /* actually longer */ } LINKS; +#define L_ISDIR 1 /* This entry refers to a directory */ +#define L_ISLDIR 2 /* A dir, hard linked to another dir */ + #define L_HSIZE 256 /* must be a power of two */ #define l_hash(info) (((info)->f_ino + (info)->f_dev) & (L_HSIZE-1)) LOCAL LINKS *links[L_HSIZE]; +extern FILE *vpr; extern FILE *listf; -extern long tape_dev; -extern long tape_ino; +extern BOOL tape_isreg; +extern dev_t tape_dev; +extern ino_t tape_ino; #define is_tape(info) ((info)->f_dev == tape_dev && (info)->f_ino == tape_ino) extern int bufsize; extern char *bigptr; extern BOOL havepat; -extern Ulong curfs; -extern Ulong maxsize; -extern Ulong Newer; -extern Ulong tsize; +extern dev_t curfs; +extern Ullong maxsize; +extern time_t Newer; +extern Ullong tsize; +extern BOOL prblockno; extern BOOL debug; +extern BOOL silent; extern BOOL uflag; extern BOOL nodir; extern BOOL acctime; @@ -79,7 +87,10 @@ extern BOOL nowarn; extern BOOL sparse; extern BOOL Ctime; +extern BOOL nodump; extern BOOL nullout; +extern BOOL link_dirs; +extern BOOL dometa; extern int intr; @@ -112,6 +123,8 @@ register int curlen; register int maxlen = 0; register int nlinks = 0; + register int ndirs = 0; + register int nldirs = 0; for(i=0; i < L_HSIZE; i++) { if (links[i] == (LINKS *)NULL) @@ -123,7 +136,25 @@ for(lp = links[i]; lp != (LINKS *)NULL; lp = lp->l_next) { curlen++; nlinks++; - if (lp->l_nlink != 0) { + if ((lp->l_flags & L_ISDIR) != 0) { + ndirs++; + if ((lp->l_flags & L_ISLDIR) != 0) + nldirs++; + } else if (lp->l_nlink != 0) { + /* + * The fact that UNIX uses '.' and '..' as hard + * links to directories on all known file + * systems is a design bug. It makes it hard to + * find hard links to directories. Note that + * POSIX neither requires '.' and '..' to be + * implemented as hard links nor that these + * directories are physical present in the + * directory content. + * As it is hard to find all links (we would + * need top stat all directories as well as all + * '.' and '..' entries, we only warn for non + * directories. + */ xstats.s_misslinks++; errmsgno(EX_BAD, "Missing links to '%s'.\n", lp->l_name); @@ -133,8 +164,15 @@ maxlen = curlen; } if (debug) { - errmsgno(EX_BAD, "hardlinks: %d hashents: %d/%d maxlen: %d\n", + if (link_dirs) { + errmsgno(EX_BAD, "entries: %d hashents: %d/%d maxlen: %d\n", + nlinks, used, L_HSIZE, maxlen); + errmsgno(EX_BAD, "hardlinks total: %d linked dirs: %d/%d linked files: %d \n", + nlinks+nldirs-ndirs, nldirs, ndirs, nlinks-ndirs); + } else { + errmsgno(EX_BAD, "hardlinks: %d hashents: %d/%d maxlen: %d\n", nlinks, used, L_HSIZE, maxlen); + } } } @@ -143,10 +181,13 @@ register char *name; register FINFO *info; { + if (nodump && (info->f_flags & F_NODUMP) != 0) + return (FALSE); + if (havepat && !match(name)) { return (FALSE); /* Bei Directories ist f_size == 0 */ - } else if (maxsize && info->f_size/1024 > maxsize) { + } else if (maxsize && info->f_size > maxsize) { return (FALSE); } else if (Newer && (Ctime ? info->f_ctime:info->f_mtime) <= Newer) { /* @@ -158,16 +199,41 @@ } else if (tsize > 0 && tsize < (tarblocks(info->f_size)+1+2)) { xstats.s_toobig++; errmsgno(EX_BAD, "'%s' does not fit on tape. Not dumped.\n", - name) ; + name); + return (FALSE); + } else if (props.pr_maxsize > 0 && info->f_size > props.pr_maxsize) { + xstats.s_toobig++; + errmsgno(EX_BAD, "'%s' file too big for current mode. Not dumped.\n", + name); + return (FALSE); + } else if (pr_unsuptype(info)) { + xstats.s_isspecial++; + errmsgno(EX_BAD, "'%s' unsupported file type '%s'. Not dumped.\n", + name, XTTONAME(info->f_xftype)); return (FALSE); } else if (is_special(info) && nospec) { xstats.s_isspecial++; - errmsgno(EX_BAD, "'%s' is not a file. Not dumped.\n", name) ; + errmsgno(EX_BAD, "'%s' is not a file. Not dumped.\n", name); return (FALSE); - } else if (is_tape(info)) { - errmsgno(EX_BAD, "'%s' is the archive. Not dumped.\n", name) ; + } else if (tape_isreg && is_tape(info)) { + errmsgno(EX_BAD, "'%s' is the archive. Not dumped.\n", name); return (FALSE); } + if (is_file(info) && dometa) { + /* + * This is the right place for this code although it does not + * look correct. Later in star-1.5 we decide here, based on + * mtime and ctime of the file, whether we archive a file at + * all and whether we only add the file's metadata. + */ + info->f_xftype = XT_META; + if (pr_unsuptype(info)) { + xstats.s_isspecial++; + errmsgno(EX_BAD, "'%s' unsupported file type '%s'. Not dumped.\n", + name, XTTONAME(info->f_xftype)); + return (FALSE); + } + } return (TRUE); } @@ -196,9 +262,34 @@ { register int fd = *fp; register int ret; + int errcnt = 0; - while((ret = read(fd, buf, len)) < 0 && errno == EINTR) +retry: + while((ret = read(fd, buf, len)) < 0 && geterrno() == EINTR) ; + if (ret < 0 && geterrno() == EINVAL && ++errcnt < 100) { + off_t oo; + off_t si; + + /* + * Work around the problem that we cannot read() + * if the buffer crosses 2 GB in non large file mode. + */ + oo = lseek(fd, (off_t)0, SEEK_CUR); + if (oo == (off_t)-1) + return (ret); + si = lseek(fd, (off_t)0, SEEK_END); + if (oo == (off_t)-1) + return (ret); + if (lseek(fd, oo, SEEK_SET) == (off_t)-1) + return (ret); + if (oo >= si) { /* EOF */ + ret = 0; + } else if ((si - oo) <= len) { + len = si - oo; + goto retry; + } + } return(ret); } @@ -254,6 +345,8 @@ info->f_lname = lname; /*XXX nur Übergangsweise!!!!!*/ info->f_lnamelen = 0; + if (prblockno) + (void)tblocks(); /* set curblockno */ if (!(dirmode && is_dir(info)) && (info->f_namelen <= props.pr_maxsname)) { /* @@ -270,20 +363,67 @@ info->f_flags |= F_TCB_BUF; } info->f_tcb = ptb; - fillbytes((char *)ptb, TBLOCK, '\0'); + filltcb(ptb); if (!name_to_tcb(info, ptb)) /* Name too long */ return; info_to_tcb(info, ptb); - if (is_dir(info)) - put_dir(name, namlen, info, ptb); - else if (!take_file(name, info)) + if (is_dir(info)) { + /* + * If we have been requested to check for hard linked + * directories, first look for possible hard links. + */ + if (link_dirs && /* info->f_nlink > 1 &&*/ read_link(name, namlen, info, ptb)) + was_link = TRUE; + + if (was_link && !is_link(info)) /* link name too long */ + return; + + if (was_link) { + put_tcb(ptb, info); + vprint(info); + } else { + put_dir(name, namlen, info, ptb); + } + } else if (!take_file(name, info)) { return; - else if (interactive && !ia_change(ptb, info)) - printf("Skipping ...\n"); - else if (is_symlink(info) && !read_symlink(name, info, ptb)) + } else if (interactive && !ia_change(ptb, info)) { + fprintf(vpr, "Skipping ...\n"); + } else if (is_symlink(info) && !read_symlink(name, info, ptb)) { + /* EMPTY */ ; - else if (is_file(info) && info->f_size != 0 && !nullout && + } else if (is_meta(info)) { + if (info->f_nlink > 1 && read_link(name, namlen, info, ptb)) + was_link = TRUE; + + if (was_link && !is_link(info)) /* link name too long */ + return; + + if (!was_link) { + /* + * XXX We definitely do not want that other tar + * XXX implementations are able to read tar archives + * XXX that contain meta files. + * XXX If a tar implementation that does not understand + * XXX meta files extracts archives with meta files, + * XXX it will most likely destroy old files on disk. + */ + ptb->dbuf.t_linkflag = LF_META; + info->f_flags &= ~F_SPLIT_NAME; + if (ptb->dbuf.t_prefix[0] != '\0') + fillbytes(ptb->dbuf.t_prefix, props.pr_maxprefix, '\0'); + if (props.pr_flags & PR_XHDR) + info->f_xflags |= XF_PATH; + else + info->f_flags |= F_LONGNAME; + ptb->dbuf.t_name[0] = 0; /* Hide P-1988 name */ + info_to_tcb(info, ptb); + } + put_tcb(ptb, info); + vprint(info); + return; + + } else if (is_file(info) && info->f_size != 0 && !nullout && (fd = _fileopen(name,"rb")) < 0) { xstats.s_openerrs++; errmsg("Cannot open '%s'.\n", name); @@ -314,7 +454,8 @@ * Hardlinks have f_rsize == 0 ! */ if (do_sparse) { - error("%s is sparse\n", info->f_name); + if (!silent) + error("%s is sparse\n", info->f_name); put_sparse(&fd, info); } else { put_file(&fd, info); @@ -343,8 +484,7 @@ char *name; int nsize = PATH_MAX+1; /* wegen laenge !!! */ - if ((name = malloc(nsize)) == 0) - comerr("Cannot alloc name buffer.\n"); + name = __malloc(nsize, "name buffer"); for (nlen = 1; nlen > 0;) { if ((nlen = fgetline(listf, name, nsize)) < 0) @@ -359,7 +499,7 @@ } if (intr) break; - curfs = -1L; + curfs = NODEV; create(name); } } @@ -384,8 +524,12 @@ errmsgno(EX_BAD, "%s: Symbolic link too long.\n", name); return (FALSE); } - if (len > props.pr_maxslname) - info->f_flags |= F_LONGLINK; + if (len > props.pr_maxslname) { + if (props.pr_flags & PR_XHDR) + info->f_xflags |= XF_LINKPATH; + else + info->f_flags |= F_LONGLINK; + } /* * string from readlink is not null terminated */ @@ -420,8 +564,12 @@ lp->l_name); return (TRUE); } - if (lp->l_namlen > props.pr_maxslname) - info->f_flags |= F_LONGLINK; + if (lp->l_namlen > props.pr_maxslname) { + if (props.pr_flags & PR_XHDR) + info->f_xflags |= XF_LINKPATH; + else + info->f_flags |= F_LONGLINK; + } if (--lp->l_nlink < 0) { if (!nowarn) errmsgno(EX_BAD, @@ -429,6 +577,13 @@ lp->l_name, lp->l_nlink); } /* + * We found a hard link to a directory that is already + * known in the link cache. Mark it for later + * statistical analysis. + */ + if (lp->l_flags & L_ISDIR) + lp->l_flags |= L_ISLDIR; + /* * if linkname is not longer than props.pr_maxslname * that's all to do with linkname */ @@ -437,6 +592,22 @@ info->f_lname = lp->l_name; info->f_lnamelen = lp->l_namlen; info->f_xftype = XT_LINK; + + /* + * With POSIX-1988, f_rsize is 0 for hardlinks + * + * XXX Should we add a property for old tar + * XXX compatibility to keep the size field as before? + */ + info->f_rsize = (off_t)0; + /* + * XXX This is the wrong place but the TCB ha already + * XXX been set up (including size field) before. + * XXX We only call info_to_tcb() to change size to 0. + * XXX There should be a better way to deal with TCB. + */ + info_to_tcb(info, ptb); + /* * XXX Dies ist eine ungewollte Referenz auf den * XXX TAR Control Block, aber hier ist der TCB @@ -456,11 +627,16 @@ lp->l_dev = info->f_dev; lp->l_nlink = info->f_nlink - 1; lp->l_namlen = namlen; + if (is_dir(info)) + lp->l_flags = L_ISDIR; + else + lp->l_flags = 0; strcpy(lp->l_name, name); } return (FALSE); } +/* ARGSUSED */ LOCAL int nullread(vp, cp, amt) void *vp; @@ -493,10 +669,10 @@ char *text; { register int amount; - register int blocks; - register long size; + register off_t blocks; + register off_t size; register int i = 0; - register int n; + register off_t n; size = info->f_rsize; if ((blocks = tarblocks(info->f_rsize)) == 0) @@ -516,6 +692,9 @@ } else { n = tarblocks(i); } + if (i % TBLOCK) { /* Clear (better compression)*/ + fillbytes(bigptr+i, TBLOCK - (i%TBLOCK), '\0'); + } buf_wake(n*TBLOCK); } while ((blocks -= n) >= 0 && i == amount && size >= 0); if (i < 0) { @@ -523,7 +702,9 @@ errmsg("Error %s '%s'.\n", text, info->f_name); } else if ((blocks != 0 || size != 0) && func != nullread) { xstats.s_sizeerrs++; - errmsgno(EX_BAD, "'%s': file changed size.\n", info->f_name); + errmsgno(EX_BAD, + "'%s': file changed size (%s).\n", + info->f_name, size < 0 ? "increased":"shrunk"); } while(--blocks >= 0) writeempty(); @@ -560,6 +741,9 @@ dinit = 1; } + if (nodump && (info->f_flags & F_NODUMP) != 0) + return; + if (!(d = opendir(dname))) { xstats.s_openerrs++; errmsg("Cannot open '%s'.\n", dname); @@ -567,7 +751,7 @@ depth--; if (!nodir) { if (interactive && !ia_change(ptb, info)) { - printf("Skipping ...\n"); + fprintf(vpr, "Skipping ...\n"); closedir(d); depth++; return; @@ -621,7 +805,7 @@ } #ifdef HAVE_SEEKDIR if (is_dir(ninfo) && depth <= 0) { - errno = 0; + seterrno(0); offset = telldir(d); if (geterrno()) errmsg("WARNING: telldir does not work.\n"); @@ -641,7 +825,7 @@ dname); break; } else { - errno = 0; + seterrno(0); seekdir(d, offset); if (geterrno()) errmsg("WARNING: seekdir does not work.\n"); @@ -666,22 +850,17 @@ FINFO finfo; char pname[PATH_MAX+1]; int OFflag = Fflag; - int len; char *p; Fflag = 0; - len = namlen; strcpy(pname, name); - p = &pname[len]; + p = &pname[namlen]; if (p[-1] != '/') { *p++ = '/'; - len++; } strcpy(p, ".mirror"); - len += 7; if (!getinfo(pname, &finfo)) { strcpy(p, ".exclude"); - len += 1; if (!getinfo(pname, &finfo)) goto notfound; } @@ -712,9 +891,15 @@ int len; const char *fn; + if (Fflag <= 0) + return (TRUE); + fn = filename(name); if (is_dir(info)) { + /* + * Exclude with -F -FF -FFFFF 1, 2, 5+ + */ if (Fflag < 3 || Fflag > 4) { if (streql(fn, "SCCS") || /* SCCS directory */ streql(fn, "RCS")) /* RCS directory */ @@ -732,10 +917,10 @@ if (Fflag > 1 && fn[len-2] == '.' && fn[len-1] == 'o') /* obj files */ return (FALSE); - if (is_file(info)) { + if (Fflag > 1 && is_file(info)) { if (streql(fn, "core") || streql(fn, "errs") || - (Fflag > 1 && streql(fn, "a.out"))) + streql(fn, "a.out")) return (FALSE); } diff -ruN star-1.3.1/star/device.c star-1.4/star/device.c --- star-1.3.1/star/device.c Thu Feb 15 23:39:08 2001 +++ star-1.4/star/device.c Mon Oct 29 17:50:53 2001 @@ -1,7 +1,7 @@ -/* @(#)device.c 1.7 01/02/15 Copyright 1996 J. Schilling */ +/* @(#)device.c 1.8 01/10/29 Copyright 1996 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)device.c 1.7 01/02/15 Copyright 1996 J. Schilling"; + "@(#)device.c 1.8 01/10/29 Copyright 1996 J. Schilling"; #endif /* * Handle local and remote device major/minor mappings @@ -25,7 +25,6 @@ */ #include -#include #include #include #define __XDEV__ /* Needed to activate XDEV_T definitions */ diff -ruN star-1.3.1/star/diff.c star-1.4/star/diff.c --- star-1.3.1/star/diff.c Sat Apr 7 11:06:03 2001 +++ star-1.4/star/diff.c Fri May 17 11:26:30 2002 @@ -1,7 +1,7 @@ -/* @(#)diff.c 1.33 01/04/07 Copyright 1993 J. Schilling */ +/* @(#)diff.c 1.41 02/05/17 Copyright 1993 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)diff.c 1.33 01/04/07 Copyright 1993 J. Schilling"; + "@(#)diff.c 1.41 02/05/17 Copyright 1993 J. Schilling"; #endif /* * List differences between a (tape) archive and @@ -27,12 +27,13 @@ #include #include +#include +#include #include #include "star.h" #include "props.h" #include "table.h" #include "diff.h" -#include #include #include /*XXX Wegen S_IFLNK */ #include "starsubs.h" @@ -47,7 +48,7 @@ extern char *listfile; extern int version; -extern int bigcnt; +extern long bigcnt; extern int bigsize; extern char *bigptr; @@ -56,7 +57,7 @@ extern BOOL debug; extern BOOL no_stats; extern BOOL abs_path; -extern BOOL verbose; +extern int verbose; extern BOOL tpath; extern BOOL interactive; @@ -121,7 +122,7 @@ int diffs = 0; BOOL do_void; - f = tarf == stdout ? stderr : stdout; + f = tarf == stdout ? stderr : stdout; /* XXX FILE *vpr is the same */ finfo.f_lname = lname; finfo.f_lnamelen = 0; @@ -130,6 +131,10 @@ (info->f_name[0] == '/' /*|| info->f_lname[0] == '/'*/)) skip_slash(info); + if (is_volhdr(info)) { + void_file(info); + return; + } if (!getinfo(info->f_name, &finfo)) { xstats.s_staterrs++; errmsg("Cannot stat '%s'.\n", info->f_name); @@ -147,8 +152,12 @@ if ((diffopts & D_PERM) && (info->f_mode & 07777) != (finfo.f_mode & 07777)) { diffs |= D_PERM; + /* + * XXX Diff ACLs not yet implemented. + */ + /* XXX hat ustar modes incl. filetype ???? */ -/*printf("%o %o\n", info->f_mode, finfo.f_mode);*/ +/*error("%o %o\n", info->f_mode, finfo.f_mode);*/ } if ((diffopts & D_UID) && info->f_uid != finfo.f_uid) { diffs |= D_UID; @@ -175,32 +184,58 @@ if ((diffopts & D_TYPE) && (info->f_filetype != finfo.f_filetype || (is_special(info) && info->f_type != finfo.f_type)) - && (!is_link(info) || H_TYPE(hdrtype) == H_STAR)) { + && (!fis_link(info) || H_TYPE(hdrtype) == H_STAR)) { - if (debug) - fprintf(f, "%s: different filetype %lo != %lo\n", + if (fis_meta(info) && is_file(&finfo)) { + /* EMPTY */ + ; + } else { + if (debug) { + fprintf(f, + "%s: different filetype %lo != %lo\n", info->f_name, info->f_type, finfo.f_type); - diffs |= D_TYPE; + } + diffs |= D_TYPE; + } } /* * XXX nsec beachten wenn im Archiv! */ - if ((diffopts & D_ATIME) && info->f_atime != finfo.f_atime) { - diffs |= D_ATIME; + if ((diffopts & D_ATIME) != 0) { + if (info->f_atime != finfo.f_atime) + diffs |= D_ATIME; +/*#define should_we*/ +#ifdef should_we + if ((info->f_xflags & XF_ATIME) && (finfo.f_flags & F_NSECS) && + info->f_ansec != finfo.f_ansec) + diffs |= D_ATIME; +#endif } - if ((diffopts & D_MTIME) && info->f_mtime != finfo.f_mtime) { - diffs |= D_MTIME; + if ((diffopts & D_MTIME) != 0) { + if (info->f_mtime != finfo.f_mtime) + diffs |= D_MTIME; +#ifdef should_we + if ((info->f_xflags & XF_MTIME) && (finfo.f_flags & F_NSECS) && + info->f_mnsec != finfo.f_mnsec) + diffs |= D_MTIME; +#endif } - if ((diffopts & D_CTIME) && info->f_ctime != finfo.f_ctime) { - diffs |= D_CTIME; + if ((diffopts & D_CTIME) != 0) { + if (info->f_ctime != finfo.f_ctime) + diffs |= D_CTIME; +#ifdef should_we + if ((info->f_xflags & XF_CTIME) && (finfo.f_flags & F_NSECS) && + info->f_cnsec != finfo.f_cnsec) + diffs |= D_CTIME; +#endif } if ((diffopts & D_HLINK) && is_link(info)) { if (!getinfo(info->f_lname, &linfo)) { xstats.s_staterrs++; errmsg("Cannot stat '%s'.\n", info->f_lname); - linfo.f_ino = 0; + linfo.f_ino = (ino_t)0; } if ((finfo.f_ino != linfo.f_ino) || (finfo.f_dev != linfo.f_dev)) { @@ -246,9 +281,9 @@ && info->f_rdev != finfo.f_rdev) { diffs |= D_RDEV; } - if ((diffopts & D_DATA) && is_file(info) && is_file(&finfo) + if ((diffopts & D_DATA) && !is_meta(info) && is_file(info) && is_file(&finfo) /* avoid permission denied error */ - && info->f_size > 0 + && info->f_size > (off_t)0 && info->f_size == finfo.f_size) { if (!cmp_file(info)) { diffs |= D_DATA; @@ -310,10 +345,16 @@ cmp_t cmp; if (!diffbuf) { - diffbuf = malloc((unsigned)bigsize); + /* + * If we have no diffbuf, we cannot diff - abort. + */ + diffbuf = __malloc((size_t)bigsize, "diff buffer"); +#ifdef __notneeded if (diffbuf == (char *)0) { - errmsg("Cannot alloc diffbuf.\n"); + void_file(info); + return (FALSE); } +#endif } if ((f = fileopen(info->f_name, "rub")) == (FILE *)NULL) { @@ -347,6 +388,9 @@ fprintf(f, "%s", label); if (flags & D_PERM) prdopt(f, "perm", printed++); + /* + * XXX Diff ACLs not yet implemented. + */ if (flags & D_TYPE) prdopt(f, "type", printed++); if (flags & D_NLINK) diff -ruN star-1.3.1/star/dirtime.c star-1.4/star/dirtime.c --- star-1.3.1/star/dirtime.c Sat Apr 7 10:25:51 2001 +++ star-1.4/star/dirtime.c Mon May 20 13:58:55 2002 @@ -1,7 +1,7 @@ -/* @(#)dirtime.c 1.9 01/04/07 Copyright 1988 J. Schilling */ +/* @(#)dirtime.c 1.11 02/05/20 Copyright 1988 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)dirtime.c 1.9 01/04/07 Copyright 1988 J. Schilling"; + "@(#)dirtime.c 1.11 02/05/20 Copyright 1988 J. Schilling"; #endif /* * Copyright (c) 1988 J. Schilling @@ -132,7 +132,8 @@ np++; } EDBG(("DIR: '%.*s' DP: '%s' NP: '%s' idx: %d\n", - dp - dirstack, dirstack, dp, np, idx)); + /* XXX Should not be > int */ + (int)(dp - dirstack), dirstack, dp, np, idx)); if (*dp) { /* @@ -204,9 +205,11 @@ { EDBG(("settime: '%s' to %s", name, ctime(&tp[1].tv_sec))); #ifdef SET_CTIME - if (xutimes(name, tp) < 0) + if (xutimes(name, tp) < 0) { #else - if (utimes(name, tp) < 0) + if (utimes(name, tp) < 0) { #endif errmsg("Can't set time on '%s'.\n", name); + xstats.s_settime++; + } } diff -ruN star-1.3.1/star/extract.c star-1.4/star/extract.c --- star-1.3.1/star/extract.c Sat Apr 7 11:06:03 2001 +++ star-1.4/star/extract.c Thu May 2 21:02:41 2002 @@ -1,7 +1,7 @@ -/* @(#)extract.c 1.36 01/04/07 Copyright 1985 J. Schilling */ +/* @(#)extract.c 1.52 02/05/02 Copyright 1985 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)extract.c 1.36 01/04/07 Copyright 1985 J. Schilling"; + "@(#)extract.c 1.52 02/05/02 Copyright 1985 J. Schilling"; #endif /* * extract files from archive @@ -45,12 +45,15 @@ #include "dirtime.h" #include "starsubs.h" +extern FILE *vpr; + extern char *listfile; extern int bufsize; extern char *bigptr; extern BOOL havepat; +extern BOOL prblockno; extern BOOL nflag; extern BOOL interactive; extern BOOL nodir; @@ -65,17 +68,21 @@ extern BOOL to_stdout; extern BOOL remove_first; extern BOOL copylinks; +extern BOOL hardlinks; +extern BOOL symlinks; +extern BOOL dometa; EXPORT void extract __PR((char *vhname)); EXPORT BOOL newer __PR((FINFO * info)); LOCAL BOOL same_symlink __PR((FINFO * info)); -LOCAL BOOL remove_file __PR((char* name, BOOL isfirst)); LOCAL BOOL create_dirs __PR((char* name)); LOCAL BOOL make_dir __PR((FINFO * info)); LOCAL BOOL make_link __PR((FINFO * info)); LOCAL BOOL make_symlink __PR((FINFO * info)); -LOCAL BOOL make_copy __PR((FINFO * info, BOOL emul_symlink)); -LOCAL int copy_file __PR((char *from, char *to, BOOL emul_symlink)); +LOCAL BOOL emul_symlink __PR((FINFO * info)); +LOCAL BOOL emul_link __PR((FINFO * info)); +LOCAL BOOL make_copy __PR((FINFO * info, BOOL do_symlink)); +LOCAL int copy_file __PR((char *from, char *to, BOOL do_symlink)); LOCAL BOOL make_fifo __PR((FINFO * info)); LOCAL BOOL make_special __PR((FINFO * info)); LOCAL BOOL get_file __PR((FINFO * info)); @@ -104,12 +111,16 @@ finfo.f_name = name; if (tcb_to_info(ptb, &finfo) == EOF) return; + if (prblockno) + (void)tblocks(); /* set curblockno */ + if (is_volhdr(&finfo)) { if (!get_volhdr(&finfo, vhname)) { excomerrno(EX_BAD, "Volume Header '%s' does not match '%s'.\n", finfo.f_name, vhname); } + void_file(&finfo); continue; } if (!abs_path && /* XXX VVV siehe skip_slash() */ @@ -143,7 +154,7 @@ } if (interactive && !ia_change(ptb, &finfo)) { if (!nflag) - printf("Skipping ...\n"); + fprintf(vpr, "Skipping ...\n"); void_file(&finfo); continue; } @@ -164,10 +175,23 @@ if (!make_symlink(&finfo)) continue; } else if (is_special(&finfo)) { - if (is_fifo(&finfo) && !make_fifo(&finfo)) - continue; - if (!make_special(&finfo)) - continue; + if (is_door(&finfo)) { + if (!nowarn) { + errmsgno(EX_BAD, + "WARNING: Extracting door '%s' as plain file.\n", + finfo.f_name); + } + if (!get_file(&finfo)) + continue; + } else if (is_fifo(&finfo)) { + if (!make_fifo(&finfo)) + continue; + } else { + if (!make_special(&finfo)) + continue; + } + } else if (is_meta(&finfo)) { + void_file(&finfo); } else if (!get_file(&finfo)) continue; if (!to_stdout) @@ -201,7 +225,7 @@ */ if (cinfo.f_mtime >= info->f_mtime) { - newer: + isnewer: if (!nowarn) errmsgno(EX_BAD, "current '%s' newer.\n", info->f_name); return (TRUE); @@ -211,7 +235,7 @@ * of 2 seconds. So we need to be a bit more generous. * XXX We should be able to test the filesytem type. */ - goto newer; + goto isnewer; } return (FALSE); } @@ -265,64 +289,6 @@ } LOCAL BOOL -remove_file(name, isfirst) - register char *name; - BOOL isfirst; -{ - char buf[32]; - char ans; - int err = EX_BAD; -extern FILE *tty; -extern BOOL interactive; -extern BOOL force_remove; -extern BOOL ask_remove; - - if (remove_first && !isfirst) - return (FALSE); - if (interactive || ask_remove) { - printf("remove '%s' ? Y(es)/N(o) :", name);flush(); - fgetline(tty, buf, 2); - } - if (force_remove || - ((interactive || ask_remove) && (ans = toupper(buf[0])) == 'Y')) { - - /* - * only unlink non directories or empty - * directories - * XXX need to implement the -remove_recursive flag - */ - if (rmdir(name) < 0) { - err = geterrno(); - if (err == EACCES) - goto cannot; - -#if defined(__CYGWIN32__) - if (err == ENOTEMPTY) { - /* - * Cygwin returns ENOTEMPTY if 'name' - * is not a dir. - * XXX Never do this on UNIX. - * XXX If you are root, you may unlink - * XXX even nonempty directories. - */ - err = ENOTDIR; - } -#endif - if (err == ENOTDIR) { - if (unlink(name) < 0) { - err = geterrno(); - goto cannot; - } - } - } - return (TRUE); - } -cannot: - errmsgno(err, "File '%s' not removed.\n", name); - return (FALSE); -} - -LOCAL BOOL create_dirs(name) register char *name; { @@ -376,6 +342,9 @@ FINFO dinfo; int err; + if (dometa) + return (TRUE); + if (create_dirs(info->f_name)) { if (getinfo(info->f_name, &dinfo) && is_dir(&dinfo)) return (TRUE); @@ -401,8 +370,13 @@ { int err; + if (dometa) + return (TRUE); + if (copylinks) return (make_copy(info, FALSE)); + else if (hardlinks) + return (emul_link(info)); #ifdef HAVE_LINK if (uncond) @@ -421,12 +395,12 @@ return (TRUE); } xstats.s_openerrs++; - errmsg("Cannot create '%s'.\n", info->f_name); + errmsg("Cannot link '%s' to '%s'.\n", info->f_name, info->f_lname); return(FALSE); #else /* HAVE_LINK */ xstats.s_isspecial++; - errmsgno(EX_BAD, "Not supported. Cannot create link '%s'.\n", - info->f_name); + errmsgno(EX_BAD, "Not supported. Cannot link '%s' to '%s'.\n", + info->f_name, info->f_lname); return (FALSE); #endif /* HAVE_LINK */ } @@ -437,8 +411,13 @@ { int err; + if (dometa) + return (TRUE); + if (copylinks) return (make_copy(info, TRUE)); + else if (symlinks) + return (emul_symlink(info)); #ifdef S_IFLNK if (uncond) @@ -457,20 +436,44 @@ return (TRUE); } xstats.s_openerrs++; - errmsg("Cannot create symbolic link '%s'.\n", info->f_name); + errmsg("Cannot create symbolic link '%s' to '%s'.\n", + info->f_name, info->f_lname); return (FALSE); #else /* S_IFLNK */ xstats.s_isspecial++; - errmsgno(EX_BAD, "Not supported. Cannot create symbolic link '%s'.\n", - info->f_name); + errmsgno(EX_BAD, "Not supported. Cannot create symbolic link '%s' to '%s'.\n", + info->f_name, info->f_lname); return (FALSE); #endif /* S_IFLNK */ } LOCAL BOOL -make_copy(info, emul_symlink) +emul_symlink(info) + FINFO *info; +{ + errmsgno(EX_BAD, "Option -symlinks not yet implemented.\n"); + errmsgno(EX_BAD, "Cannot create symbolic link '%s' to '%s'.\n", + info->f_name, info->f_lname); + return (FALSE); +} + +LOCAL BOOL +emul_link(info) FINFO *info; - BOOL emul_symlink; +{ + errmsgno(EX_BAD, "Option -hardlinks not yet implemented.\n"); + errmsgno(EX_BAD, "Cannot link '%s' to '%s'.\n", info->f_name, info->f_lname); +#ifdef HAVE_LINK + return (FALSE); +#else + return (FALSE); +#endif /* S_IFLNK */ +} + +LOCAL BOOL +make_copy(info, do_symlink) + FINFO *info; + BOOL do_symlink; { int ret; int err; @@ -478,29 +481,30 @@ if (uncond) unlink(info->f_name); - if ((ret = copy_file(info->f_lname, info->f_name, emul_symlink)) >= 0) + if ((ret = copy_file(info->f_lname, info->f_name, do_symlink)) >= 0) return (TRUE); err = geterrno(); if (ret != -2 && create_dirs(info->f_name)) { - if (copy_file(info->f_lname, info->f_name, emul_symlink) >= 0) + if (copy_file(info->f_lname, info->f_name, do_symlink) >= 0) return (TRUE); err = geterrno(); } - if ((err == EACCES || err == EEXIST) && + if ((err == EACCES || err == EEXIST || err == EISDIR) && remove_file(info->f_name, FALSE)) { - if (copy_file(info->f_lname, info->f_name, emul_symlink) >= 0) + if (copy_file(info->f_lname, info->f_name, do_symlink) >= 0) return (TRUE); } xstats.s_openerrs++; - errmsg("Cannot create '%s'.\n", info->f_name); + errmsg("Cannot create link copy '%s' from '%s'.\n", + info->f_name, info->f_lname); return(FALSE); } LOCAL int -copy_file(from, to, emul_symlink) +copy_file(from, to, do_symlink) char *from; char *to; - BOOL emul_symlink; + BOOL do_symlink; { FINFO finfo; FILE *fin; @@ -509,7 +513,18 @@ char buf[8192]; char nbuf[PATH_MAX+1]; - if (emul_symlink && from[0] != '/') { + /* + * When tar archives hard links, both names (from/to) are relative to + * the current directory. With symlinks this does not work. Symlinks + * are always evaluated relative to the directory they reside in. + * For this reason, we cannot simply open the from/to files if we + * like to emulate a symbolic link. To emulate the behavior of a + * symbolic link, we concat the the directory part of the 'to' name + * (which is the path that becomes the sombolic link) to the complete + * 'from' name (which is the path the symbolic linkc pints to) in case + * the 'from' name is a relative path name. + */ + if (do_symlink && from[0] != '/') { char *p = strrchr(to, '/'); int len; @@ -533,7 +548,7 @@ } if (!is_file(&finfo)) { errmsgno(EX_BAD, "Not a file. Cannot copy from '%s'.\n", from); - errno = EINVAL; + seterrno(EINVAL); return (-2); } @@ -560,6 +575,9 @@ int mode; int err; + if (dometa) + return (TRUE); + #ifdef HAVE_MKFIFO mode = info->f_mode | info->f_type; if (uncond) @@ -599,6 +617,9 @@ int dev; int err; + if (dometa) + return (TRUE); + #ifdef HAVE_MKNOD mode = info->f_mode | info->f_type; dev = info->f_rdev; @@ -639,13 +660,16 @@ int err; int ret; + if (dometa) + return (TRUE); + if (to_stdout) { f = stdout; } else if ((f = fileopen(info->f_name, "wctub")) == (FILE *)NULL) { err = geterrno(); if (err == EMISSDIR && create_dirs(info->f_name)) return get_file(info); - if ((err == EACCES || err == EEXIST) && + if ((err == EACCES || err == EEXIST || err == EISDIR) && remove_file(info->f_name, FALSE)) { return get_file(info); } @@ -670,13 +694,25 @@ die(EX_BAD); } if (!to_stdout) { +#ifdef HAVE_FSYNC + int cnt; +#endif if (ret == FALSE) xstats.s_rwerrs--; /* Compensate overshoot below */ if (fflush(f) != 0) ret = FALSE; #ifdef HAVE_FSYNC - if (fsync(fdown(f)) != 0) + err = 0; + cnt = 0; + do { + if (fsync(fdown(f)) != 0) + err = geterrno(); + + if (err == EINVAL) + err = 0; + } while (err == EINTR && ++cnt < 10); + if (err != 0) ret = FALSE; #endif if (fclose(f) != 0) @@ -726,9 +762,9 @@ int amt; char *text; { - register int amount; - register long size; - register int tsize; + register int amount; /* XXX ??? */ + register off_t size; + register int tasize; BOOL ret = TRUE; size = info->f_rsize; @@ -747,7 +783,7 @@ amount = (amount / TBLOCK) * TBLOCK; amount = min(size, amount); amount = min(amount, amt); - tsize = tarsize(amount); + tasize = tarsize(amount); if ((*func)(arg, bigptr, amount) != amount) { ret = FALSE; @@ -757,7 +793,7 @@ } size -= amount; - buf_rwake(tsize); + buf_rwake(tasize); } return (ret); } @@ -769,7 +805,7 @@ static BOOL warned = FALSE; if (!warned && !nowarn) { - errmsgno(EX_BAD, "Warning: skipping leading '/' on filenames.\n"); + errmsgno(EX_BAD, "WARNING: skipping leading '/' on filenames.\n"); warned = TRUE; } /* XXX diff -ruN star-1.3.1/star/fflags.c star-1.4/star/fflags.c --- star-1.3.1/star/fflags.c Thu Jan 1 01:00:00 1970 +++ star-1.4/star/fflags.c Sun Jan 27 22:48:12 2002 @@ -0,0 +1,296 @@ +/* @(#)fflags.c 1.4 02/01/19 Copyright 2001-2002 J. Schilling */ +#ifndef lint +static char sccsid[] = + "@(#)fflags.c 1.4 02/01/19 Copyright 2001-2002 J. Schilling"; +#endif +/* + * Routines to handle extended file flags + * + * Copyright (c) 2001-2002 J. Schilling + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#ifdef USE_FFLAGS +#include +#include +#include "star.h" +#include "props.h" +#include "table.h" +#include +#include +#include +#include +#include +#include +#include "starsubs.h" +#ifdef __linux__ +#include +#include +#include +#endif + +#ifndef HAVE_ERRNO_DEF +extern int errno; +#endif + +EXPORT void get_fflags __PR((FINFO *info)); +EXPORT void set_fflags __PR((FINFO *info)); +EXPORT char *textfromflags __PR((FINFO *info, char *buf)); +EXPORT int texttoflags __PR((FINFO *info, char *buf)); + +EXPORT void +get_fflags(info) + register FINFO *info; +{ +#ifdef __linux__ + int f; + long l = 0L; + + if ((f = open(info->f_name, O_RDONLY|O_NDELAY)) >= 0) { + if (ioctl(f, EXT2_IOC_GETFLAGS, &l) >= 0) { + info->f_fflags = l; + if ((l & EXT2_NODUMP_FL) != 0) + info->f_flags |= F_NODUMP; + if (info->f_fflags != 0) + info->f_xflags |= XF_FFLAGS; + } else { + info->f_fflags = 0L; + } + close(f); + } +#else /* !__linux__ */ + info->f_fflags = 0L; +#endif +} + +EXPORT void +set_fflags(info) + register FINFO *info; +{ +/* + * Be careful: True64 includes a chflags() stub but no #defines for st_flags + */ +#if defined(HAVE_CHFLAGS) && defined(UF_SETTABLE) + char buf[512]; + + /* + * As for 14.2.2002 the man page of chflags() is wrong, the following + * code is a result of kernel source study. + * If we are not allowed to set the flags, try to only set the user + * settable flags. + */ + if ((chflags(info->f_name, info->f_fflags) < 0 && geterrno() == EPERM) || + chflags(info->f_name, info->f_fflags & UF_SETTABLE) < 0) + errmsg("Cannot set file flags '%s' for '%s'.\n", + textfromflags(info, buf), info->f_name); +#else +#ifdef __linux__ + char buf[512]; + int f; + Ulong flags; + Ulong oldflags; + BOOL err = TRUE; + /* + * Linux bites again! There is no define for the flags that are only + * settable by the root user. + */ +#define SF_MASK (EXT2_IMMUTABLE_FL|EXT2_APPEND_FL) + + if ((f = open(info->f_name, O_RDONLY|O_NONBLOCK)) >= 0) { + if (ioctl(f, EXT2_IOC_SETFLAGS, &info->f_fflags) >= 0) { + err = FALSE; + + } else if (geterrno() == EPERM) { + if (ioctl(f, EXT2_IOC_GETFLAGS, &oldflags) >= 0) { + + flags = info->f_fflags & ~SF_MASK; + oldflags &= SF_MASK; + flags |= oldflags; + if (ioctl(f, EXT2_IOC_SETFLAGS, &flags) >= 0) + err = FALSE; + } + } + close(f); + } + if (err) + errmsg("Cannot set file flags '%s' for '%s'.\n", + textfromflags(info, buf), info->f_name); +#endif + +#endif +} + + +LOCAL struct { + char *name; + Ulong flag; +} flagnames[] = { + /* shorter names per flag first, all prefixed by "no" */ +#ifdef SF_APPEND + { "sappnd", SF_APPEND }, + { "sappend", SF_APPEND }, +#endif + +#ifdef EXT2_APPEND_FL /* 'a' */ + { "sappnd", EXT2_APPEND_FL }, + { "sappend", EXT2_APPEND_FL }, +#endif + +#ifdef SF_ARCHIVED + { "arch", SF_ARCHIVED }, + { "archived", SF_ARCHIVED }, +#endif + +#ifdef SF_IMMUTABLE + { "schg", SF_IMMUTABLE }, + { "schange", SF_IMMUTABLE }, + { "simmutable", SF_IMMUTABLE }, +#endif +#ifdef EXT2_IMMUTABLE_FL /* 'i' */ + { "schg", EXT2_IMMUTABLE_FL }, + { "schange", EXT2_IMMUTABLE_FL }, + { "simmutable", EXT2_IMMUTABLE_FL }, +#endif + +#ifdef SF_NOUNLINK + { "sunlnk", SF_NOUNLINK }, + { "sunlink", SF_NOUNLINK }, +#endif + +/*--------------------------------------------------------------------------*/ + +#ifdef UF_APPEND + { "uappnd", UF_APPEND }, + { "uappend", UF_APPEND }, +#endif + +#ifdef UF_IMMUTABLE + { "uchg", UF_IMMUTABLE }, + { "uchange", UF_IMMUTABLE }, + { "uimmutable", UF_IMMUTABLE }, +#endif + +#ifdef EXT2_COMPR_FL /* 'c' */ + { "compress", EXT2_COMPR_FL }, +#endif + +#ifdef EXT2_NOATIME_FL /* 'A' */ + { "noatime", EXT2_NOATIME_FL }, +#endif + +#ifdef UF_NODUMP + { "nodump", UF_NODUMP }, +#endif +#ifdef EXT2_NODUMP_FL /* 'd' */ + { "nodump", EXT2_NODUMP_FL }, +#endif + +#ifdef UF_OPAQUE + { "opaque", UF_OPAQUE }, +#endif + +#ifdef EXT2_SECRM_FL /* 's' Purge before unlink */ + { "secdel", EXT2_SECRM_FL }, +#endif + +#ifdef EXT2_SYNC_FL /* 'S' */ + { "sync", EXT2_SYNC_FL }, +#endif + +#ifdef EXT2_UNRM_FL /* 'u' Allow to 'unrm' file the */ + { "undel", EXT2_UNRM_FL }, +#endif + +#ifdef UF_NOUNLINK + { "uunlnk", UF_NOUNLINK }, + { "uunlink", UF_NOUNLINK }, +#endif + { NULL, 0 } +}; +#define nflagnames ((sizeof(flagnames) / sizeof(flagnames[0])) -1) + +/* + * With 32 bits for flags and 512 bytes for the text buffer any name + * for a single flag may be <= 16 bytes. + */ +EXPORT char * +textfromflags(info, buf) + register FINFO *info; + register char *buf; +{ + register Ulong flags = info->f_fflags; + register char *n; + register char *p; + register int i; + + buf[0] = '\0'; + p = buf; + + for (i = 0; i < nflagnames; i++) { + if (flags & flagnames[i].flag) { + flags &= ~flagnames[i].flag; + if (p != buf) + *p++ = ','; + for (n = flagnames[i].name; *n; *p++ = *n++) + ; + } + } + *p = '\0'; + return (buf); +} + +EXPORT int +texttoflags(info, buf) + register FINFO *info; + register char *buf; +{ + register char *p; + register char *sep; + register int i; + register Ulong flags = 0; + + p = buf; + + while (*p) { + if ((sep = strchr(p, ',')) != NULL) + *sep = '\0'; + + for (i = 0; i < nflagnames; i++) { + if (streql(flagnames[i].name, p)) { + flags |= flagnames[i].flag; + break; + } + } +#ifdef nonono + if (i == nflagnames) { + not found! + } +#endif + if (sep != NULL) { + *sep++ = ','; + p = sep; + } else { + break; + } + } + info->f_fflags = flags; + return (0); +} + +#endif /* USE_FFLAGS */ diff -ruN star-1.3.1/star/fifo.c star-1.4/star/fifo.c --- star-1.3.1/star/fifo.c Sun Feb 25 12:13:09 2001 +++ star-1.4/star/fifo.c Tue Jan 1 19:19:54 2002 @@ -1,7 +1,7 @@ -/* @(#)fifo.c 1.21 01/02/25 Copyright 1989 J. Schilling */ +/* @(#)fifo.c 1.29 02/01/01 Copyright 1989 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)fifo.c 1.21 01/02/25 Copyright 1989 J. Schilling"; + "@(#)fifo.c 1.29 02/01/01 Copyright 1989 J. Schilling"; #endif /* * A "fifo" that uses shared memory between two processes @@ -30,23 +30,26 @@ #if !defined(HAVE_SMMAP) && !defined(HAVE_USGSHM) && !defined(HAVE_DOSALLOCSHAREDMEM) #undef FIFO /* We cannot have a FIFO on this platform */ #endif +#if !defined(HAVE_FORK) +#undef FIFO /* We cannot have a FIFO on this platform */ +#endif #ifdef FIFO #if !defined(USE_MMAP) && !defined(USE_USGSHM) #define USE_MMAP #endif + +#include +#include +#include /* includes */ #include -#include #if defined(HAVE_SMMAP) && defined(USE_MMAP) #include #endif -#include -#include -#include #include #include -#include #include "star.h" #include "fifo.h" +#include #include "starsubs.h" #ifndef HAVE_SMMAP @@ -127,8 +130,17 @@ if (obs == 0) obs = bs; - if (fs == 0) + if (fs == 0) { +#if defined(sun) && defined(mc68000) fs = 1*1024*1024; +#else +#if defined(__linux) && !defined(USE_MMAP) + fs = 4*1024*1024; +#else + fs = 8*1024*1024; +#endif +#endif + } if (fs < bs + obs) fs = bs + obs; if (fs < 2*obs) @@ -185,6 +197,11 @@ LOCAL void fifo_setparams() { + if (mp == NULL) { + comerrno(EX_BAD, "Panic: NULL fifo parameter structure.\n"); + /* NOTREACHED */ + return; + } mp->end = &mp->base[fs]; mp->size = fs; mp->ibs = ibs; @@ -335,8 +352,8 @@ if (ret < 0 || (ret == 0 && pid)) { if ((mp->flags & FIFO_EXIT) == 0) errmsg("Sync pipe read error on pid %d.\n", pid); - prstats(); - exit(1); + exprstats(1); + /* NOTREACHED */ } if (ret == 0) { /* @@ -510,7 +527,8 @@ if (rmp->getptr + cnt > rmp->end) { errmsgno(EX_BAD, "getptr >: %p %p %d end: %p\n", - rmp->getptr, &rmp->getptr[cnt], cnt, rmp->end); + (void *)rmp->getptr, (void *)&rmp->getptr[cnt], + cnt, (void *)rmp->end); } { /* Temporary until all modules know about mp->xxx */ @@ -573,10 +591,33 @@ EXPORT void fifo_exit() { + extern BOOL cflag; + + /* + * Note that we may be called with fifo not active. + */ + if (mp == NULL) + return; + + /* + * Tell other side of FIFO to exit(). + */ mp->flags |= FIFO_EXIT; + /* - * XXX Wake up other side ??? + * Wake up other side by closing the sync pipes. */ + if ((pid != 0) ^ cflag) { + EDEBUG(("Fifo_exit() from get prozess: cflag: %d pid: %d\n", cflag, pid)); + /* Get Prozess */ + close(mp->gpin); + close(mp->ppout); + } else { + EDEBUG(("Fifo_exit() from put prozess: cflag: %d pid: %d\n", cflag, pid)); + /* Put Prozess */ + close(mp->gpout); + close(mp->ppin); + } } EXPORT void @@ -626,7 +667,8 @@ if (amt < 0) comerr("write error getptr: %p, cnt: %d %p\n", - mp->getptr, cnt, &mp->getptr[cnt]); + (void *)mp->getptr, cnt, + (void *)&mp->getptr[cnt]); if (amt < cnt) error("wrote: %d (%d)\n", amt, cnt); @@ -654,7 +696,13 @@ comerr("Cannot get mmap for %d Bytes on /dev/zero.\n", size); close(f); - if (debug) errmsgno(EX_BAD, "shared memory segment attached: %p\n", (void *)addr); + if (debug) errmsgno(EX_BAD, "shared memory segment attached at: %p size %d\n", + (void *)addr, size); + +#ifdef HAVE_MLOCK + if (getuid() == 0 && mlock(addr, size) < 0) + errmsg("Cannot lock fifo memory.\n"); +#endif return (addr); } @@ -691,11 +739,21 @@ if ((addr = shmat(id, (char *)0, 0600)) == (char *)-1) comerr("shmat failed\n"); - if (debug) errmsgno(EX_BAD, "shared memory segment attached: %p\n", addr); + if (debug) errmsgno(EX_BAD, "shared memory segment attached at: %p size %d\n", + (void *)addr, size); if (shmctl(id, IPC_RMID, 0) < 0) comerr("shmctl failed\n"); +#ifdef SHM_LOCK + /* + * Although SHM_LOCK is standard, it seems that all versions of AIX + * ommit this definition. + */ + if (getuid() == 0 && shmctl(id, SHM_LOCK, 0) < 0) + errmsg("shmctl failed to lock shared memory segment\n"); +#endif + return (addr); } #endif @@ -715,8 +773,8 @@ if(DosAllocSharedMem(&addr,NULL,size,0X100L | 0x1L | 0x2L | 0x10L)) comerr("DosAllocSharedMem() failed\n"); - if (debug) - errmsgno(EX_BAD, "shared memory allocated at address: %x\n", addr); + if (debug) errmsgno(EX_BAD, "shared memory allocated attached at: %p size %d\n", + (void *)addr, size); return (addr); } diff -ruN star-1.3.1/star/fifo.h star-1.4/star/fifo.h --- star-1.3.1/star/fifo.h Thu Nov 9 07:58:18 2000 +++ star-1.4/star/fifo.h Tue Aug 14 15:21:08 2001 @@ -1,4 +1,4 @@ -/* @(#)fifo.h 1.6 00/11/09 Copyright 1989 J. Schilling */ +/* @(#)fifo.h 1.8 01/08/14 Copyright 1989 J. Schilling */ /* * Definitions for a "fifo" that uses * shared memory between two processes @@ -24,13 +24,14 @@ typedef struct { BOOL reading; /* true if currently reading from tape */ int swapflg; /* -1: init, 0: FALSE, 1: TRUE */ - long blocksize; /* Blocksize for each transfer */ - long blocks; /* Full blocks transfered on Volume */ - long parts; /* Bytes fom partial transferes on Volume */ - long lastsize; /* Size of last transfer (for backtape) */ - long Tblocks; /* Total blocks transfered */ - long Tparts; /* Total Bytes fom parttial transferes */ int volno; /* Volume # */ + int nblocks; /* Blocksize for each transfer in TBLOCK*/ + long blocksize; /* Blocksize for each transfer in bytes */ + long lastsize; /* Size of last transfer (for backtape) */ + Llong blocks; /* Full blocks transfered on Volume */ + Llong parts; /* Bytes fom partial transferes on Volume */ + Llong Tblocks; /* Total blocks transfered */ + Llong Tparts; /* Total Bytes fom parttial transferes */ } m_stats; typedef struct { diff -ruN star-1.3.1/star/header.c star-1.4/star/header.c --- star-1.3.1/star/header.c Sat Apr 7 10:25:51 2001 +++ star-1.4/star/header.c Fri May 10 10:28:01 2002 @@ -1,7 +1,7 @@ -/* @(#)header.c 1.43 01/04/07 Copyright 1985, 1995 J. Schilling */ +/* @(#)header.c 1.67 02/05/10 Copyright 1985, 1995 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)header.c 1.43 01/04/07 Copyright 1985, 1995 J. Schilling"; + "@(#)header.c 1.67 02/05/10 Copyright 1985, 1995 J. Schilling"; #endif /* * Handling routines to read/write, parse/create @@ -27,13 +27,12 @@ #include #include +#include #include "star.h" #include "props.h" #include "table.h" -#include #include #include -#include #include #define __XDEV__ /* Needed to activate _dev_major()/_dev_minor() */ #include @@ -56,24 +55,31 @@ /* 5 */ "ustar", /* 6 */ "xstar", /* 7 */ "xustar", - /* 8 */ "res8", /* Reserved */ - /* 9 */ "bar", - /*10 */ "cpio binary", - /*11 */ "cpio -c", - /*12 */ "cpio", - /*13 */ "cpio crc", - /*14 */ "cpio ascii", - /*15 */ "cpio ascii crc", + /* 8 */ "exustar", + /* 9 */ "pax", /* USTAR POSIX.1-2001 */ + /*10 */ "suntar", + /*11 */ "res11", /* Reserved */ + /*12 */ "res12", /* Reserved */ + /*13 */ "res13", /* Reserved */ + /*14 */ "res14", /* Reserved */ + /*15 */ "bar", + /*16 */ "cpio binary", + /*17 */ "cpio -c", + /*18 */ "cpio", + /*19 */ "cpio crc", + /*20 */ "cpio ascii", + /*21 */ "cpio ascii crc", }; extern FILE *tty; +extern FILE *vpr; extern long hdrtype; extern long chdrtype; extern int version; extern int swapflg; extern BOOL debug; extern BOOL numeric; -extern BOOL verbose; +extern int verbose; extern BOOL xflag; extern BOOL nflag; extern BOOL ignoreerr; @@ -82,13 +88,14 @@ extern BOOL nullout; extern BOOL modebits; -extern Ulong tsize; +extern Ullong tsize; extern char *bigbuf; extern int bigsize; LOCAL Ulong checksum __PR((TCB * ptb)); LOCAL Ulong bar_checksum __PR((TCB * ptb)); +LOCAL BOOL signedtarsum __PR((TCB *ptb, Ulong ocheck)); LOCAL BOOL isstmagic __PR((char* s)); LOCAL BOOL isxmagic __PR((TCB *ptb)); LOCAL BOOL ismagic __PR((char* s)); @@ -96,7 +103,8 @@ LOCAL BOOL strxneql __PR((char* s1, char* s2, int l)); LOCAL BOOL ustmagcheck __PR((TCB * ptb)); LOCAL void print_hdrtype __PR((int type)); -LOCAL int get_hdrtype __PR((TCB * ptb, BOOL isrecurse)); +EXPORT int get_hdrtype __PR((TCB * ptb, BOOL isrecurse)); +EXPORT int get_compression __PR((TCB * ptb)); EXPORT int get_tcb __PR((TCB * ptb)); EXPORT void put_tcb __PR((TCB * ptb, FINFO * info)); EXPORT void write_tcb __PR((TCB * ptb, FINFO * info)); @@ -118,11 +126,15 @@ EXPORT BOOL ia_change __PR((TCB * ptb, FINFO * info)); LOCAL BOOL checkeof __PR((TCB * ptb)); LOCAL BOOL eofblock __PR((TCB * ptb)); -EXPORT void astoo_cpio __PR((char* s, Ulong * l, int cnt)); -EXPORT void astoo __PR((char* s, Ulong * l)); -EXPORT void otoa __PR((char* s, Ulong l, int fieldw)); -EXPORT void astob __PR((char* s, Ulong * l, int fieldw)); -EXPORT void btoa __PR((char* s, Ulong l, int fieldw)); +LOCAL void astoo_cpio __PR((char* s, Ulong * l, int cnt)); +LOCAL void stoli __PR((char* s, Ulong * l)); +EXPORT void stolli __PR((char* s, Ullong * ull)); +LOCAL void litos __PR((char* s, Ulong l, int fieldw)); +EXPORT void llitos __PR((char* s, Ullong ull, int fieldw)); +LOCAL void stob __PR((char* s, Ulong * l, int fieldw)); +LOCAL void stollb __PR((char* s, Ullong * ull, int fieldw)); +LOCAL void btos __PR((char* s, Ulong l, int fieldw)); +LOCAL void llbtos __PR((char* s, Ullong ull, int fieldw)); /* * XXX Hier sollte eine tar/bar universelle Checksummenfunktion sein! @@ -211,36 +223,74 @@ #undef CHECKS LOCAL BOOL +signedtarsum(ptb, ocheck) + TCB *ptb; + Ulong ocheck; +{ + BOOL osigned = signedcksum; + Ulong check; + + signedcksum = !signedcksum; + check = checksum(ptb); + if (ocheck == check) { + errmsgno(EX_BAD, "WARNING: archive uses %s checksums.\n", + signedcksum?"signed":"unsigned"); + return (TRUE); + } + signedcksum = osigned; + return (FALSE); +} + +LOCAL BOOL isstmagic(s) char *s; { return (strxneql(s, stmagic, STMAGLEN)); } +/* + * Check for XUSTAR format. + * + * This is star's upcoming new standard format. This format understands star's + * old extended POSIX format and in future will write POSIX.1-2001 extensions + * using 'x' headers. + */ LOCAL BOOL isxmagic(ptb) TCB *ptb; { + register int i; + /* * prefix[130] is is granted to be '\0' with 'xstar'. */ if (ptb->xstar_dbuf.t_prefix[130] != '\0') return (FALSE); /* - * If atime[0] or ctime[0] is not an octal number it cannot be 'xstar'. + * If atime[0]...atime[10] or ctime[0]...ctime[10] + * is not a POSIX octal number it cannot be 'xstar'. + * With the octal representation we may store any date + * for 1970 +- 136 years (1834 ... 2106). After 2106 + * we will most likely always use POSIX.1-2001 'x' + * headers and thus don't need to check for base 256 + * numbers. */ - if (ptb->xstar_dbuf.t_atime[0] < '0' || - ptb->xstar_dbuf.t_atime[0] > '7') - return (FALSE); - if (ptb->xstar_dbuf.t_ctime[0] < '0' || - ptb->xstar_dbuf.t_ctime[0] > '7') - return (FALSE); + for (i = 0; i < 11; i++) { + if (ptb->xstar_dbuf.t_atime[i] < '0' || + ptb->xstar_dbuf.t_atime[i] > '7') + return (FALSE); + if (ptb->xstar_dbuf.t_ctime[i] < '0' || + ptb->xstar_dbuf.t_ctime[i] > '7') + return (FALSE); + } /* - * We may need to remove this in future. + * Check for both POSIX compliant end of number characters. */ - if (ptb->xstar_dbuf.t_atime[11] != ' ' || - ptb->xstar_dbuf.t_ctime[11] != ' ') + if ((ptb->xstar_dbuf.t_atime[11] != ' ' && + ptb->xstar_dbuf.t_atime[11] != '\0') || + (ptb->xstar_dbuf.t_ctime[11] != ' ' && + ptb->xstar_dbuf.t_ctime[11] != '\0')) return (FALSE); return (TRUE); @@ -295,7 +345,7 @@ error("%s%s archive.\n", isswapped?"swapped ":"", hdrtxt[type]); } -LOCAL int +EXPORT int get_hdrtype(ptb, isrecurse) TCB *ptb; BOOL isrecurse; @@ -304,10 +354,17 @@ Ulong ocheck; int ret = H_UNDEF; - astoo(ptb->dbuf.t_chksum, &ocheck); + stoli(ptb->dbuf.t_chksum, &ocheck); check = checksum(ptb); - if (ocheck != check) + if (ocheck != check && !signedtarsum(ptb, ocheck)) { + if (debug && !isrecurse) { + errmsgno(EX_BAD, + "Bad tar checksum at: %lld: 0%lo should be 0%lo.\n", + tblocks(), + ocheck, check); + } goto nottar; + } if (isstmagic(ptb->dbuf.t_magic)) { /* Check for 'tar\0' at end */ if (ustmagcheck(ptb)) @@ -318,10 +375,21 @@ return (ret); } if (ustmagcheck(ptb)) { /* 'ustar\000' POSIX magic */ - if (isxmagic(ptb)) - ret = H_XUSTAR; - else - ret = H_USTAR; + if (isxmagic(ptb)) { + if (ptb->ustar_dbuf.t_typeflag == 'g' || + ptb->ustar_dbuf.t_typeflag == 'x') + ret = H_EXUSTAR; + else + ret = H_XUSTAR; + } else { + if (ptb->ustar_dbuf.t_typeflag == 'g' || + ptb->ustar_dbuf.t_typeflag == 'x') + ret = H_PAX; + else if (ptb->ustar_dbuf.t_typeflag == 'X') + ret = H_SUNTAR; + else + ret = H_USTAR; + } if (debug) print_hdrtype(ret); return (ret); } @@ -356,14 +424,20 @@ nottar: if (ptb->bar_dbuf.bar_magic[0] == 'V') { - astoo(ptb->bar_dbuf.t_chksum, &ocheck); + stoli(ptb->bar_dbuf.t_chksum, &ocheck); check = bar_checksum(ptb); if (ocheck == check) { ret = H_BAR; if (debug) print_hdrtype(ret); return (ret); + } else if (debug && !isrecurse) { + errmsgno(EX_BAD, + "Bad bar checksum at: %lld: 0%lo should be 0%lo.\n", + tblocks(), + ocheck, check); } + } if (strxneql((char *)ptb, "070701", 6)) { ret = H_CPIO_ASC; @@ -413,6 +487,25 @@ } EXPORT int +get_compression(ptb) + TCB *ptb; +{ + char *p = (char *)ptb; + + if (p[0] == '\037') { + if ((p[1] == '\037') || /* Packed */ + (p[1] == '\213') || /* Gzip compressed */ + (p[1] == '\235') || /* LZW compressed */ + (p[1] == '\236') || /* Freezed */ + (p[1] == '\240')) /* SCO LZH compressed*/ + return (C_GZIP); + } + if (p[0] == 'B' && p[1] == 'Z' && p[2] == 'h') + return (C_BZIP2); + return (C_NONE); +} + +EXPORT int get_tcb(ptb) TCB *ptb; { @@ -457,7 +550,7 @@ if (H_TYPE(hdrtype) == H_BAR) { comerrno(EX_BAD, "Can't handle bar archives (yet).\n"); } - if (H_TYPE(hdrtype) >= H_CPIO) { + if (H_TYPE(hdrtype) >= H_CPIO_BASE) { /* XXX JS Test */if (H_TYPE(hdrtype) == H_CPIO_CHR) { /* XXX JS Test */FINFO info; /* XXX JS Test */tcb_to_info(ptb, &info); @@ -465,18 +558,15 @@ comerrno(EX_BAD, "Can't handle cpio archives (yet).\n"); } if (H_TYPE(hdrtype) == H_UNDEF) { - char *p = (char *)ptb; + switch (get_compression(ptb)) { - if (p[0] == '\037') { - if ((p[1] == '\037') || /* Packed */ - (p[1] == '\213') || /* Gzip compressed */ - (p[1] == '\235') || /* LZW compressed */ - (p[1] == '\236') || /* Freezed */ - (p[1] == '\240')) /* SCO LZH compressed*/ + case C_GZIP: comerrno(EX_BAD, "Archive is compressed, try to use the -z option.\n"); - } - if (p[0] == 'B' && p[1] == 'Z' && p[2] == 'h') + break; + case C_BZIP2: comerrno(EX_BAD, "Archive is bzip2 compressed, try to use the -bz option.\n"); + break; + } if (!ignoreerr) { comerrno(EX_BAD, "Unknown archive type (neither tar, nor bar/cpio).\n"); @@ -485,20 +575,20 @@ if (chdrtype != H_UNDEF && chdrtype != hdrtype) { errmsgno(EX_BAD, "Found: "); print_hdrtype(hdrtype); - errmsgno(EX_BAD, "Warning: extracting as "); + errmsgno(EX_BAD, "WARNING: extracting as "); print_hdrtype(chdrtype); hdrtype = chdrtype; } setprops(hdrtype); } - if ((eof = ptb->dbuf.t_name[0] == '\0' && checkeof(ptb))) { - if (!ignoreerr) - return (EOF); + eof = (ptb->dbuf.t_name[0] == '\0') && checkeof(ptb); + if (eof && !ignoreerr) { + return (EOF); } /* * XXX Hier muß eine Universalchecksummenüberprüfung hin */ - astoo(ptb->dbuf.t_chksum, &ocheck); + stoli(ptb->dbuf.t_chksum, &ocheck); check = checksum(ptb); /* * check == 0 : genullter Block. @@ -509,14 +599,22 @@ switch (H_TYPE(hdrtype)) { case H_XUSTAR: + case H_EXUSTAR: if (ismagic(tmagic) && isxmagic(ptb)) return (0); + /* + * Both formats are equivalent. + * Acept XSTAR too. + */ + /* FALLTHROUGH */ case H_XSTAR: if (ismagic(tmagic) && isstmagic(ptb->xstar_dbuf.t_xmagic)) return (0); break; + case H_PAX: case H_USTAR: + case H_SUNTAR: if (ismagic(tmagic)) return (0); break; @@ -535,7 +633,7 @@ case H_OTAR: return (0); } - errmsgno(EX_BAD, "Wrong magic at: %d: '%.8s'.\n", + errmsgno(EX_BAD, "Wrong magic at: %lld: '%.8s'.\n", tblocks(), tmagic); /* * Allow buggy gnu Volheaders & Multivolheaders to work @@ -544,16 +642,17 @@ return (0); } else if (eof) { - errmsgno(EX_BAD, "EOF Block at: %d ignored.\n", + errmsgno(EX_BAD, "EOF Block at: %lld ignored.\n", tblocks()); } else { - errmsgno(EX_BAD, "Checksum error at: %d: 0%lo should be 0%lo.\n", + if (signedtarsum(ptb, ocheck)) + return (0); + errmsgno(EX_BAD, "Checksum error at: %lld: 0%lo should be 0%lo.\n", tblocks(), ocheck, check); } } while (ignoreerr); - prstats(); - exit(EX_BAD); + exprstats(EX_BAD); /* NOTREACHED */ return (EOF); /* Keep lint happy */ } @@ -569,6 +668,8 @@ if (info->f_flags & (F_LONGNAME|F_LONGLINK)) x1++; + if (info->f_xflags & (XF_PATH|XF_LINKPATH)) + x1++; /*XXX start alter code und Test */ if (( (info->f_flags & F_ADDSLASH) ? 1:0 + @@ -577,21 +678,23 @@ info->f_lnamelen > props.pr_maxslname) x2++; - if (x1 != x2) { -error("type: %ld name: %s x1 %d x2 %d namelen: %ld prefix: %s lnamelen: %ld\n", + if ((x1 != x2) && info->f_xftype != XT_META) { +error("type: %ld name: '%s' x1 %d x2 %d namelen: %ld prefix: '%s' lnamelen: %ld\n", info->f_filetype, info->f_name, x1, x2, info->f_namelen, ptb->dbuf.t_prefix, info->f_lnamelen); - } /*XXX ende alter code und Test */ - if (x1 || x2) { + if (x1 || x2 || (info->f_xflags != 0)) { if ((info->f_flags & F_TCB_BUF) != 0) { /* TCB is on buffer */ - movebytes(ptb, &tb, TBLOCK); + movetcb(ptb, &tb); ptb = &tb; info->f_flags &= ~F_TCB_BUF; } - write_longnames(info); + if (info->f_xflags != 0) + info_to_xhdr(info, ptb); + else + write_longnames(info); } write_tcb(ptb, info); } @@ -603,17 +706,17 @@ { if (tsize > 0) { TCB tb; - long left; - Ulong size = info->f_rsize; + Llong left; + off_t size = info->f_rsize; left = tsize - tblocks(); if (is_link(info)) size = 0L; /* file + tcb + EOF */ - if (left < (long)(tarblocks(size)+1+2)) { + if (left < (tarblocks(size)+1+2)) { if ((info->f_flags & F_TCB_BUF) != 0) { - movebytes(ptb, &tb, TBLOCK); + movetcb(ptb, &tb); ptb = &tb; info->f_flags &= ~F_TCB_BUF; } @@ -622,9 +725,9 @@ } if (!nullout) { /* 17 (> 16) Bit !!! */ if (props.pr_fillc == '0') - otoa(ptb->dbuf.t_chksum, checksum(ptb) & 0x1FFFF, 7); + litos(ptb->dbuf.t_chksum, checksum(ptb) & 0x1FFFF, 7); else - otoa(ptb->dbuf.t_chksum, checksum(ptb) & 0x1FFFF, 6); + litos(ptb->dbuf.t_chksum, checksum(ptb) & 0x1FFFF, 6); } if ((info->f_flags & F_TCB_BUF) != 0) /* TCB is on buffer */ put_block(); @@ -648,11 +751,12 @@ gettimeofday(&tv, (struct timezone *)0); fillbytes((char *)&finfo, sizeof (FINFO), '\0'); - fillbytes((char *)&tb, TBLOCK, '\0'); + filltcb(&tb); finfo.f_name = name; finfo.f_namelen = strlen(name); finfo.f_xftype = XT_VOLHDR; finfo.f_mtime = tv.tv_sec; + finfo.f_mnsec = tv.tv_usec*1000; finfo.f_tcb = &tb; if (!name_to_tcb(&finfo, &tb)) /* Name too long */ @@ -686,30 +790,70 @@ return; if (props.pr_fillc == '0') { + /* + * This is a POSIX compliant header, it is allowed to use + * 7 bytes from 8 byte headers as POSIX only requires a ' ' or + * '\0' as last char. + */ if (modebits) - otoa(ptb->dbuf.t_mode, (info->f_mode|info->f_type) & 0xFFFF, 7); + litos(ptb->dbuf.t_mode, (info->f_mode|info->f_type) & 0xFFFF, 7); else - otoa(ptb->dbuf.t_mode, info->f_mode & 0xFFFF, 7); - otoa(ptb->dbuf.t_uid, info->f_uid & 0xFFFF, 7); - otoa(ptb->dbuf.t_gid, info->f_gid & 0xFFFF, 7); + litos(ptb->dbuf.t_mode, info->f_mode & 0xFFFF, 7); + + if (info->f_uid > MAXOCTAL7 && (props.pr_flags & PR_XHDR)) { + info->f_xflags |= XF_UID; + } + litos(ptb->dbuf.t_uid, info->f_uid & MAXOCTAL7, 7); + + if (info->f_gid > MAXOCTAL7 && (props.pr_flags & PR_XHDR)) { + info->f_xflags |= XF_GID; + } + litos(ptb->dbuf.t_gid, info->f_gid & MAXOCTAL7, 7); } else { + /* + * This is a pre POSIX header, it is only allowed to use + * 6 bytes from 8 byte headers as historic TAR requires a ' ' + * and a '\0' as last char. + */ if (modebits) - otoa(ptb->dbuf.t_mode, (info->f_mode|info->f_type) & 0xFFFF, 6); + litos(ptb->dbuf.t_mode, (info->f_mode|info->f_type) & 0xFFFF, 6); else - otoa(ptb->dbuf.t_mode, info->f_mode & 0xFFFF, 6); - otoa(ptb->dbuf.t_uid, info->f_uid & 0xFFFF, 6); - otoa(ptb->dbuf.t_gid, info->f_gid & 0xFFFF, 6); + litos(ptb->dbuf.t_mode, info->f_mode & 0xFFFF, 6); + + if (info->f_uid > MAXOCTAL6 && (props.pr_flags & PR_XHDR)) { + info->f_xflags |= XF_UID; + } + litos(ptb->dbuf.t_uid, info->f_uid & MAXOCTAL6, 6); + + if (info->f_gid > MAXOCTAL7 && (props.pr_flags & PR_XHDR)) { + info->f_xflags |= XF_GID; + } + litos(ptb->dbuf.t_gid, info->f_gid & MAXOCTAL6, 6); + } + + if (info->f_rsize > MAXOCTAL11 && (props.pr_flags & PR_XHDR)) { + info->f_xflags |= XF_SIZE; + } + if (info->f_rsize <= MAXINT32) { + litos(ptb->dbuf.t_size, (Ulong)info->f_rsize, 11); + } else { + llitos(ptb->dbuf.t_size, (Ullong)info->f_rsize, 11); } - otoa(ptb->dbuf.t_size, info->f_rsize, 11); - otoa(ptb->dbuf.t_mtime, (Ulong)info->f_mtime, 11); + litos(ptb->dbuf.t_mtime, (Ulong)info->f_mtime, 11); ptb->dbuf.t_linkflag = XTTOUS(info->f_xftype); if (H_TYPE(hdrtype) == H_USTAR) { info_to_ustar(info, ptb); + } else if (H_TYPE(hdrtype) == H_PAX) { + info_to_ustar(info, ptb); + } else if (H_TYPE(hdrtype) == H_SUNTAR) { + info_to_ustar(info, ptb); } else if (H_TYPE(hdrtype) == H_XSTAR) { info_to_xstar(info, ptb); } else if (H_TYPE(hdrtype) == H_XUSTAR) { info_to_xstar(info, ptb); + } else if (H_TYPE(hdrtype) == H_EXUSTAR) { + info_to_xstar(info, ptb); } else if (H_TYPE(hdrtype) == H_GNUTAR) { info_to_gnutar(info, ptb); } else if (H_TYPE(hdrtype) == H_STAR) { @@ -723,24 +867,44 @@ register TCB *ptb; { ptb->dbuf.t_vers = STVERSION; - otoa(ptb->dbuf.t_filetype, info->f_filetype & 0xFFFF, 6); /* XXX -> 7 ??? */ - otoa(ptb->dbuf.t_type, info->f_type & 0xFFFF, 11); - otoa(ptb->dbuf.t_rdev, info->f_rdev, 11); + litos(ptb->dbuf.t_filetype, info->f_filetype & 0xFFFF, 6); /* XXX -> 7 ??? */ + litos(ptb->dbuf.t_type, info->f_type & 0xFFFF, 11); +#ifdef needed + /* XXX we need to do something if st_rdev is > 32 bits */ + if ((info->f_rdevmaj > MAXOCTAL7 || info->f_rdevmin > MAXOCTAL7) && + (props.pr_flags & PR_XHDR)) { + info->f_xflags |= XF_DEVMAJOR|XF_DEVMINOR; + } +#endif + litos(ptb->dbuf.t_rdev, info->f_rdev, 11); #ifdef DEV_MINOR_NONCONTIG ptb->dbuf.t_devminorbits = '@'; + if (props.pr_flags & PR_XHDR) { + info->f_xflags |= XF_DEVMAJOR|XF_DEVMINOR; + } #else ptb->dbuf.t_devminorbits = '@' + minorbits; #endif - otoa(ptb->dbuf.t_atime, (Ulong)info->f_atime, 11); - otoa(ptb->dbuf.t_ctime, (Ulong)info->f_ctime, 11); + litos(ptb->dbuf.t_atime, (Ulong)info->f_atime, 11); + litos(ptb->dbuf.t_ctime, (Ulong)info->f_ctime, 11); /* strcpy(ptb->dbuf.t_magic, stmagic);*/ ptb->dbuf.t_magic[0] = 't'; ptb->dbuf.t_magic[1] = 'a'; ptb->dbuf.t_magic[2] = 'r'; if (!numeric) { nameuid(ptb->dbuf.t_uname, STUNMLEN, info->f_uid); + /* XXX Korrektes overflowchecking */ + if (ptb->dbuf.t_uname[STUNMLEN-1] != '\0' && + props.pr_flags & PR_XHDR) { + info->f_xflags |= XF_UNAME; + } namegid(ptb->dbuf.t_gname, STGNMLEN, info->f_gid); + /* XXX Korrektes overflowchecking */ + if (ptb->dbuf.t_gname[STGNMLEN-1] != '\0' && + props.pr_flags & PR_XHDR) { + info->f_xflags |= XF_GNAME; + } if (*ptb->dbuf.t_uname) { info->f_uname = ptb->dbuf.t_uname; info->f_umaxlen = STUNMLEN; @@ -751,8 +915,14 @@ } } - if (is_sparse(info)) - otoa(ptb->xstar_in_dbuf.t_realsize, info->f_size, 11); + if (is_sparse(info)) { + /* XXX Korrektes overflowchecking fuer xhdr */ + if (info->f_size <= MAXINT32) { + litos(ptb->xstar_in_dbuf.t_realsize, (Ulong)info->f_size, 11); + } else { + llitos(ptb->xstar_in_dbuf.t_realsize, (Ullong)info->f_size, 11); + } + } } LOCAL void @@ -761,7 +931,7 @@ register TCB *ptb; { /*XXX solaris hat illegalerweise mehr als 12 Bit in t_mode !!! - * otoa(ptb->dbuf.t_mode, info->f_mode|info->f_type & 0xFFFF, 6); XXX -> 7 ??? + * litos(ptb->dbuf.t_mode, info->f_mode|info->f_type & 0xFFFF, 6); XXX -> 7 ??? */ /* strcpy(ptb->ustar_dbuf.t_magic, magic);*/ ptb->ustar_dbuf.t_magic[0] = 'u'; @@ -777,7 +947,9 @@ ptb->ustar_dbuf.t_version[1] = '0'; if (!numeric) { + /* XXX Korrektes overflowchecking fuer xhdr */ nameuid(ptb->ustar_dbuf.t_uname, TUNMLEN, info->f_uid); + /* XXX Korrektes overflowchecking fuer xhdr */ namegid(ptb->ustar_dbuf.t_gname, TGNMLEN, info->f_gid); if (*ptb->ustar_dbuf.t_uname) { info->f_uname = ptb->ustar_dbuf.t_uname; @@ -788,11 +960,22 @@ info->f_gmaxlen = TGNMLEN; } } - otoa(ptb->ustar_dbuf.t_devmajor, info->f_rdevmaj, 7); -#if DEV_MINOR_BITS > 21 - if (info->f_rdevmin > 07777777) { + if (info->f_rdevmaj > MAXOCTAL7 && (props.pr_flags & PR_XHDR)) { + info->f_xflags |= XF_DEVMAJOR; + } + litos(ptb->ustar_dbuf.t_devmajor, info->f_rdevmaj, 7); +#if DEV_MINOR_BITS > 21 /* XXX */ + /* + * XXX The DEV_MINOR_BITS autoconf macro is only tested with 32 bit + * XXX ints but this does not matter as it is sufficient to know that + * XXX it will not fit into a 7 digit octal number. + */ + if (info->f_rdevmin > MAXOCTAL7) { extern BOOL hpdev; + if (props.pr_flags & PR_XHDR) { + info->f_xflags |= XF_DEVMINOR; + } if (!is_special(info)) { /* * Until we know how to deal with this, we reduce @@ -801,7 +984,7 @@ info->f_rdevmin = 0; goto doposix; } - if ((info->f_rdevmin <= 077777777) && hpdev) { + if ((info->f_rdevmin <= MAXOCTAL8) && hpdev) { char c; /* @@ -810,10 +993,15 @@ * violates the POSIX specs. */ c = ptb->ustar_dbuf.t_prefix[0]; - otoa(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 8); + litos(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 8); ptb->ustar_dbuf.t_prefix[0] = c; } else { - btoa(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 7); + /* + * XXX If we ever need to write more than a long into + * XXX devmajor, we need to change llitos() to check + * XXX for 7 char limits too. + */ + btos(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 7); } } else #endif @@ -821,7 +1009,7 @@ #if DEV_MINOR_BITS > 21 doposix: #endif - otoa(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 7); + litos(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 7); } } @@ -831,8 +1019,8 @@ register TCB *ptb; { info_to_ustar(info, ptb); - otoa(ptb->xstar_dbuf.t_atime, (Ulong)info->f_atime, 11); - otoa(ptb->xstar_dbuf.t_ctime, (Ulong)info->f_ctime, 11); + litos(ptb->xstar_dbuf.t_atime, (Ulong)info->f_atime, 11); + litos(ptb->xstar_dbuf.t_ctime, (Ulong)info->f_ctime, 11); /* * Help recognition in isxmagic(), make sure that prefix[130] is null. @@ -845,8 +1033,14 @@ ptb->xstar_dbuf.t_xmagic[1] = 'a'; ptb->xstar_dbuf.t_xmagic[2] = 'r'; } - if (is_sparse(info)) - otoa(ptb->xstar_in_dbuf.t_realsize, info->f_size, 11); + if (is_sparse(info)) { + /* XXX Korrektes overflowchecking fuer xhdr */ + if (info->f_size <= MAXINT32) { + litos(ptb->xstar_in_dbuf.t_realsize, (Ulong)info->f_size, 11); + } else { + llitos(ptb->xstar_in_dbuf.t_realsize, (Ullong)info->f_size, 11); + } + } } LOCAL void @@ -869,18 +1063,23 @@ } } if (info->f_xftype == XT_CHR || info->f_xftype == XT_BLK) { - otoa(ptb->ustar_dbuf.t_devmajor, info->f_rdevmaj, 6); /* XXX -> 7 ??? */ - otoa(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 6); /* XXX -> 7 ??? */ + litos(ptb->ustar_dbuf.t_devmajor, info->f_rdevmaj, 6); /* XXX -> 7 ??? */ + litos(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 6); /* XXX -> 7 ??? */ } /* * XXX GNU tar only fill this if doing a gnudump. */ - otoa(ptb->gnu_dbuf.t_atime, (Ulong)info->f_atime, 11); - otoa(ptb->gnu_dbuf.t_ctime, (Ulong)info->f_ctime, 11); + litos(ptb->gnu_dbuf.t_atime, (Ulong)info->f_atime, 11); + litos(ptb->gnu_dbuf.t_ctime, (Ulong)info->f_ctime, 11); - if (is_sparse(info)) - otoa(ptb->gnu_in_dbuf.t_realsize, info->f_size, 11); + if (is_sparse(info)) { + if (info->f_size <= MAXINT32) { + litos(ptb->gnu_in_dbuf.t_realsize, (Ulong)info->f_size, 11); + } else { + llitos(ptb->gnu_in_dbuf.t_realsize, (Ullong)info->f_size, 11); + } + } } EXPORT int @@ -892,8 +1091,12 @@ char xname; char xlink; Ulong ul; + Ullong ull; + int xt = XT_BAD; + int rxt = XT_BAD; static BOOL posixwarn = FALSE; static BOOL namewarn = FALSE; +static BOOL modewarn = FALSE; /* * F_HAS_NAME is only used from list.c when the -listnew option is @@ -904,47 +1107,83 @@ info->f_lname = ptb->dbuf.t_linkname; info->f_uname = info->f_gname = NULL; info->f_umaxlen = info->f_gmaxlen = 0L; - info->f_xftype = 0; - info->f_offset = 0; + info->f_xftype = XT_BAD; + info->f_rxftype = XT_BAD; + info->f_xflags = 0; + info->f_contoffset = (off_t)0; info->f_flags &= F_HAS_NAME; + info->f_fflags = 0L; -/* XXX JS Test */if (H_TYPE(hdrtype) >= H_CPIO) { +/* XXX JS Test */if (H_TYPE(hdrtype) >= H_CPIO_BASE) { /* XXX JS Test */cpiotcb_to_info(ptb, info); /* XXX JS Test */list_file(info); /* XXX JS Test */return (ret); /* XXX JS Test */} - /* - * Handle very long names - */ - if ((info->f_flags & F_HAS_NAME) == 0 && + while (pr_isxheader(ptb->dbuf.t_linkflag)) { + /* + * Handle POSIX.1-2001 extensions. + */ + if ((ptb->dbuf.t_linkflag == LF_XHDR || + ptb->dbuf.t_linkflag == LF_VU_XHDR)) { + ret = tcb_to_xhdr(ptb, info); + if (ret != 0) + return (ret); + + xt = info->f_xftype; + rxt = info->f_rxftype; + } + /* + * Handle very long names the old (star & gnutar) way. + */ + if ((info->f_flags & F_HAS_NAME) == 0 && props.pr_nflags & PR_LONG_NAMES) { - while (ptb->dbuf.t_linkflag == LF_LONGLINK || - ptb->dbuf.t_linkflag == LF_LONGNAME) - ret = tcb_to_longname(ptb, info); + while (ptb->dbuf.t_linkflag == LF_LONGLINK || + ptb->dbuf.t_linkflag == LF_LONGNAME) { + ret = tcb_to_longname(ptb, info); + } + } + } + if (!pr_validtype(ptb->dbuf.t_linkflag)) { + errmsgno(EX_BAD, + "WARNING: Archive contains unknown typeflag '%c' (0x%02X).\n", + ptb->dbuf.t_linkflag, ptb->dbuf.t_linkflag); } if (ptb->dbuf.t_name[NAMSIZ] == '\0') { - if (!nowarn && !namewarn) { + if (ptb->dbuf.t_name[NAMSIZ-1] == '\0') { + if (!nowarn && !modewarn) { + errmsgno(EX_BAD, + "WARNING: Archive violates POSIX 1003.1 (mode field starts with null byte).\n"); + modewarn = TRUE; + } + } else if (!nowarn && !namewarn) { errmsgno(EX_BAD, - "Warning: Archive violates POSIX 1003.1 (100 char filename is null terminated).\n"); + "WARNING: Archive violates POSIX 1003.1 (100 char filename is null terminated).\n"); namewarn = TRUE; } ptb->dbuf.t_name[NAMSIZ] = ' '; } - astoo(ptb->dbuf.t_mode, &info->f_mode); + stoli(ptb->dbuf.t_mode, &info->f_mode); if (info->f_mode & ~07777) { if (!nowarn && !modebits && H_TYPE(hdrtype) == H_USTAR && !posixwarn) { errmsgno(EX_BAD, - "Warning: Archive violates POSIX 1003.1 (too many bits in mode field).\n"); + "WARNING: Archive violates POSIX 1003.1 (too many bits in mode field).\n"); posixwarn = TRUE; } info->f_mode &= 07777; } - astoo(ptb->dbuf.t_uid, &info->f_uid); - astoo(ptb->dbuf.t_gid, &info->f_gid); - astoo(ptb->dbuf.t_size, &info->f_size); + if ((info->f_xflags & XF_UID) == 0) + stoli(ptb->dbuf.t_uid, &info->f_uid); + if ((info->f_xflags & XF_UID) == 0) + stoli(ptb->dbuf.t_gid, &info->f_gid); + if ((info->f_xflags & XF_SIZE) == 0) { + stolli(ptb->dbuf.t_size, &ull); + info->f_size = ull; + } info->f_rsize = 0L; + +#ifdef OLD /*XXX if (ptb->dbuf.t_linkflag < LNKTYPE)*/ /* Alte star Version!!! */ if (ptb->dbuf.t_linkflag != LNKTYPE && ptb->dbuf.t_linkflag != DIRTYPE) { @@ -953,11 +1192,29 @@ */ info->f_rsize = info->f_size; } - astoo(ptb->dbuf.t_mtime, &ul); - info->f_mtime = (time_t)ul; +#else + switch (ptb->dbuf.t_linkflag) { - info->f_ansec = info->f_mnsec = info->f_cnsec = 0L; + case LNKTYPE: + case DIRTYPE: + case CHRTYPE: + case BLKTYPE: + case FIFOTYPE: + case LF_META: + break; + default: + info->f_rsize = info->f_size; + break; + } +#endif + if ((info->f_xflags & XF_MTIME) == 0) { + stoli(ptb->dbuf.t_mtime, &ul); + info->f_mtime = (time_t)ul; + info->f_mnsec = 0L; + } + + info->f_typeflag = ptb->ustar_dbuf.t_typeflag; switch (H_TYPE(hdrtype)) { @@ -966,11 +1223,14 @@ case H_OTAR: tar_to_info(ptb, info); break; + case H_PAX: case H_USTAR: + case H_SUNTAR: ustar_to_info(ptb, info); break; case H_XSTAR: case H_XUSTAR: + case H_EXUSTAR: xstar_to_info(ptb, info); break; case H_GNUTAR: @@ -980,6 +1240,21 @@ star_to_info(ptb, info); break; } + info->f_rxftype = info->f_xftype; + if (rxt != XT_BAD) { + info->f_rxftype = rxt; + info->f_filetype = XTTOST(info->f_rxftype); + info->f_type = XTTOIF(info->f_rxftype); + /* + * XT_LINK may be any 'real' file type, + * XT_META may be either a regular file or a contigouos file. + */ + if (info->f_xftype != XT_LINK && info->f_xftype != XT_META) + info->f_xftype = info->f_rxftype; + } + if (xt != XT_BAD) { + info->f_xftype = xt; + } /* * Hack for list module (option -newest) ... @@ -992,6 +1267,7 @@ /* * Handle long name in posix split form now. + * Also copy ptb->dbuf.t_linkname[] if namelen is == 100. */ tcb_to_name(ptb, info); @@ -1011,7 +1287,7 @@ if (ptb->dbuf.t_name[strlen(ptb->dbuf.t_name) - 1] == '/') { typeflag = DIRTYPE; info->f_filetype = F_DIR; - info->f_rsize = 0L; /* XXX hier?? siehe oben */ + info->f_rsize = (off_t)0; /* XXX hier?? siehe oben */ } else if (typeflag == SYMTYPE) { info->f_filetype = F_SLINK; } else if (typeflag != DIRTYPE) { @@ -1021,6 +1297,7 @@ info->f_type = XTTOIF(info->f_xftype); info->f_rdevmaj = info->f_rdevmin = info->f_rdev = 0; info->f_ctime = info->f_atime = info->f_mtime; + info->f_cnsec = info->f_ansec = 0L; } LOCAL void @@ -1029,6 +1306,7 @@ register FINFO *info; { Ulong id; + Ullong ull; int mbits; version = ptb->dbuf.t_vers; @@ -1036,8 +1314,8 @@ tar_to_info(ptb, info); return; } - astoo(ptb->dbuf.t_filetype, &info->f_filetype); - astoo(ptb->dbuf.t_type, &info->f_type); + stoli(ptb->dbuf.t_filetype, &info->f_filetype); + stoli(ptb->dbuf.t_type, &info->f_type); /* * star Erweiterungen sind wieder ANSI kompatibel, d.h. linkflag * hält den echten Dateityp (LONKLINK, LONGNAME, SPARSE ...) @@ -1047,59 +1325,81 @@ else info->f_xftype = USTOXT(ptb->ustar_dbuf.t_typeflag); - astoo(ptb->dbuf.t_rdev, &info->f_rdev); - mbits = ptb->dbuf.t_devminorbits - '@'; - if (mbits == 0) { - static BOOL dwarned = FALSE; - if (!dwarned) { - errmsgno(EX_BAD, + stoli(ptb->dbuf.t_rdev, &info->f_rdev); + if ((info->f_xflags & (XF_DEVMAJOR|XF_DEVMINOR)) != + (XF_DEVMAJOR|XF_DEVMINOR)) { + mbits = ptb->dbuf.t_devminorbits - '@'; + if (mbits == 0) { + static BOOL dwarned = FALSE; + if (!dwarned) { + errmsgno(EX_BAD, #ifdef DEV_MINOR_NONCONTIG - "Warning: Minor device numbers are non contiguous, devices may not be extracted correctly.\n"); + "WARNING: Minor device numbers are non contiguous, devices may not be extracted correctly.\n"); #else - "Warning: The archiving system used non contiguous minor numbers, cannot extract devices correctly.\n"); + "WARNING: The archiving system used non contiguous minor numbers, cannot extract devices correctly.\n"); #endif - dwarned = TRUE; + dwarned = TRUE; + } + /* + * Let us hope that both, the archiving and the + * extracting system use the same major()/minor() + * mapping. + */ + info->f_rdevmaj = major(info->f_rdev); + info->f_rdevmin = minor(info->f_rdev); + } else { + /* + * Convert from remote major()/minor() mapping to + * local major()/minor() mapping. + */ + if (mbits < 0) /* Old star format */ + mbits = 8; + info->f_rdevmaj = _dev_major(mbits, info->f_rdev); + info->f_rdevmin = _dev_minor(mbits, info->f_rdev); + info->f_rdev = makedev(info->f_rdevmaj, info->f_rdevmin); } - /* - * Let us hope that both, the archiving and the extracting system - * use the same major()/minor() mapping. - */ - info->f_rdevmaj = major(info->f_rdev); - info->f_rdevmin = minor(info->f_rdev); - } else { - /* - * Convert from remote major()/minor() mapping to - * local major()/minor() mapping. - */ - if (mbits < 0) /* Old star format */ - mbits = 8; - info->f_rdevmaj = _dev_major(mbits, info->f_rdev); - info->f_rdevmin = _dev_minor(mbits, info->f_rdev); - info->f_rdev = makedev(info->f_rdevmaj, info->f_rdevmin); - } - - astoo(ptb->dbuf.t_atime, &id); - info->f_atime = (time_t)id; - astoo(ptb->dbuf.t_ctime, &id); - info->f_ctime = (time_t)id; - - if (!numeric && uidname(ptb->dbuf.t_uname, STUNMLEN, &id)) - info->f_uid = id; - if (!numeric && gidname(ptb->dbuf.t_gname, STGNMLEN, &id)) - info->f_gid = id; - if (*ptb->dbuf.t_uname) { - info->f_uname = ptb->dbuf.t_uname; - info->f_umaxlen = STUNMLEN; - } - if (*ptb->dbuf.t_gname) { - info->f_gname = ptb->dbuf.t_gname; - info->f_gmaxlen = STGNMLEN; - } - - if (is_sparse(info)) - astoo(ptb->xstar_in_dbuf.t_realsize, &info->f_size); - if (is_multivol(info)) - astoo(ptb->xstar_in_dbuf.t_offset, &info->f_offset); + } + + if ((info->f_xflags & XF_ATIME) == 0) { + stoli(ptb->dbuf.t_atime, &id); + info->f_atime = (time_t)id; + info->f_ansec = 0L; + } + if ((info->f_xflags & XF_CTIME) == 0) { + stoli(ptb->dbuf.t_ctime, &id); + info->f_ctime = (time_t)id; + info->f_cnsec = 0L; + } + + if ((info->f_xflags & XF_UNAME) == 0) { + if (*ptb->dbuf.t_uname) { + info->f_uname = ptb->dbuf.t_uname; + info->f_umaxlen = STUNMLEN; + } + } + if (info->f_uname) { + if (!numeric && uidname(info->f_uname, info->f_umaxlen, &id)) + info->f_uid = id; + } + if ((info->f_xflags & XF_GNAME) == 0) { + if (*ptb->dbuf.t_gname) { + info->f_gname = ptb->dbuf.t_gname; + info->f_gmaxlen = STGNMLEN; + } + } + if (info->f_gname) { + if (!numeric && gidname(info->f_gname, info->f_gmaxlen, &id)) + info->f_gid = id; + } + + if (is_sparse(info)) { + stolli(ptb->xstar_in_dbuf.t_realsize, &ull); + info->f_size = ull; + } + if (is_multivol(info)) { + stolli(ptb->xstar_in_dbuf.t_offset, &ull); + info->f_contoffset = ull; + } } LOCAL void @@ -1114,35 +1414,49 @@ info->f_filetype = XTTOST(info->f_xftype); info->f_type = XTTOIF(info->f_xftype); - if (!numeric && uidname(ptb->ustar_dbuf.t_uname, TUNMLEN, &id)) - info->f_uid = id; - if (!numeric && gidname(ptb->ustar_dbuf.t_gname, TGNMLEN, &id)) - info->f_gid = id; - if (*ptb->ustar_dbuf.t_uname) { - info->f_uname = ptb->ustar_dbuf.t_uname; - info->f_umaxlen = TUNMLEN; - } - if (*ptb->ustar_dbuf.t_gname) { - info->f_gname = ptb->ustar_dbuf.t_gname; - info->f_gmaxlen = TGNMLEN; - } - - astoo(ptb->ustar_dbuf.t_devmajor, &info->f_rdevmaj); - if (ptb->ustar_dbuf.t_devminor[0] & 0x80) { - astob(ptb->ustar_dbuf.t_devminor, &info->f_rdevmin, 7); - } else { - /* - * The 'tar' that comes with HP-UX writes illegal tar archives. - * It includes 8 characters in the minor field and allows - * to archive 24 bits for the minor device which are used by HP-UX. - * As we like to be able to read these archives, we need to convert - * the number carefully by temporarily writing a NULL to the next - * character and restoring the right content afterwards. - */ - c = ptb->ustar_dbuf.t_prefix[0]; - ptb->ustar_dbuf.t_prefix[0] = '\0'; - astoo(ptb->ustar_dbuf.t_devminor, &info->f_rdevmin); - ptb->ustar_dbuf.t_prefix[0] = c; + if ((info->f_xflags & XF_UNAME) == 0) { + if (*ptb->ustar_dbuf.t_uname) { + info->f_uname = ptb->ustar_dbuf.t_uname; + info->f_umaxlen = TUNMLEN; + } + } + if (info->f_uname) { + if (!numeric && uidname(info->f_uname, info->f_umaxlen, &id)) + info->f_uid = id; + } + if ((info->f_xflags & XF_GNAME) == 0) { + if (*ptb->ustar_dbuf.t_gname) { + info->f_gname = ptb->ustar_dbuf.t_gname; + info->f_gmaxlen = TGNMLEN; + } + } + if (info->f_gname) { + if (!numeric && gidname(info->f_gname, info->f_gmaxlen, &id)) + info->f_gid = id; + } + + if ((info->f_xflags & XF_DEVMAJOR) == 0) + stoli(ptb->ustar_dbuf.t_devmajor, &info->f_rdevmaj); + + if ((info->f_xflags & XF_DEVMINOR) == 0) { + if (ptb->ustar_dbuf.t_devminor[0] & 0x80) { + stob(ptb->ustar_dbuf.t_devminor, &info->f_rdevmin, 7); + } else { + /* + * The 'tar' that comes with HP-UX writes illegal tar + * archives. It includes 8 characters in the minor + * field and allows to archive 24 bits for the minor + * device which are used by HP-UX. As we like to be + * able to read these archives, we need to convert + * the number carefully by temporarily writing a NULL + * to the next character and restoring the right + * content afterwards. + */ + c = ptb->ustar_dbuf.t_prefix[0]; + ptb->ustar_dbuf.t_prefix[0] = '\0'; + stoli(ptb->ustar_dbuf.t_devminor, &info->f_rdevmin); + ptb->ustar_dbuf.t_prefix[0] = c; + } } info->f_rdev = makedev(info->f_rdevmaj, info->f_rdevmin); @@ -1150,7 +1464,14 @@ /* * ANSI Tar hat keine atime & ctime im Header! */ - info->f_ctime = info->f_atime = info->f_mtime; + if ((info->f_xflags & XF_ATIME) == 0) { + info->f_atime = info->f_mtime; + info->f_ansec = 0L; + } + if ((info->f_xflags & XF_CTIME) == 0) { + info->f_ctime = info->f_mtime; + info->f_cnsec = 0L; + } } LOCAL void @@ -1159,18 +1480,29 @@ register FINFO *info; { Ulong ul; + Ullong ull; ustar_to_info(ptb, info); - astoo(ptb->xstar_dbuf.t_atime, &ul); - info->f_atime = (time_t)ul; - astoo(ptb->xstar_dbuf.t_ctime, &ul); - info->f_ctime = (time_t)ul; - - if (is_sparse(info)) - astoo(ptb->xstar_in_dbuf.t_realsize, &info->f_size); - if (is_multivol(info)) - astoo(ptb->xstar_in_dbuf.t_offset, &info->f_offset); + if ((info->f_xflags & XF_ATIME) == 0) { + stoli(ptb->xstar_dbuf.t_atime, &ul); + info->f_atime = (time_t)ul; + info->f_ansec = 0L; + } + if ((info->f_xflags & XF_CTIME) == 0) { + stoli(ptb->xstar_dbuf.t_ctime, &ul); + info->f_ctime = (time_t)ul; + info->f_cnsec = 0L; + } + + if (is_sparse(info)) { + stolli(ptb->xstar_in_dbuf.t_realsize, &ull); + info->f_size = ull; + } + if (is_multivol(info)) { + stolli(ptb->xstar_in_dbuf.t_offset, &ull); + info->f_contoffset = ull; + } } LOCAL void @@ -1179,25 +1511,34 @@ register FINFO *info; { Ulong ul; + Ullong ull; ustar_to_info(ptb, info); - astoo(ptb->gnu_dbuf.t_atime, &ul); - info->f_atime = (time_t)ul; - - if (info->f_atime == 0 && ptb->gnu_dbuf.t_atime[0] == '\0') - info->f_atime = info->f_mtime; - - astoo(ptb->gnu_dbuf.t_ctime, &ul); - info->f_ctime = (time_t)ul; - - if (info->f_ctime == 0 && ptb->gnu_dbuf.t_ctime[0] == '\0') - info->f_ctime = info->f_mtime; - - if (is_sparse(info)) - astoo(ptb->gnu_in_dbuf.t_realsize, &info->f_size); - if (is_multivol(info)) - astoo(ptb->gnu_dbuf.t_offset, &info->f_offset); + if ((info->f_xflags & XF_ATIME) == 0) { + stoli(ptb->gnu_dbuf.t_atime, &ul); + info->f_atime = (time_t)ul; + info->f_ansec = 0L; + if (info->f_atime == 0 && ptb->gnu_dbuf.t_atime[0] == '\0') + info->f_atime = info->f_mtime; + } + + if ((info->f_xflags & XF_CTIME) == 0) { + stoli(ptb->gnu_dbuf.t_ctime, &ul); + info->f_ctime = (time_t)ul; + info->f_cnsec = 0L; + if (info->f_ctime == 0 && ptb->gnu_dbuf.t_ctime[0] == '\0') + info->f_ctime = info->f_mtime; + } + + if (is_sparse(info)) { + stolli(ptb->gnu_in_dbuf.t_realsize, &ull); + info->f_size = ull; + } + if (is_multivol(info)) { + stolli(ptb->gnu_dbuf.t_offset, &ull); + info->f_contoffset = ull; + } } /* @@ -1210,9 +1551,11 @@ { Ulong ul; - astoo_cpio(&((char *)ptb)[6], &info->f_dev, 6); - astoo_cpio(&((char *)ptb)[12], &info->f_ino, 6); -error("ino: %ld\n", info->f_ino); + astoo_cpio(&((char *)ptb)[6], &ul, 6); + info->f_dev = ul; + astoo_cpio(&((char *)ptb)[12], &ul, 6); + info->f_ino = ul; +error("ino: %lld\n", (Llong)info->f_ino); astoo_cpio(&((char *)ptb)[18], &info->f_mode, 6); error("mode: %lo\n", info->f_mode); info->f_type = info->f_mode & S_IFMT; @@ -1229,7 +1572,8 @@ astoo_cpio(&((char *)ptb)[59], &info->f_namelen, 6); - astoo_cpio(&((char *)ptb)[65], &info->f_size, 11); + astoo_cpio(&((char *)ptb)[65], &ul, 11); + info->f_size = ul; info->f_rsize = info->f_size; info->f_name = &((char *)ptb)[76]; } @@ -1245,11 +1589,11 @@ return _USTOXT(ustype); /* - * Map Gnu tar & Star types ANSI: "local enhancements" + * Map Vendor Unique (Gnu tar & Star) types ANSI: "local enhancements" */ if ((props.pr_flags & (PR_LOCAL_STAR|PR_LOCAL_GNU)) && ustype >= 'A' && ustype <= 'Z') - return _GTTOXT(ustype); + return _VTTOXT(ustype); /* * treat unknown types as regular files conforming to standard @@ -1257,6 +1601,7 @@ return (XT_FILE); } +/* ARGSUSED */ EXPORT BOOL ia_change(ptb, info) TCB *ptb; @@ -1272,14 +1617,14 @@ vprint(info); if (nflag) return (FALSE); - printf("get/put ? Y(es)/N(o)/C(hange name) :");flush(); + fprintf(vpr, "get/put ? Y(es)/N(o)/C(hange name) :");fflush(vpr); fgetline(tty, buf, 2); if ((ans = toupper(buf[0])) == 'Y') return (TRUE); else if (ans == 'C') { for(;;) { - printf("Enter new name:"); - flush(); + fprintf(vpr, "Enter new name:"); + fflush(vpr); if ((len = fgetline(tty, buf, sizeof buf)) == 0) continue; if (len > sizeof(buf) - 1) @@ -1335,7 +1680,10 @@ return (TRUE); } -EXPORT void /*char **/ +/* + * Convert octal string -> long int + */ +LOCAL void /*char **/ astoo_cpio(s,l, cnt) register char *s; Ulong *l; @@ -1358,8 +1706,11 @@ /*return(s);*/ } -EXPORT void /*char **/ -astoo(s,l) +/* + * Convert string -> long int + */ +LOCAL void /*char **/ +stoli(s,l) register char *s; Ulong *l; { @@ -1383,8 +1734,44 @@ /*return(s);*/ } -EXPORT void -otoa(s, l, fieldw) +/* + * Convert string -> long long int + */ +EXPORT void /*char **/ +stolli(s,ull) + register char *s; + Ullong *ull; +{ + register Ullong ret = (Ullong)0; + register char c; + register int t; + + if (*((Uchar*)s) & 0x80) { + stollb(s, ull, 11); + return; + } + + while(*s == ' ') + s++; + + for(;;) { + c = *s++; + if(isoctal(c)) + t = c - '0'; + else + break; + ret *= 8; + ret += t; + } + *ull = ret; + /*return(s);*/ +} + +/* + * Convert long int -> string. + */ +LOCAL void +litos(s, l, fieldw) char *s; register Ulong l; register int fieldw; @@ -1409,26 +1796,93 @@ do { *--p = (l%8) + '0'; /* Compiler optimiert */ - fieldw--; - } while ((l /= 8) > 0); + + } while (--fieldw > 0 && (l /= 8) > 0); switch (fieldw) { - case 11: *--p = fill; - case 10: *--p = fill; - case 9: *--p = fill; - case 8: *--p = fill; - case 7: *--p = fill; - case 6: *--p = fill; - case 5: *--p = fill; - case 4: *--p = fill; - case 3: *--p = fill; - case 2: *--p = fill; - case 1: *--p = fill; + + default: + break; + case 11: *--p = fill; /* FALLTHROUGH */ + case 10: *--p = fill; /* FALLTHROUGH */ + case 9: *--p = fill; /* FALLTHROUGH */ + case 8: *--p = fill; /* FALLTHROUGH */ + case 7: *--p = fill; /* FALLTHROUGH */ + case 6: *--p = fill; /* FALLTHROUGH */ + case 5: *--p = fill; /* FALLTHROUGH */ + case 4: *--p = fill; /* FALLTHROUGH */ + case 3: *--p = fill; /* FALLTHROUGH */ + case 2: *--p = fill; /* FALLTHROUGH */ + case 1: *--p = fill; /* FALLTHROUGH */ + case 0: ; } } -EXPORT void /*char **/ -astob(s, l, fieldw) +/* + * Convert long long int -> string. + */ +EXPORT void +llitos(s, ull, fieldw) + char *s; + register Ullong ull; + register int fieldw; +{ + register char *p = &s[fieldw+1]; + register char fill = props.pr_fillc; + + /* + * Currently only used with fieldwidth == 11. + * XXX Large 8 byte fields are handled separately. + */ + if (/*fieldw == 11 &&*/ ull > MAXOCTAL11) { + llbtos(s, ull, fieldw); + return; + } + + /* + * Bei 12 Byte Feldern würde hier das Nächste Feld überschrieben, wenn + * entgegen der normalen Reihenfolge geschrieben wird! + * Da der TCB sowieso vorher genullt wird ist es aber kein Problem + * das bei 8 Bytes Feldern notwendige Nullbyte wegzulassen. + */ +/*XXX *p = '\0';*/ + /* + * Das Zeichen nach einer Zahl. + * XXX Soll hier besser ein NULL Byte bei POSIX Tar hin? + * XXX Wuerde das Probleme mit einer automatischen Erkennung geben? + */ + *--p = ' '; +/*??? *--p = '\0';*/ + + do { + *--p = (ull%8) + '0'; /* Compiler optimiert */ + + } while (--fieldw > 0 && (ull /= 8) > 0); + + switch (fieldw) { + + default: + break; + case 11: *--p = fill; /* FALLTHROUGH */ + case 10: *--p = fill; /* FALLTHROUGH */ + case 9: *--p = fill; /* FALLTHROUGH */ + case 8: *--p = fill; /* FALLTHROUGH */ + case 7: *--p = fill; /* FALLTHROUGH */ + case 6: *--p = fill; /* FALLTHROUGH */ + case 5: *--p = fill; /* FALLTHROUGH */ + case 4: *--p = fill; /* FALLTHROUGH */ + case 3: *--p = fill; /* FALLTHROUGH */ + case 2: *--p = fill; /* FALLTHROUGH */ + case 1: *--p = fill; /* FALLTHROUGH */ + case 0: ; + } +} + +/* + * Convert binary (base 256) string -> long int. + */ +LOCAL void /*char **/ +stob(s, l, fieldw) register char *s; Ulong *l; register int fieldw; @@ -1448,8 +1902,35 @@ /*return(s);*/ } -EXPORT void -btoa(s, l, fieldw) +/* + * Convert binary (base 256) string -> long long int. + */ +LOCAL void /*char **/ +stollb(s, ull, fieldw) + register char *s; + Ullong *ull; + register int fieldw; +{ + register Ullong ret = 0L; + register Uchar c; + + c = *s++ & 0x7F; + ret = c * 256; + + while (--fieldw >= 0) { + c = *s++; + ret *= 256; + ret += c; + } + *ull = ret; + /*return(s);*/ +} + +/* + * Convert long int -> binary (base 256) string. + */ +LOCAL void +btos(s, l, fieldw) char *s; register Ulong l; register int fieldw; @@ -1458,8 +1939,27 @@ do { *--p = l%256; /* Compiler optimiert */ - fieldw--; - } while ((l /= 256) > 0); + + } while (--fieldw > 0 && (l /= 256) > 0); + + s[0] |= 0x80; +} + +/* + * Convert long long int -> binary (base 256) string. + */ +LOCAL void +llbtos(s, ull, fieldw) + char *s; + register Ullong ull; + register int fieldw; +{ + register char *p = &s[fieldw+1]; + + do { + *--p = ull%256; /* Compiler optimiert */ + + } while (--fieldw > 0 && (ull /= 256) > 0); s[0] |= 0x80; } diff -ruN star-1.3.1/star/hole.c star-1.4/star/hole.c --- star-1.3.1/star/hole.c Sun May 7 14:52:08 2000 +++ star-1.4/star/hole.c Fri May 17 10:01:14 2002 @@ -1,8 +1,8 @@ /*#define DEBUG*/ -/* @(#)hole.c 1.18 00/05/07 Copyright 1990 J. Schilling */ +/* @(#)hole.c 1.29 02/05/11 Copyright 1990 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)hole.c 1.18 00/05/07 Copyright 1990 J. Schilling"; + "@(#)hole.c 1.29 02/05/11 Copyright 1990 J. Schilling"; #endif /* * Handle files with holes (sparse files) @@ -28,11 +28,10 @@ #include #include #include -#include #include #include -#include #include "star.h" +#include #include "props.h" #include "table.h" #include "starsubs.h" @@ -46,25 +45,29 @@ # endif #endif /* sun */ +#define DEBUG #ifdef DEBUG #define EDEBUG(a) if (debug) error a #else #define EDEBUG(a) #endif -extern int bigcnt; +extern long bigcnt; extern char *bigptr; extern BOOL debug; extern BOOL nullout; -char zeroblk[TBLOCK]; - +/* + * XXX If we have really big files, there could in theory be more than + * XXX 2 billions of hole/nohole pairs in a file. + * XXX But if this happens, we would need > 32 GB of RAM for the hole list. + */ typedef struct { FILE *fh_file; char *fh_name; - long fh_size; - long fh_newpos; + off_t fh_size; + off_t fh_newpos; sp_t *fh_sparse; int fh_nsparse; int fh_spindex; @@ -97,8 +100,8 @@ fh->fh_newpos += amount; if (amount < fh->fh_size && - cmpbytes(bigptr, zeroblk, amount) >= amount) { - if (lseek(fdown(fh->fh_file), fh->fh_newpos, SEEK_SET) < 0) { + cmpnullbytes(bigptr, amount) >= amount) { + if (lseek(fdown(fh->fh_file), fh->fh_newpos, SEEK_SET) == (off_t)-1) { xstats.s_rwerrs++; errmsg("Error seeking '%s'.\n", fh->fh_name); } @@ -121,7 +124,7 @@ fh.fh_file = f; fh.fh_name = info->f_name; fh.fh_size = info->f_rsize; - fh.fh_newpos = 0L; + fh.fh_newpos = (off_t)0; return (xt_file(info, vp_force_hole_func, &fh, TBLOCK, "writing")); } @@ -135,13 +138,13 @@ { register int cnt; - EDEBUG(("amount: %d newpos: %d index: %d\n", - amount, fh->fh_newpos, fh->fh_spindex)); + EDEBUG(("amount: %d newpos: %lld index: %d\n", + amount, (Llong)fh->fh_newpos, fh->fh_spindex)); if (fh->fh_sparse[fh->fh_spindex].sp_offset > fh->fh_newpos) { - EDEBUG(("seek to: %d\n", - fh->fh_sparse[fh->fh_spindex].sp_offset)); + EDEBUG(("seek to: %lld\n", + (Llong)fh->fh_sparse[fh->fh_spindex].sp_offset)); if (lseek(fdown(fh->fh_file), fh->fh_sparse[fh->fh_spindex].sp_offset, SEEK_SET) < 0) { @@ -151,18 +154,18 @@ fh->fh_newpos = fh->fh_sparse[fh->fh_spindex].sp_offset; } - EDEBUG(("write %d at: %d\n", amount, fh->fh_newpos)); + EDEBUG(("write %d at: %lld\n", amount, (Llong)fh->fh_newpos)); cnt = ffilewrite(fh->fh_file, p, amount); fh->fh_size -= cnt; fh->fh_newpos += cnt; - EDEBUG(("off: %d numb: %d cnt: %d off+numb: %d newpos: %d index: %d\n", - fh->fh_sparse[fh->fh_spindex].sp_offset, - fh->fh_sparse[fh->fh_spindex].sp_numbytes, cnt, - fh->fh_sparse[fh->fh_spindex].sp_offset + - fh->fh_sparse[fh->fh_spindex].sp_numbytes, - fh->fh_newpos, + EDEBUG(("off: %lld numb: %lld cnt: %d off+numb: %lld newpos: %lld index: %d\n", + (Llong)fh->fh_sparse[fh->fh_spindex].sp_offset, + (Llong)fh->fh_sparse[fh->fh_spindex].sp_numbytes, cnt, + (Llong)(fh->fh_sparse[fh->fh_spindex].sp_offset + + fh->fh_sparse[fh->fh_spindex].sp_numbytes), + (Llong)fh->fh_newpos, fh->fh_spindex)); if ((fh->fh_sparse[fh->fh_spindex].sp_offset + @@ -187,8 +190,9 @@ register int cnt; char *cmp_buf[TBLOCK]; - EDEBUG(("amount: %d newpos: %d index: %d\n", - amount, fh->fh_newpos, fh->fh_spindex)); + EDEBUG(("amount: %d newpos: %lld index: %d\n", + amount, + (Llong)fh->fh_newpos, fh->fh_spindex)); /* * If we already found diffs we save time and only pass tape ... */ @@ -196,8 +200,8 @@ return (amount); if (fh->fh_sparse[fh->fh_spindex].sp_offset > fh->fh_newpos) { - EDEBUG(("seek to: %d\n", - fh->fh_sparse[fh->fh_spindex].sp_offset)); + EDEBUG(("seek to: %lld\n", + (Llong)fh->fh_sparse[fh->fh_spindex].sp_offset)); while (fh->fh_newpos < fh->fh_sparse[fh->fh_spindex].sp_offset){ register int amt; @@ -210,7 +214,7 @@ if (cnt != amt) fh->fh_diffs++; - if (cmpbytes(cmp_buf, zeroblk, amt) < cnt) + if (cmpnullbytes(cmp_buf, amt) < cnt) fh->fh_diffs++; fh->fh_newpos += cnt; @@ -219,7 +223,7 @@ return (amount); } } - EDEBUG(("read %d at: %d\n", amount, fh->fh_newpos)); + EDEBUG(("read %d at: %lld\n", amount, (Llong)fh->fh_newpos)); cnt = ffileread(fh->fh_file, cmp_buf, amount); if (cnt != amount) @@ -231,12 +235,12 @@ fh->fh_size -= cnt; fh->fh_newpos += cnt; - EDEBUG(("off: %d numb: %d cnt: %d off+numb: %d newpos: %d index: %d\n", - fh->fh_sparse[fh->fh_spindex].sp_offset, - fh->fh_sparse[fh->fh_spindex].sp_numbytes, cnt, - fh->fh_sparse[fh->fh_spindex].sp_offset + - fh->fh_sparse[fh->fh_spindex].sp_numbytes, - fh->fh_newpos, + EDEBUG(("off: %lld numb: %lld cnt: %d off+numb: %lld newpos: %lld index: %d\n", + (Llong)fh->fh_sparse[fh->fh_spindex].sp_offset, + (Llong)fh->fh_sparse[fh->fh_spindex].sp_numbytes, cnt, + (Llong)(fh->fh_sparse[fh->fh_spindex].sp_offset + + fh->fh_sparse[fh->fh_spindex].sp_numbytes), + (Llong)fh->fh_newpos, fh->fh_spindex)); if ((fh->fh_sparse[fh->fh_spindex].sp_offset + @@ -260,14 +264,15 @@ { register int cnt; - EDEBUG(("amount: %d newpos: %d index: %d\n", - amount, fh->fh_newpos, fh->fh_spindex)); + EDEBUG(("amount: %d newpos: %lld index: %d\n", + amount, + (Llong)fh->fh_newpos, fh->fh_spindex)); if (fh->fh_spindex < fh->fh_nsparse && fh->fh_sparse[fh->fh_spindex].sp_offset > fh->fh_newpos) { - EDEBUG(("seek to: %d\n", - fh->fh_sparse[fh->fh_spindex].sp_offset)); + EDEBUG(("seek to: %lld\n", + (Llong)fh->fh_sparse[fh->fh_spindex].sp_offset)); if (lseek(*(int *)(fh->fh_file), fh->fh_sparse[fh->fh_spindex].sp_offset, SEEK_SET) < 0) { @@ -277,7 +282,7 @@ fh->fh_newpos = fh->fh_sparse[fh->fh_spindex].sp_offset; } - EDEBUG(("read %d at: %d\n", amount, fh->fh_newpos)); + EDEBUG(("read %d at: %lld\n", amount, (Llong)fh->fh_newpos)); if (nullout) { cnt = amount; @@ -291,12 +296,12 @@ /* if (cnt < TBLOCK)*/ /* fillbytes(&p[cnt], TBLOCK-cnt, '\0');*/ - EDEBUG(("off: %d numb: %d cnt: %d off+numb: %d newpos: %d index: %d\n", - fh->fh_sparse[fh->fh_spindex].sp_offset, - fh->fh_sparse[fh->fh_spindex].sp_numbytes, cnt, - fh->fh_sparse[fh->fh_spindex].sp_offset + - fh->fh_sparse[fh->fh_spindex].sp_numbytes, - fh->fh_newpos, + EDEBUG(("off: %lld numb: %lld cnt: %d off+numb: %lld newpos: %lld index: %d\n", + (Llong)fh->fh_sparse[fh->fh_spindex].sp_offset, + (Llong)fh->fh_sparse[fh->fh_spindex].sp_numbytes, cnt, + (Llong)(fh->fh_sparse[fh->fh_spindex].sp_offset + + fh->fh_sparse[fh->fh_spindex].sp_numbytes), + (Llong)fh->fh_newpos, fh->fh_spindex)); if ((fh->fh_sparse[fh->fh_spindex].sp_offset + @@ -342,9 +347,9 @@ register int sparse_in_hdr = props.pr_sparse_in_hdr; register int ind; char *p; -/*XXX*/extern int hdrtype; +/*XXX*/extern long hdrtype; - EDEBUG(("rsize: %d\n" , info->f_rsize)); + EDEBUG(("rsize: %lld\n" , (Llong)info->f_rsize)); sparse = (sp_t *)malloc(nsparse*sizeof(sp_t)); if (sparse == 0) { @@ -371,16 +376,20 @@ } for (i= 0; i < sparse_in_hdr; i++) { - astoo(p, &sparse[i].sp_offset); p += 12; - astoo(p, &sparse[i].sp_numbytes); p += 12; + Ullong ull; + + stolli(p, &ull); p += 12; + sparse[i].sp_offset = ull; + stolli(p, &ull); p += 12; + sparse[i].sp_numbytes = ull; if (sparse[i].sp_numbytes == 0) break; } #ifdef DEBUG if (debug) for (i = 0; i < sparse_in_hdr; i++) { - error("i: %d offset: %d numbytes: %d\n", i, - sparse[i].sp_offset, - sparse[i].sp_numbytes); + error("i: %d offset: %lld numbytes: %lld\n", i, + (Llong)sparse[i].sp_offset, + (Llong)sparse[i].sp_numbytes); if (sparse[i].sp_numbytes == 0) break; } @@ -392,7 +401,7 @@ else extended = ptb->xstar_in_dbuf.t_isextended; - extended |= sparse_in_hdr == 0; + extended |= (sparse_in_hdr == 0); EDEBUG(("isextended: %d\n", extended)); @@ -405,7 +414,7 @@ if ((props.pr_flags & PR_GNU_SPARSE_BUG) == 0) info->f_rsize -= TBLOCK; - EDEBUG(("rsize: %d\n" , info->f_rsize)); + EDEBUG(("rsize: %lld\n" , (Llong)info->f_rsize)); ind += SPARSE_EXT_HDR; @@ -417,12 +426,16 @@ } p = (char *)ptb; for (i = 0; i < SPARSE_EXT_HDR; i++) { - astoo(p, &sparse[i+ind].sp_offset); p += 12; - astoo(p, &sparse[i+ind].sp_numbytes); p += 12; + Ullong ull; - EDEBUG(("i: %d offset: %d numbytes: %d\n", i, - sparse[i+ind].sp_offset, - sparse[i+ind].sp_numbytes)); + stolli(p, &ull); p += 12; + sparse[i+ind].sp_offset = ull; + stolli(p, &ull); p += 12; + sparse[i+ind].sp_numbytes = ull; + + EDEBUG(("i: %d offset: %lld numbytes: %lld\n", i, + (Llong)sparse[i+ind].sp_offset, + (Llong)sparse[i+ind].sp_numbytes)); if (sparse[i+ind].sp_numbytes == 0) break; @@ -433,13 +446,13 @@ ind += i; EDEBUG(("ind: %d\n", ind)); if (debug) for (i = 0; i < ind; i++) { - error("i: %d offset: %d numbytes: %d\n", i, - sparse[i].sp_offset, - sparse[i].sp_numbytes); + error("i: %d offset: %lld numbytes: %lld\n", i, + (Llong)sparse[i].sp_offset, + (Llong)sparse[i].sp_numbytes); if (sparse[i].sp_numbytes == 0) break; } - EDEBUG(("rsize: %d\n" , info->f_rsize)); + EDEBUG(("rsize: %lld\n" , (Llong)info->f_rsize)); #endif return (sparse); } @@ -450,11 +463,13 @@ FINFO *info; sp_t **spp; { - char rbuf[TBLOCK]; + long rbuf[32*1024/sizeof(long)]; /* Force it be long aligned */ sp_t *sparse; int nsparse = 25; register int amount = 0; - register long pos = 0; + register int cnt = 0; + register char *rbp = (char *)rbuf; + register off_t pos = (off_t)0; register int i = 0; register BOOL data = FALSE; register BOOL use_ai = FALSE; @@ -474,6 +489,7 @@ fai.fai_daddr = fai_arr; use_ai = ioctl(*fp, _FIOAI, &fai) >= 0; /* Use if operational*/ fai_idx = 0; + fai.fai_num = 0; /* start at 0 again */ #endif /* _FIOAI */ *spp = (sp_t *)0; @@ -490,18 +506,80 @@ fai.fai_off = pos; fai.fai_size = 512 * NFAI; fai.fai_num = NFAI; + retry: ioctl(*fp, _FIOAI, &fai); - if (fai.fai_num == 0) + if (fai.fai_num == 0) { + /* + * Check whether we crossed the end of + * the file or off_t wrapps. + */ + if (pos < lseek(*fp, (off_t)0, SEEK_END)) { + off_t di; + + di = lseek(*fp, (off_t)0, SEEK_END); + di -= pos; + fai.fai_off = pos; + fai.fai_size = (di/512) * 512; + fai.fai_num = di/512; + if (fai.fai_num != 0) + goto retry; + if (di > 0 && di < 512) { + /* + * The last entry + * cannot be checked + * via the ooctl. + */ + fai.fai_size = 512; + fai.fai_num = 1; + fai.fai_daddr[0] = !_FIOAI_HOLE; + goto fake; + } + } break; + } + fake: fai_idx = 0; } is_hole = fai.fai_daddr[fai_idx++] == _FIOAI_HOLE; + amount = 512; + if (pos + amount < 0) + amount = info->f_size - pos; + else if (pos + amount > info->f_size) + amount = info->f_size - pos; +#else + /* EMPTY */ #endif /* _FIOAI */ } else { - if ((amount = _fileread(fp, rbuf, TBLOCK)) == 0) - break; - is_hole = cmpbytes(rbuf, zeroblk, amount) >= amount; + if (cnt <= 0) { + if ((cnt = _fileread(fp, rbuf, sizeof(rbuf))) == 0) + break; + if (cnt < 0) { + errmsg( + "Error scanning for holes in '%s'.\n", + info->f_name); + + errmsg("Current pos: %lld\n", + (Llong)lseek(*fp, (off_t)0, SEEK_CUR)); + + free(sparse); + return (0); + } + rbp = (char *)rbuf; + } + if ((amount = cmpnullbytes(rbp, cnt)) >= cnt) { + is_hole = TRUE; + cnt = 0; + } else { + amount = (amount / TBLOCK) * TBLOCK; + if ((is_hole = amount != 0) == FALSE) { + amount += TBLOCK; + if (amount > cnt) + amount = cnt; + } + rbp += amount; + cnt -= amount; + } } if (is_hole) { @@ -510,16 +588,16 @@ pos - sparse[i].sp_offset; info->f_rsize += sparse[i].sp_numbytes; - EDEBUG(("i: %d offset: %d numbytes: %d\n", i, - sparse[i].sp_offset, - sparse[i].sp_numbytes)); + EDEBUG(("i: %d offset: %lld numbytes: %lld\n", i, + (Llong)sparse[i].sp_offset, + (Llong)sparse[i].sp_numbytes)); data = FALSE; i++; if (i >= nsparse) { if ((sparse = grow_sp_list(sparse, &nsparse)) == 0) { - lseek(*fp, 0L, SEEK_SET); + lseek(*fp, (off_t)0, SEEK_SET); return (0); } } @@ -538,19 +616,19 @@ sparse[i].sp_numbytes = pos - sparse[i].sp_offset; info->f_rsize += sparse[i].sp_numbytes; - EDEBUG(("i: %d offset: %d numbytes: %d\n", i, - sparse[i].sp_offset, - sparse[i].sp_numbytes)); + EDEBUG(("i: %d offset: %lld numbytes: %lld\n", i, + (Llong)sparse[i].sp_offset, + (Llong)sparse[i].sp_numbytes)); } else { sparse[i].sp_offset = pos -1; sparse[i].sp_numbytes = 1; info->f_rsize += 1; - EDEBUG(("i: %d offset: %d numbytes: %d\n", i, - sparse[i].sp_offset, - sparse[i].sp_numbytes)); + EDEBUG(("i: %d offset: %lld numbytes: %lld\n", i, + (Llong)sparse[i].sp_offset, + (Llong)sparse[i].sp_numbytes)); } - lseek(*fp, 0L, SEEK_SET); + lseek(*fp, (off_t)0, SEEK_SET); *spp = sparse; return (++i); } @@ -577,14 +655,14 @@ if (sparse == 0) { errmsgno(EX_BAD, "Skipping '%s' sorry ...\n", info->f_name); - errmsgno(EX_BAD, "Warning '%s' is damaged\n", info->f_name); + errmsgno(EX_BAD, "WARNING: '%s' is damaged\n", info->f_name); void_file(info); return (FALSE); } fh.fh_file = f; fh.fh_name = info->f_name; fh.fh_size = info->f_rsize; - fh.fh_newpos = 0L; + fh.fh_newpos = (off_t)0; fh.fh_sparse = sparse; fh.fh_spindex = 0; ret = xt_file(info, vp_get_sparse_func, &fh, TBLOCK, "writing"); @@ -609,7 +687,7 @@ fh.fh_file = f; fh.fh_name = info->f_name; fh.fh_size = info->f_rsize; - fh.fh_newpos = 0L; + fh.fh_newpos = (off_t)0; fh.fh_sparse = sparse; fh.fh_spindex = 0; fh.fh_diffs = 0; @@ -629,7 +707,7 @@ fh_t fh; sp_t *sparse; int nsparse; - long rsize; + off_t rsize; nsparse = mk_sp_list(fp, info, &sparse); if (nsparse == 0) { @@ -642,13 +720,13 @@ } rsize = info->f_rsize; - EDEBUG(("rsize: %d\n", rsize)); + EDEBUG(("rsize: %lld\n", (Llong)rsize)); put_sp_list(info, sparse, nsparse); fh.fh_file = (FILE *)fp; fh.fh_name = info->f_name; fh.fh_size = info->f_rsize = rsize; - fh.fh_newpos = 0L; + fh.fh_newpos = (off_t)0; fh.fh_sparse = sparse; fh.fh_nsparse = nsparse; fh.fh_spindex = 0; @@ -667,9 +745,9 @@ register char *p; TCB tb; TCB *ptb = info->f_tcb; -/*XXX*/extern int hdrtype; +/*XXX*/extern long hdrtype; - EDEBUG(("1nsparse: %d rsize: %d\n", nsparse, info->f_rsize)); + EDEBUG(("1nsparse: %d rsize: %lld\n", nsparse, (Llong)info->f_rsize)); if (nsparse > sparse_in_hdr) { if ((props.pr_flags & PR_GNU_SPARSE_BUG) == 0) @@ -677,14 +755,14 @@ (((nsparse-sparse_in_hdr)+SPARSE_EXT_HDR-1)/ SPARSE_EXT_HDR)*TBLOCK; } - EDEBUG(("2nsparse: %d rsize: %d added: %d\n", nsparse, info->f_rsize, + EDEBUG(("2nsparse: %d rsize: %lld added: %d\n", nsparse, (Llong)info->f_rsize, (((nsparse-sparse_in_hdr)+SPARSE_EXT_HDR-1)/ SPARSE_EXT_HDR)*TBLOCK)); - EDEBUG(("addr sp: %d\n", &((TCB *)0)->xstar_in_dbuf.t_sp)); - EDEBUG(("addr rs: %d\n", &((TCB *)0)->xstar_in_dbuf.t_realsize)); - EDEBUG(("flags: 0x%X\n", info->f_flags)); + EDEBUG(("addr sp: %d\n", (int)((TCB *)0)->xstar_in_dbuf.t_sp)); + EDEBUG(("addr rs: %d\n", (int)((TCB *)0)->xstar_in_dbuf.t_realsize)); + EDEBUG(("flags: 0x%lX\n", info->f_flags)); - info->f_xftype = XT_SPARSE; + info->f_rxftype = info->f_xftype = XT_SPARSE; if (info->f_flags & F_SPLIT_NAME && props.pr_nflags & PR_PREFIX_REUSED) tcb_undo_split(ptb, info); info_to_tcb(info, ptb); @@ -694,8 +772,8 @@ else p = (char *)ptb->xstar_in_dbuf.t_sp; for (i=0; i < sparse_in_hdr && i < nsparse; i++) { - otoa(p, sparse[i].sp_offset, 11); p += 12; - otoa(p, sparse[i].sp_numbytes, 11); p += 12; + llitos(p, (Ullong)sparse[i].sp_offset, 11); p += 12; + llitos(p, (Ullong)sparse[i].sp_numbytes, 11); p += 12; } if (sparse_in_hdr > 0 && nsparse > sparse_in_hdr) { if (H_TYPE(hdrtype) == H_GNUTAR) @@ -711,11 +789,11 @@ sparse += sparse_in_hdr; ptb = &tb; while (nsparse > 0) { - fillbytes((char *)ptb, TBLOCK, '\0'); + filltcb(ptb); p = (char *)ptb; for (i=0; i < SPARSE_EXT_HDR && i < nsparse; i++) { - otoa(p, sparse[i].sp_offset, 11); p += 12; - otoa(p, sparse[i].sp_numbytes, 11); p += 12; + llitos(p, (Ullong)sparse[i].sp_offset, 11); p += 12; + llitos(p, (Ullong)sparse[i].sp_numbytes, 11); p += 12; } nsparse -= SPARSE_EXT_HDR; sparse += SPARSE_EXT_HDR; diff -ruN star-1.3.1/star/lhash.c star-1.4/star/lhash.c --- star-1.3.1/star/lhash.c Sun May 7 14:52:09 2000 +++ star-1.4/star/lhash.c Fri May 17 11:26:30 2002 @@ -1,7 +1,7 @@ -/* @(#)lhash.c 1.8 00/05/07 Copyright 1988 J. Schilling */ +/* @(#)lhash.c 1.9 02/05/17 Copyright 1988 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)lhash.c 1.8 00/05/07 Copyright 1988 J. Schilling"; + "@(#)lhash.c 1.9 02/05/17 Copyright 1988 J. Schilling"; #endif /* * Copyright (c) 1988 J. Schilling @@ -45,11 +45,13 @@ #include #include +#include +#include #include #include "star.h" -#include #include #include +#include "starsubs.h" extern BOOL notpat; @@ -60,15 +62,14 @@ static unsigned h_size; -EXPORT void hash_build __PR((FILE * fp, unsigned int size)); +EXPORT void hash_build __PR((FILE * fp, size_t size)); EXPORT BOOL hash_lookup __PR((char* str)); LOCAL int hashval __PR((unsigned char* str, unsigned int maxsize)); -LOCAL struct h_elem* _malloc __PR((unsigned int len)); EXPORT void hash_build(fp, size) FILE *fp; - unsigned size; + size_t size; { register struct h_elem *hp; register int i; @@ -77,7 +78,7 @@ char buf[PATH_MAX+1]; h_size = size; - h_tab = (struct h_elem **)_malloc(size * sizeof (struct h_elem *)); + h_tab = __malloc(size * sizeof (struct h_elem *), "list option"); for (i=0; i= 0) { if (len == 0) @@ -87,7 +88,7 @@ buf, len, PATH_MAX); continue; } - hp = _malloc((unsigned)len + 1 + sizeof (struct h_elem *)); + hp = __malloc((size_t)len + 1 + sizeof (struct h_elem *), "list option"); strcpy(hp->h_data, buf); hv = hashval((unsigned char *)buf, size); hp->h_next = h_tab[hv]; @@ -121,15 +122,4 @@ for (i=0; (c = *str++) != '\0'; i++) sum ^= (c << (i&7)); return sum % maxsize; -} - -LOCAL struct h_elem * -_malloc(len) - unsigned len; -{ - char *ret; - - if ((ret = malloc(len)) == NULL) - comerr("No memory for list option.\n"); - return (struct h_elem *)ret; } diff -ruN star-1.3.1/star/list.c star-1.4/star/list.c --- star-1.3.1/star/list.c Sat Apr 7 22:18:12 2001 +++ star-1.4/star/list.c Sun May 5 15:00:18 2002 @@ -1,12 +1,12 @@ -/* @(#)list.c 1.30 01/04/07 Copyright 1985, 1995 J. Schilling */ +/* @(#)list.c 1.41 02/05/05 Copyright 1985, 1995, 2000-2001 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)list.c 1.30 01/04/07 Copyright 1985, 1995 J. Schilling"; + "@(#)list.c 1.41 02/05/05 Copyright 1985, 1995, 2000-2001 J. Schilling"; #endif /* * List the content of an archive * - * Copyright (c) 1985, 1995 J. Schilling + * Copyright (c) 1985, 1995, 2000-2001 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify @@ -37,12 +37,13 @@ extern FILE *tarf; extern FILE *vpr; extern char *listfile; +extern Llong curblockno; extern BOOL havepat; -extern BOOL verbose; -extern BOOL tpath; extern BOOL numeric; -extern BOOL verbose; +extern int verbose; +extern BOOL prblockno; +extern BOOL tpath; extern BOOL cflag; extern BOOL xflag; extern BOOL interactive; @@ -77,6 +78,9 @@ for (;;) { if (get_tcb(ptb) == EOF) break; + if (prblockno) + (void)tblocks(); /* set curblockno */ + finfo.f_name = name; if (tcb_to_info(ptb, &finfo) == EOF) return; @@ -84,10 +88,14 @@ /* * XXX nsec beachten wenn im Archiv! */ - if (finfo.f_mtime > newinfo.f_mtime && + if (((finfo.f_mtime > newinfo.f_mtime) || + ((finfo.f_xflags & XF_MTIME) && + (newinfo.f_xflags & XF_MTIME) && + (finfo.f_mtime == newinfo.f_mtime) && + (finfo.f_mnsec > newinfo.f_mnsec))) && (!listnewf || is_file(&finfo))) { movebytes(&finfo, &newinfo, sizeof(finfo)); - movebytes(&tb, &newtb, sizeof(tb)); + movetcb(&tb, &newtb); /* * Paranoia..... */ @@ -144,6 +152,9 @@ else *str++ = '-'; } +#ifdef USE_ACL + *str++ = ' '; +#endif *str = '\0'; str = s; if (mode & 01000) { @@ -168,6 +179,10 @@ else str[2] = 'S'; } +#ifdef USE_ACL + if ((info->f_xflags & (XF_ACL_ACCESS|XF_ACL_DEFAULT)) != 0) + str[9] = '+'; +#endif } EXPORT void @@ -177,12 +192,21 @@ FILE *f; time_t *tp; char *tstr; - char mstr[10]; - static char nuid[11]; - static char ngid[11]; + char mstr[11]; /* 9 UNIX chars + ACL '+' + nul */ + static char nuid[11]; /* XXXX 64 bit longs??? */ + static char ngid[11]; /* XXXX 64 bit longs??? */ f = vpr; + if (prblockno) + fprintf(f, "block %9lld: ", curblockno); + if (cflag) + fprintf(f, "a "); + else if (xflag) + fprintf(f, "x "); + if (verbose) { + register Uint xft = info->f_xftype; + /* tp = (time_t *) (acctime ? &info->f_atime :*/ /* (Ctime ? &info->f_ctime : &info->f_mtime));*/ tp = acctime ? &info->f_atime : @@ -203,22 +227,25 @@ fprintf(f, "%3lu %3lu", info->f_rdevmaj, info->f_rdevmin); else - fprintf(f, "%7lu", info->f_size); + fprintf(f, "%7llu", (Llong)info->f_size); modstr(info, mstr, info->f_mode); /* * XXX Übergangsweise, bis die neue Filetypenomenklatur sauber eingebaut ist. */ -if (info->f_xftype == 0) { - info->f_xftype = IFTOXT(info->f_type); - errmsgno(EX_BAD, "XXXXX xftype == 0\n"); +if (xft == 0 || xft == XT_BAD) { + xft = info->f_xftype = IFTOXT(info->f_type); + errmsgno(EX_BAD, "XXXXX xftype == 0 (typeflag = '%c' 0x%02X)\n", + info->f_typeflag, info->f_typeflag); } + if (xft == XT_LINK) + xft = info->f_rxftype; fprintf(f, " %s%s %3.*s/%-3.*s %.12s %4.4s ", #ifdef OLD typetab[info->f_filetype & 07], #else - XTTOSTR(info->f_xftype), + XTTOSTR(xft), #endif mstr, (int)info->f_umaxlen, info->f_uname, @@ -226,18 +253,21 @@ &tstr[4], &tstr[20]); } fprintf(f, "%s", info->f_name); - if(tpath) { + if (tpath) { fprintf(f, "\n"); return; } - if (is_link(info)) + if (is_link(info)) { + if (is_dir(info)) + fprintf(f, " directory"); fprintf(f, " link to %s", info->f_lname); + } if (is_symlink(info)) fprintf(f, " -> %s", info->f_lname); if (is_volhdr(info)) fprintf(f, " --Volume Header--"); if (is_multivol(info)) - fprintf(f, " --Continued at byte %ld--", info->f_offset); + fprintf(f, " --Continued at byte %lld--", (Llong)info->f_contoffset); fprintf(f, "\n"); } @@ -249,16 +279,33 @@ char *mode; if (verbose || interactive) { + if (verbose > 1) { + list_file(info); + return; + } + f = vpr; + if (prblockno) + fprintf(f, "block %9lld: ", curblockno); if (cflag) mode = "a "; else if (xflag) mode = "x "; else mode = ""; + + if (tpath) { + fprintf(f, "%s%s\n", mode, info->f_name); + return; + } if (is_dir(info)) { - fprintf(f, "%s%s directory\n", mode, info->f_name); + if (is_link(info)) { + fprintf(f, "%s%s directory link to %s\n", + mode, info->f_name, info->f_lname); + } else { + fprintf(f, "%s%s directory\n", mode, info->f_name); + } } else if (is_link(info)) { fprintf(f, "%s%s link to %s\n", mode, info->f_name, info->f_lname); @@ -268,9 +315,9 @@ } else if (is_special(info)) { fprintf(f, "%s%s special\n", mode, info->f_name); } else { - fprintf(f, "%s%s %ld bytes, %ld tape blocks\n", - mode, info->f_name, info->f_size, - tarblocks(info->f_rsize)); + fprintf(f, "%s%s %lld bytes, %lld tape blocks\n", + mode, info->f_name, (Llong)info->f_size, + (Llong)tarblocks(info->f_rsize)); } } } diff -ruN star-1.3.1/star/longnames.c star-1.4/star/longnames.c --- star-1.3.1/star/longnames.c Thu Nov 9 07:49:48 2000 +++ star-1.4/star/longnames.c Thu May 9 22:44:13 2002 @@ -1,13 +1,13 @@ -/* @(#)longnames.c 1.23 00/11/09 Copyright 1993, 1995 J. Schilling */ +/* @(#)longnames.c 1.34 02/05/09 Copyright 1993, 1995, 2001 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)longnames.c 1.23 00/11/09 Copyright 1993, 1995 J. Schilling"; + "@(#)longnames.c 1.34 02/05/09 Copyright 1993, 1995, 2001 J. Schilling"; #endif /* * Handle filenames that cannot fit into a single * string of 100 charecters * - * Copyright (c) 1993, 1995 J. Schilling + * Copyright (c) 1993, 1995, 2001 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify @@ -33,20 +33,13 @@ #include #include #include "starsubs.h" - -typedef struct { - char *m_name; - int m_size; - int m_add; -} move_t; +#include "movearch.h" LOCAL void enametoolong __PR((char* name, int len, int maxlen)); LOCAL char* split_posix_name __PR((char* name, int namlen, int add)); EXPORT BOOL name_to_tcb __PR((FINFO * info, TCB * ptb)); EXPORT void tcb_to_name __PR((TCB * ptb, FINFO * info)); EXPORT void tcb_undo_split __PR((TCB * ptb, FINFO * info)); -LOCAL int move_from_name __PR((move_t * move, char* p, int amount)); -LOCAL int move_to_name __PR((move_t * move, char* p, int amount)); EXPORT int tcb_to_longname __PR((TCB * ptb, FINFO * info)); EXPORT void write_longnames __PR((FINFO * info)); LOCAL void put_longname __PR((FINFO * info, @@ -145,7 +138,10 @@ * cannot split */ if (namelen+add <= props.pr_maxnamelen) { - info->f_flags |= F_LONGNAME; + if (props.pr_flags & PR_XHDR) + info->f_xflags |= XF_PATH; + else + info->f_flags |= F_LONGNAME; if (add) info->f_flags |= F_ADDSLASH; strncpy(ptb->dbuf.t_name, name, props.pr_maxsname); @@ -165,11 +161,29 @@ return (TRUE); } +/* + * This function is only called by tcb_to_info(). + * If we ever decide to call it from somewhere else check if the linkname + * kludge for 100 char linknames does not make problems. + */ EXPORT void tcb_to_name(ptb, info) TCB *ptb; FINFO *info; { + if ((info->f_flags & F_LONGLINK) == 0 && /* name from 'K' head*/ + (info->f_xflags & XF_LINKPATH) == 0 && /* name from 'x' head*/ + ptb->dbuf.t_linkname[NAMSIZ-1] != '\0') { + extern char longlinkname[]; + + /* + * Our caller has set ptb->dbuf.t_linkname[NAMSIZ] to '\0' + * if the link name len is exactly 100 chars. + */ + info->f_lname = longlinkname; + strcpy(info->f_lname, ptb->dbuf.t_linkname); + } + /* * Name has already been set up because it is a very long name or * because it has been setup from somwhere else. @@ -177,6 +191,11 @@ */ if (info->f_flags & (F_LONGNAME|F_HAS_NAME)) return; + /* + * Name has already been set up from a POSIX.1-2001 extended header. + */ + if (info->f_xflags & XF_PATH) + return; if (props.pr_nflags & PR_POSIX_SPLIT) { strcatl(info->f_name, ptb->dbuf.t_prefix, @@ -196,60 +215,23 @@ fillbytes(ptb->dbuf.t_prefix, props.pr_maxprefix, '\0'); info->f_flags &= ~F_SPLIT_NAME; - info->f_flags |= F_LONGNAME; - - strncpy(ptb->dbuf.t_name, info->f_name, props.pr_maxsname); -} - -#define vp_move_from_name ((int(*)__PR((void *, char *, int)))move_from_name) - -/* - * Move name from archive. - */ -LOCAL int -move_from_name(move, p, amount) - move_t *move; - char *p; - int amount; -{ - movebytes(p, move->m_name, amount); - move->m_name += amount; - move->m_name[0] = '\0'; - return (amount); -} -#define vp_move_to_name ((int(*)__PR((void *, char *, int)))move_to_name) + if (props.pr_flags & PR_XHDR) + info->f_xflags |= XF_PATH; + else + info->f_flags |= F_LONGNAME; -/* - * Move name to archive. - */ -LOCAL int -move_to_name(move, p, amount) - move_t *move; - char *p; - int amount; -{ - if (amount > move->m_size) - amount = move->m_size; - movebytes(move->m_name, p, amount); - move->m_name += amount; - move->m_size -= amount; - if (move->m_add) { - if (move->m_size == 1) { - p[amount-1] = '/'; - } else if (move->m_size == 0) { - if (amount > 1) - p[amount-2] = '/'; - p[amount-1] = '\0'; - } - } - return (amount); + strncpy(ptb->dbuf.t_name, info->f_name, props.pr_maxsname); } /* * A bad idea to do this here! * We have to set up a more generalized pool of namebuffers wich are allocated - * on an actual MAX_PATH base. + * on an actual MAX_PATH base or even better allocated on demand. + * + * XXX If we change the code to allocate the data, we need to make sure that + * XXX the allocated data holds one byte more than needed as movearch.c + * XXX adds a second null byte to the buffer to enforce null-termination. */ char longlinkname[PATH_MAX+1]; @@ -259,30 +241,51 @@ register FINFO *info; { move_t move; + Ullong ull; /* - * File size is strlen of name + * File size is strlen of name + 1 */ - astoo(ptb->dbuf.t_size, &info->f_size); + stolli(ptb->dbuf.t_size, &ull); + info->f_size = ull; info->f_rsize = info->f_size; if (info->f_size > PATH_MAX) { xstats.s_toolong++; - errmsgno(EX_BAD, "Long name too long (%ld) ignored.\n", - info->f_size); + errmsgno(EX_BAD, "Long name too long (%lld) ignored.\n", + (Llong)info->f_size); void_file(info); return (get_tcb(ptb)); } if (ptb->dbuf.t_linkflag == LF_LONGNAME) { + if ((info->f_xflags & XF_PATH) != 0) { + /* + * Ignore old star/gnutar extended headers for very + * long filenames if we already found a POSIX.1-2001 + * compliant long PATH name. + */ + void_file(info); + return (get_tcb(ptb)); + } info->f_namelen = info->f_size -1; info->f_flags |= F_LONGNAME; - move.m_name = info->f_name; + move.m_data = info->f_name; } else { + if ((info->f_xflags & XF_LINKPATH) != 0) { + /* + * Ignore old star/gnutar extended headers for very + * long linknames if we already found a POSIX.1-2001 + * compliant long LINKPATH name. + */ + void_file(info); + return (get_tcb(ptb)); + } info->f_lname = longlinkname; info->f_lnamelen = info->f_size -1; info->f_flags |= F_LONGLINK; - move.m_name = info->f_lname; + move.m_data = info->f_lname; } - if (xt_file(info, vp_move_from_name, &move, 0, "moving long name") < 0) + move.m_flags = 0; + if (xt_file(info, vp_move_from_arch, &move, 0, "moving long name") < 0) die(EX_BAD); return (get_tcb(ptb)); @@ -295,11 +298,13 @@ /* * XXX Should test for F_LONGNAME & F_FLONGLINK */ - if (info->f_namelen > props.pr_maxsname) { + if ((info->f_flags & F_LONGNAME) || + (info->f_namelen > props.pr_maxsname)) { put_longname(info, info->f_name, info->f_namelen+1, "././@LongName", XT_LONGNAME); } - if (info->f_lnamelen > props.pr_maxslname) { + if ((info->f_flags & F_LONGLINK) || + (info->f_lnamelen > props.pr_maxslname)) { put_longname(info, info->f_lname, info->f_lnamelen+1, "././@LongLink", XT_LONGLINK); } @@ -321,13 +326,17 @@ ptb = (TCB *)get_block(); finfo.f_flags |= F_TCB_BUF; - fillbytes((char *)ptb, TBLOCK, '\0'); + filltcb(ptb); strcpy(ptb->dbuf.t_name, tname); - move.m_add = 0; + move.m_flags = 0; if ((info->f_flags & F_ADDSLASH) != 0 && xftype == XT_LONGNAME) { - move.m_add = 1; + /* + * A slash is only added to the filename and not to the + * linkname. + */ + move.m_flags |= MF_ADDSLASH; namelen++; } finfo.f_rsize = finfo.f_size = namelen; @@ -335,7 +344,7 @@ info_to_tcb(&finfo, ptb); write_tcb(ptb, &finfo); - move.m_name = name; + move.m_data = name; move.m_size = finfo.f_size; - cr_file(&finfo, vp_move_to_name, &move, 0, "moving long name"); + cr_file(&finfo, vp_move_to_arch, &move, 0, "moving long name"); } diff -ruN star-1.3.1/star/movearch.c star-1.4/star/movearch.c --- star-1.3.1/star/movearch.c Thu Jan 1 01:00:00 1970 +++ star-1.4/star/movearch.c Fri Dec 7 20:30:40 2001 @@ -0,0 +1,91 @@ +/* @(#)movearch.c 1.27 01/12/07 Copyright 1993, 1995, 2001 J. Schilling */ +#ifndef lint +static char sccsid[] = + "@(#)movearch.c 1.27 01/12/07 Copyright 1993, 1995, 2001 J. Schilling"; +#endif +/* + * Handle non-file type data that needs to be moved from/to the archive. + * + * Copyright (c) 1993, 1995, 2001 J. Schilling + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "star.h" +#include "props.h" +#include "table.h" +#include +#include +#include +#include "starsubs.h" +#include "movearch.h" + +EXPORT int move_from_arch __PR((move_t * move, char* p, int amount)); +EXPORT int move_to_arch __PR((move_t * move, char* p, int amount)); + + +/* + * Move data from archive. + */ +EXPORT int +move_from_arch(move, p, amount) + move_t *move; + char *p; + int amount; +{ + movebytes(p, move->m_data, amount); + move->m_data += amount; + /* + * If we make sure that the buffer holds at least one character more + * than needed, then we may safely add another null byte at the end of + * the extracted buffer. + * This makes sure, that a buggy tar implementation which wight archive + * non null-terminated long filenames with 'L' or 'K' filetype may + * not cause us to core dump. + * It is needed when extracting extended attribute buffers from + * POSIX.1-2001 archives as POSIX.1-2001 makes the buffer '\n' but not + * null-terminated. + */ + move->m_data[0] = '\0'; + return (amount); +} + +/* + * Move data to archive. + */ +EXPORT int +move_to_arch(move, p, amount) + move_t *move; + char *p; + int amount; +{ + if (amount > move->m_size) + amount = move->m_size; + movebytes(move->m_data, p, amount); + move->m_data += amount; + move->m_size -= amount; + if (move->m_flags & MF_ADDSLASH) { + if (move->m_size == 1) { + p[amount-1] = '/'; + } else if (move->m_size == 0) { + if (amount > 1) + p[amount-2] = '/'; + p[amount-1] = '\0'; + } + } + return (amount); +} diff -ruN star-1.3.1/star/movearch.h star-1.4/star/movearch.h --- star-1.3.1/star/movearch.h Thu Jan 1 01:00:00 1970 +++ star-1.4/star/movearch.h Sun Aug 12 12:21:55 2001 @@ -0,0 +1,36 @@ +/* @(#)movearch.h 1.1 01/08/12 Copyright 1993, 1995, 2001 J. Schilling */ +/* + * Handle non-file type data that needs to be moved from/to the archive. + * + * Copyright (c) 1993, 1995, 2001 J. Schilling + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +typedef struct { + char *m_data; /* Pointer to data to be moved ftom/to arch */ + int m_size; /* Size of data to be moved from/to arch */ + int m_flags; /* Flags holding different move options */ +} move_t; + +#define MF_ADDSLASH 0x01 /* Add a slash to the data on archive */ + + +extern int move_from_arch __PR((move_t * move, char* p, int amount)); +extern int move_to_arch __PR((move_t * move, char* p, int amount)); + +#define vp_move_from_arch ((int(*)__PR((void *, char *, int)))move_from_arch) +#define vp_move_to_arch ((int(*)__PR((void *, char *, int)))move_to_arch) diff -ruN star-1.3.1/star/props.c star-1.4/star/props.c --- star-1.3.1/star/props.c Sun May 7 14:52:07 2000 +++ star-1.4/star/props.c Thu May 9 15:40:53 2002 @@ -1,11 +1,21 @@ -/* @(#)props.c 1.14 00/05/07 Copyright 1994 J. Schilling */ +/* @(#)props.c 1.26 02/05/09 Copyright 1994 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)props.c 1.14 00/05/07 Copyright 1994 J. Schilling"; + "@(#)props.c 1.26 02/05/09 Copyright 1994 J. Schilling"; #endif /* * Set up properties for different archive types * + * NOTE that part of the information in struct propertiesis available more + * than once. This is needed as different parts of the source need the + * information in different ways. Partly for performance reasons, partly + * because one method of storing the information is inappropriate for all + * places in the source. + * + * If you add new features or information related to the fields + * pr_flags/pr_nflags or the fields pr_xftypetab[]/pr_typeflagtab[] + * take care of possible problems due to this fact. + * * Copyright (c) 1994 J. Schilling */ /* @@ -28,27 +38,35 @@ #include #include "star.h" #include "props.h" +#include "table.h" #include "diff.h" #include #include #include "starsubs.h" extern BOOL debug; +extern BOOL dodump; struct properties props; EXPORT void setprops __PR((long htype)); EXPORT void printprops __PR((void)); +LOCAL void prsettypeflags __PR((char *types, int typeflag)); EXPORT void setprops(htype) long htype; { + fillbytes(props.pr_typeflagtab, sizeof(props.pr_typeflagtab), '\0'); + switch (H_TYPE(htype)) { - case H_STAR: + case H_STAR: /* Old star format (1985) */ + props.pr_maxsize = 0; props.pr_flags = PR_LOCAL_STAR|PR_SPARSE|PR_VOLHDR; - props.pr_fillc = ' '; + props.pr_xdflags = 0; + props.pr_fillc = ' '; /* Use old tar octal format */ + props.pr_xc = 'x'; /* Use POSIX.1-2001 x-hdr */ props.pr_diffmask = 0L; props.pr_nflags = PR_POSIX_SPLIT|PR_PREFIX_REUSED|PR_LONG_NAMES; @@ -58,13 +76,33 @@ props.pr_maxslname = NAMSIZ; props.pr_maxprefix = PFXSIZ; props.pr_sparse_in_hdr = 0; + /* + * The STAR format extensions from 1986 archive nearly any UNIX file type + */ + movebytes(xtstar_tab, props.pr_xftypetab, sizeof(props.pr_xftypetab)); + + /* + * The STAR format is pre-POSIX but supports many POSIX/GNU + * extensions. + */ + prsettypeflags("01234567gxIKLMSV", TF_VALIDTYPE); + prsettypeflags("gxKLM", TF_XHEADERS); break; - case H_XSTAR: - case H_XUSTAR: + case H_XSTAR: /* ext P-1988 format (1994) */ + case H_XUSTAR: /* ext ^ no "tar" sig (1998) */ + case H_EXUSTAR: /* ext P-2001 format (2001) */ + props.pr_maxsize = 0; props.pr_flags = PR_POSIX_OCTAL|PR_LOCAL_STAR|PR_SPARSE|PR_VOLHDR; - props.pr_fillc = '0'; + if (H_TYPE(htype) == H_XUSTAR || H_TYPE(htype) == H_EXUSTAR) + props.pr_flags |= PR_XHDR; + props.pr_xdflags = 0; + if (H_TYPE(htype) == H_EXUSTAR) + props.pr_xdflags |= (XF_ATIME|XF_CTIME|XF_MTIME); + + props.pr_fillc = '0'; /* Use ustar octal format */ + props.pr_xc = 'x'; /* Use POSIX.1-2001 x-hdr */ props.pr_diffmask = 0L; props.pr_nflags = PR_POSIX_SPLIT|PR_PREFIX_REUSED|PR_LONG_NAMES; @@ -74,25 +112,89 @@ props.pr_maxslname = NAMSIZ; props.pr_maxprefix = 130; props.pr_sparse_in_hdr = 0; + /* + * As long as we don't support the POSIX.1-2001 speudo 'x' file + * We can only archive file types from the USTAR list and + * sparse files as well as + * meta files (regular files without archived content). + */ + movebytes(xtustar_tab, props.pr_xftypetab, sizeof(props.pr_xftypetab)); + props.pr_xftypetab[XT_SPARSE] = 1; + props.pr_xftypetab[XT_META] = 1; + + /* + * Extended PAX format may allow more filetypes in a vendor + * unique extension of the POSIX.1-2001 extended headers. + * XXX As we currently only add the SCHILY.filetype headers + * XXX if -dump has been specified, we can only allow more + * XXX filetypes in this case. + */ +/* if (H_TYPE(htype) == H_EXUSTAR)*/ + if (dodump && H_TYPE(htype) == H_EXUSTAR) + movebytes(xtexustar_tab, props.pr_xftypetab, sizeof(props.pr_xftypetab)); + + /* + * The X-STAR format family is POSIX with extensions. + */ + prsettypeflags("01234567gxIKLMSV", TF_VALIDTYPE); + prsettypeflags("gxKLM", TF_XHEADERS); break; - case H_USTAR: + case H_PAX: /* ieee 1003.1-2001 ext ustar*/ + case H_USTAR: /* ieee 1003.1-1988 ustar */ + case H_SUNTAR: /* Sun's tar from Solaris 7-9*/ + props.pr_maxsize = MAXOCTAL11; props.pr_flags = PR_POSIX_OCTAL; - props.pr_fillc = '0'; + if (H_TYPE(htype) == H_PAX || H_TYPE(htype) == H_SUNTAR) { + props.pr_maxsize = 0; + props.pr_flags |= PR_XHDR; + } + props.pr_xdflags = 0; + props.pr_fillc = '0'; /* Use ustar octal format */ + props.pr_xc = 'x'; /* Use POSIX.1-2001 x-hdr */ + if (H_TYPE(htype) == H_SUNTAR) { + props.pr_xdflags = XF_MTIME; + props.pr_xc = 'X'; /* Use Sun Solaris X-hdr */ + } props.pr_diffmask = (D_ATIME|D_CTIME); + if (H_TYPE(htype) == H_PAX) { + props.pr_diffmask = 0L; + } props.pr_nflags = PR_POSIX_SPLIT; props.pr_maxnamelen = NAMSIZ; props.pr_maxlnamelen = NAMSIZ; + if (H_TYPE(htype) == H_PAX || H_TYPE(htype) == H_SUNTAR) { + props.pr_nflags |= PR_LONG_NAMES; + props.pr_maxnamelen = PATH_MAX; + props.pr_maxlnamelen = PATH_MAX; + } props.pr_maxsname = NAMSIZ; props.pr_maxslname = NAMSIZ; props.pr_maxprefix = PFXSIZ; props.pr_sparse_in_hdr = 0; + /* + * USTAR is limited to 7 basic file types + */ + movebytes(xtustar_tab, props.pr_xftypetab, sizeof(props.pr_xftypetab)); + + /* + * Even the USTAR format should support POSIX extension headers. + */ + prsettypeflags("01234567gx", TF_VALIDTYPE); + prsettypeflags("gx", TF_XHEADERS); + if (H_TYPE(htype) == H_SUNTAR) { + prsettypeflags("01234567gxX", TF_VALIDTYPE); + prsettypeflags("gxX", TF_XHEADERS); + } break; - case H_GNUTAR: + case H_GNUTAR: /* gnu tar format (1989) */ + props.pr_maxsize = 0; props.pr_flags = PR_LOCAL_GNU|PR_SPARSE|PR_GNU_SPARSE_BUG|PR_VOLHDR; - props.pr_fillc = ' '; + props.pr_xdflags = 0; + props.pr_fillc = ' '; /* Use old tar octal format */ + props.pr_xc = 'x'; /* Really ??? */ props.pr_diffmask = 0L; props.pr_nflags = PR_LONG_NAMES; props.pr_maxnamelen = PATH_MAX; @@ -101,13 +203,32 @@ props.pr_maxslname = NAMSIZ-1; props.pr_maxprefix = 0; props.pr_sparse_in_hdr = SPARSE_IN_HDR; + /* + * GNU tar is limited to the USTAR file types + sparse files + */ + movebytes(xtustar_tab, props.pr_xftypetab, sizeof(props.pr_xftypetab)); + props.pr_xftypetab[XT_SPARSE] = 1; + + prsettypeflags("01234567DKLMNSV", TF_VALIDTYPE); + prsettypeflags("KLM", TF_XHEADERS); break; - case H_TAR: - case H_OTAR: + case H_TAR: /* tar with unknown format */ + case H_OTAR: /* tar old format (1978 ???) */ default: + /* + * Since the large file summit was in 1995, we may assume + * that any large file aware TAR implementation must be POSIX + * compliant too. The only known exception is GNU tar which + * is recognised separately. + * Limit max file size to the max that is supported + * by non large file aware systems. + */ + props.pr_maxsize = MAXNONLARGEFILE; props.pr_flags = 0; - props.pr_fillc = ' '; + props.pr_xdflags = 0; + props.pr_fillc = ' '; /* Use old tar octal format */ + props.pr_xc = 'x'; /* Really ??? */ props.pr_diffmask = (D_ATIME|D_CTIME); props.pr_nflags = PR_DUMB_EOF; props.pr_maxnamelen = NAMSIZ-1; @@ -116,6 +237,18 @@ props.pr_maxslname = NAMSIZ-1; props.pr_maxprefix = 0; props.pr_sparse_in_hdr = 0; + /* + * Only a very limited set of file types (file,symlink,dir) + */ + movebytes(xttar_tab, props.pr_xftypetab, sizeof(props.pr_xftypetab)); + + /* + * Old tar does no know about file types bejond "012" but the + * USTAR basic format has been designed to be compatible with + * the old tar format. + */ + prsettypeflags("01234567", TF_VALIDTYPE); + prsettypeflags("", TF_XHEADERS); } if (debug) printprops(); } @@ -123,7 +256,14 @@ EXPORT void printprops() { +extern long hdrtype; + error("hdrtype: %ld\n", hdrtype); + if (props.pr_maxsize) + error("pr_maxsize: %llu\n", (Ullong)props.pr_maxsize); + else + error("pr_maxsize: unlimited\n"); error("pr_flags: 0x%X\n", props.pr_flags); + error("pr_xdflags: 0x%X\n", props.pr_xdflags); error("pr_fillc: '%c'\n", props.pr_fillc); prdiffopts(stderr, "pr_diffmask: ", props.pr_diffmask); error("pr_nflags: 0x%X\n", props.pr_nflags); @@ -133,4 +273,21 @@ error("pr_maxslname: %d\n", props.pr_maxslname); error("pr_maxprefix: %d\n", props.pr_maxprefix); error("pr_sparse_in_hdr: %d\n", props.pr_sparse_in_hdr); +} + +LOCAL void +prsettypeflags(types, typeflag) + char *types; + int typeflag; +{ + register Uchar *ucp = (Uchar *)types; + + /* + * 'Otar' flag for plain file is always a valid typeflag. + */ + if (typeflag == TF_VALIDTYPE) + props.pr_typeflagtab[0] = typeflag; + + while (*ucp != '\0') + props.pr_typeflagtab[*ucp++] |= typeflag; } diff -ruN star-1.3.1/star/props.h star-1.4/star/props.h --- star-1.3.1/star/props.h Fri May 9 15:07:50 1997 +++ star-1.4/star/props.h Fri Dec 7 20:30:38 2001 @@ -1,4 +1,4 @@ -/* @(#)props.h 1.7 97/05/09 Copyright 1994 J. Schilling */ +/* @(#)props.h 1.12 01/12/07 Copyright 1994 J. Schilling */ /* * Properties definitions to handle different * archive types @@ -21,15 +21,31 @@ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + /* - * Properties to describe the different archive formats. + * Properties to describe the different archive formats. + * + * if pr_maxnamelen id == pr_maxsname, we cannot have long names + * besides file name splitting. + * + * NOTE that part of the information in struct propertiesis available more + * than once. This is needed as different parts of the source need the + * information in different ways. Partly for performance reasons, partly + * because one method of storing the information is inappropriate for all + * places in the source. + * + * If you add new features or information related to the fields + * pr_flags/pr_nflags or the fields pr_xftypetab[]/pr_typeflagtab[] + * take care of possible problems due to this fact. * - * if pr_maxnamelen id == pr_maxsname, we cannot have long names - * besides file name splitting. */ struct properties { + Ullong pr_maxsize; /* max file size */ int pr_flags; /* gerneral flags */ + int pr_xdflags; /* default extended header flags */ char pr_fillc; /* fill prefix for numbers in TCB */ + char pr_xc; /* typeflag used for extended headers */ long pr_diffmask; /* diffopts not supported */ int pr_nflags; /* name related flags */ int pr_maxnamelen; /* max length for filename */ @@ -38,9 +54,16 @@ int pr_maxslname; /* max length for short linkname */ int pr_maxprefix; /* max length of prefix if splitting */ int pr_sparse_in_hdr; /* # of sparse entries in header */ + char pr_xftypetab[32]; /* (*1) list of supported file types */ + char pr_typeflagtab[256]; /* (*2) list of supported TCB typeflags */ }; /* + * 1) pr_xftypetab is used when creating archives only. + * 2) pr_typeflagtab is used when extracting archives only. + */ + +/* * general flags */ #define PR_POSIX_OCTAL 0x0001 /* left fill octal number with '0' */ @@ -49,6 +72,7 @@ #define PR_SPARSE 0x0010 /* can handle sparse files */ #define PR_GNU_SPARSE_BUG 0x0020 /* size does not contain ext. headers*/ #define PR_VOLHDR 0x0100 /* can handle volume headers */ +#define PR_XHDR 0x0200 /* POSIX.1-2001 extended headers */ /* * name related flags @@ -57,5 +81,20 @@ #define PR_PREFIX_REUSED 0x02 /* prefix space used by other option */ #define PR_LONG_NAMES 0x04 /* can handle very long names */ #define PR_DUMB_EOF 0x10 /* handle t_name[0] == '\0' as EOF */ + +/* + * Macro to make pr_xftypetab easier to use. See also table.h/table.c. + */ +#define pr_unsuptype(i) (props.pr_xftypetab[(i)->f_xftype] == 0) + +/* + * typeflagtab related flags + */ +#define TF_VALIDTYPE 0x01 /* A valid typeflag for extraction */ +#define TF_XHEADERS 0x02 /* This is a valid extended header */ + +#define _pr_typeflags(c) (props.pr_typeflagtab[(Uchar)(c)]) +#define pr_validtype(c) ((_pr_typeflags(c) & TF_VALIDTYPE) != 0) +#define pr_isxheader(c) ((_pr_typeflags(c) & TF_XHEADERS) != 0) extern struct properties props; diff -ruN star-1.3.1/star/remote.c star-1.4/star/remote.c --- star-1.3.1/star/remote.c Sun Nov 12 16:24:47 2000 +++ star-1.4/star/remote.c Mon May 20 13:58:06 2002 @@ -1,14 +1,17 @@ /*#define USE_REMOTE*/ -#ifdef USE_REMOTE -/* @(#)remote.c 1.22 00/11/12 Copyright 1990 J. Schilling */ +/* @(#)remote.c 1.39 02/05/20 Copyright 1990 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)remote.c 1.22 00/11/12 Copyright 1990 J. Schilling"; + "@(#)remote.c 1.39 02/05/20 Copyright 1990 J. Schilling"; #endif /* * Remote tape interface * * Copyright (c) 1990 J. Schilling + * + * TOTO: + * Signal handler for SIGPIPE + * check rmtaborted for exit() / clean abort of connection */ /* * This program is free software; you can redistribute it and/or modify @@ -27,8 +30,15 @@ */ #include + +#if !defined(HAVE_NETDB_H) || !defined(HAVE_RCMD) +#undef USE_REMOTE /* There is no rcmd() */ +#endif + +#ifdef USE_REMOTE #include -#include +#include +#include #include #ifdef HAVE_SYS_MTIO_H #include @@ -42,9 +52,8 @@ #include #include #include -#include -#include #include +#include #include #include "remote.h" @@ -54,27 +63,30 @@ #define CMD_SIZE 80 -extern BOOL debug; +LOCAL BOOL rmt_debug; LOCAL void rmtabrt __PR((int sig)); +EXPORT int rmtdebug __PR((int dlevel)); +EXPORT char *rmthostname __PR((char *hostname, char *rmtspec, int size)); EXPORT int rmtgetconn __PR((char* host, int size)); LOCAL void rmtoflags __PR((int fmode, char *cmode)); EXPORT int rmtopen __PR((int fd, char* fname, int fmode)); EXPORT int rmtclose __PR((int fd)); EXPORT int rmtread __PR((int fd, char* buf, int count)); EXPORT int rmtwrite __PR((int fd, char* buf, int count)); -EXPORT int rmtseek __PR((int fd, long offset, int whence)); +EXPORT off_t rmtseek __PR((int fd, off_t offset, int whence)); EXPORT int rmtioctl __PR((int fd, int cmd, int count)); LOCAL int rmtmapold __PR((int cmd)); LOCAL int rmtmapnew __PR((int cmd)); -LOCAL int rmtxstatus __PR((int fd, int cmd)); -LOCAL struct mtget* rmt_v1_status __PR((int fd)); -EXPORT struct mtget* rmtstatus __PR((int fd)); -LOCAL int rmtcmd __PR((int fd, char* name, char* cbuf)); +LOCAL Llong rmtxstatus __PR((int fd, int cmd)); +LOCAL int rmt_v1_status __PR((int fd, struct mtget* mtp)); +EXPORT int rmtstatus __PR((int fd, struct mtget* mtp)); +LOCAL Llong rmtcmd __PR((int fd, char* name, char* cbuf)); LOCAL void rmtsendcmd __PR((int fd, char* name, char* cbuf)); LOCAL int rmtgetline __PR((int fd, char* line, int count)); -LOCAL int rmtgetstatus __PR((int fd, char* name)); +LOCAL Llong rmtgetstatus __PR((int fd, char* name)); LOCAL int rmtaborted __PR((int fd)); +EXPORT char *rmtfilename __PR((char *name)); LOCAL void rmtabrt(sig) @@ -84,6 +96,40 @@ } EXPORT int +rmtdebug(dlevel) + int dlevel; +{ + int odebug = rmt_debug; + + rmt_debug = dlevel; + return (odebug); +} + +EXPORT char * +rmthostname(hostname, rmtspec, size) + char *hostname; + char *rmtspec; + register int size; +{ + register int i; + register char *hp; + register char *fp; + register char *remfn; + + if ((remfn = rmtfilename(rmtspec)) == NULL) { + hostname[0] = '\0'; + return (NULL); + } + remfn--; + for (fp = rmtspec, hp = hostname, i = 1; + fp < remfn && i < size; i++) { + *hp++ = *fp++; + } + *hp = '\0'; + return (hostname); +} + +EXPORT int rmtgetconn(host, size) char *host; int size; @@ -111,13 +157,18 @@ } } if ((p = strchr(host, '@')) != NULL) { - js_snprintf(rmtuser, sizeof(rmtuser), "%.*s", p - host, host); + size_t d = p - host; + + if (d > sizeof(rmtuser)) + d = sizeof(rmtuser); + js_snprintf(rmtuser, sizeof(rmtuser), "%.*s", + (int)d, host); name = rmtuser; host = &p[1]; } else { name = pw->pw_name; } - if (debug) + if (rmt_debug) errmsgno(EX_BAD, "locuser: '%s' rmtuser: '%s' host: '%s'\n", pw->pw_name, name, host); rmtpeer = host; @@ -135,7 +186,7 @@ (char *)&size, sizeof (size)) < 0) { size -= 512; } - if (debug) + if (rmt_debug) errmsgno(EX_BAD, "sndsize: %d\n", size); #endif #ifdef SO_RCVBUF @@ -144,7 +195,7 @@ (char *)&size, sizeof (size)) < 0) { size -= 512; } - if (debug) + if (rmt_debug) errmsgno(EX_BAD, "rcvsize: %d\n", size); #endif @@ -284,6 +335,8 @@ rmtoflags(fmode, cmode); js_snprintf(cbuf, CMD_SIZE, "O%s\n%d %s\n", fname, fmode & O_ACCMODE, cmode); ret = rmtcmd(fd, "open", cbuf); + if (ret < 0) + return (ret); /* * Tell the rmt server that we are aware of Version 1 commands. @@ -317,8 +370,22 @@ if (n < 0) return (-1); + /* + * Nice idea from disassembling Solaris ufsdump... + */ + if (n > count) { + errmsgno(EX_BAD, + "rmtread: expected response size %d, got %d\n", + count, n); + errmsgno(EX_BAD, + "This means the remote rmt daemon is not compatible.\n"); + return (rmtaborted(fd)); + /* + * XXX Should we better abort (exit) here? + */ + } while (amt < n) { - if ((cnt = read(fd, &buf[amt], n - amt)) <= 0) { + if ((cnt = _niread(fd, &buf[amt], n - amt)) <= 0) { return (rmtaborted(fd)); } amt += cnt; @@ -337,58 +404,33 @@ js_snprintf(cbuf, CMD_SIZE, "W%d\n", count); rmtsendcmd(fd, "write", cbuf); - write(fd, buf, count); + if (_niwrite(fd, buf, count) != count) + rmtaborted(fd); return (rmtgetstatus(fd, "write")); } -EXPORT int +EXPORT off_t rmtseek(fd, offset, whence) int fd; - long offset; + off_t offset; int whence; { char cbuf[CMD_SIZE]; - js_snprintf(cbuf, CMD_SIZE, "L%ld\n%d\n", offset, whence); - return (rmtcmd(fd, "seek", cbuf)); -} + switch (whence) { -/* - * Definitions for the new RMT Protocol version 1 - * - * The new Protocol version tries to make the use - * of rmtioctl() more portable between different platforms. - */ -#define RMTIVERSION -1 -#define RMT_NOVERSION -1 -#define RMT_VERSION 1 + case 0: whence = SEEK_SET; break; + case 1: whence = SEEK_CUR; break; + case 2: whence = SEEK_END; break; -/* - * Support for commands bejond MTWEOF..MTNOP (0..7) - */ -#define RMTICACHE 0 -#define RMTINOCACHE 1 -#define RMTIRETEN 2 -#define RMTIERASE 3 -#define RMTIEOM 4 -#define RMTINBSF 5 + default: + seterrno(EINVAL); + return (-1); + } -/* - * Old MTIOCGET copies a binary version of struct mtget back - * over the wire. This is highly non portable. - * MTS_* retrieves ascii versions (%d format) of a single - * field in the struct mtget. - * NOTE: MTS_ERREG may only be valid on the first call and - * must be retrived first. - */ -#define MTS_TYPE 'T' /* mtget.mt_type */ -#define MTS_DSREG 'D' /* mtget.mt_dsreg */ -#define MTS_ERREG 'E' /* mtget.mt_erreg */ -#define MTS_RESID 'R' /* mtget.mt_resid */ -#define MTS_FILENO 'F' /* mtget.mt_fileno */ -#define MTS_BLKNO 'B' /* mtget.mt_blkno */ -#define MTS_FLAGS 'f' /* mtget.mt_flags */ -#define MTS_BF 'b' /* mtget.mt_bf */ + js_snprintf(cbuf, CMD_SIZE, "L%lld\n%d\n", (Llong)offset, whence); + return ((off_t)rmtcmd(fd, "seek", cbuf)); +} EXPORT int rmtioctl(fd, cmd, count) @@ -418,7 +460,7 @@ * We cannot map the current command but it's value is * within the range 0..7. Do not send it over the wire. */ - errno = EINVAL; + seterrno(EINVAL); return (-1); } if (i >= 0) @@ -518,9 +560,7 @@ return (-1); } -static struct mtget mts; - -LOCAL int +LOCAL Llong rmtxstatus(fd, cmd) int fd; char cmd; @@ -532,45 +572,47 @@ return (rmtcmd(fd, "extended status", cbuf)); } -LOCAL struct mtget * -rmt_v1_status(fd) - int fd; +LOCAL int +rmt_v1_status(fd, mtp) + int fd; + struct mtget *mtp; { - mts.mt_erreg = mts.mt_type = 0; + mtp->mt_erreg = mtp->mt_type = 0; #ifdef HAVE_MTGET_ERREG - mts.mt_erreg = rmtxstatus(fd, MTS_ERREG); /* must be first */ + mtp->mt_erreg = rmtxstatus(fd, MTS_ERREG); /* must be first */ #endif #ifdef HAVE_MTGET_TYPE - mts.mt_type = rmtxstatus(fd, MTS_TYPE); + mtp->mt_type = rmtxstatus(fd, MTS_TYPE); #endif - if (mts.mt_erreg == -1 || mts.mt_type == -1) - return (0); + if (mtp->mt_erreg == -1 || mtp->mt_type == -1) + return (-1); #ifdef HAVE_MTGET_DSREG /* doch immer vorhanden ??? */ - mts.mt_dsreg = rmtxstatus(fd, MTS_DSREG); + mtp->mt_dsreg = rmtxstatus(fd, MTS_DSREG); #endif #ifdef HAVE_MTGET_RESID - mts.mt_resid = rmtxstatus(fd, MTS_RESID); + mtp->mt_resid = rmtxstatus(fd, MTS_RESID); #endif #ifdef HAVE_MTGET_FILENO - mts.mt_fileno = rmtxstatus(fd, MTS_FILENO); + mtp->mt_fileno = rmtxstatus(fd, MTS_FILENO); #endif #ifdef HAVE_MTGET_BLKNO - mts.mt_blkno = rmtxstatus(fd, MTS_BLKNO); + mtp->mt_blkno = rmtxstatus(fd, MTS_BLKNO); #endif #ifdef HAVE_MTGET_FLAGS - mts.mt_flags = rmtxstatus(fd, MTS_FLAGS); + mtp->mt_flags = rmtxstatus(fd, MTS_FLAGS); #endif #ifdef HAVE_MTGET_BF - mts.mt_bf = rmtxstatus(fd, MTS_BF); + mtp->mt_bf = rmtxstatus(fd, MTS_BF); #endif - return (&mts); + return (0); } -EXPORT struct mtget * -rmtstatus(fd) - int fd; +EXPORT int +rmtstatus(fd, mtp) + int fd; + struct mtget *mtp; { register int i; register char *cp; @@ -578,25 +620,39 @@ int n; if (rmtioctl(fd, RMTIVERSION, 0) == RMT_VERSION) - return (rmt_v1_status(fd)); + return (rmt_v1_status(fd, mtp)); /* No newline */ if ((n = rmtcmd(fd, "status", "S")) < 0) - return (0); + return (-1); - for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++) + /* + * From disassembling Solaris ufsdump, they seem to check + * only if (n > sizeof(mts)). + */ + if (n != sizeof(struct mtget)) { + errmsgno(EX_BAD, + "rmtstatus: expected response size %d, got %d\n", + (int)sizeof(struct mtget), n); + errmsgno(EX_BAD, + "This means the remote rmt daemon is not compatible.\n"); + /* + * XXX should we better abort here? + */ + } + + for (i = 0, cp = (char *)mtp; i < sizeof(struct mtget); i++) *cp++ = 0; - for (i = 0, cp = (char *)&mts; i < n; i++) { + for (i = 0, cp = (char *)mtp; i < n; i++) { /* * Make sure to read all bytes because we otherwise * would confuse the protocol. Do not copy more * than the size of our local struct mtget. */ - if (read(fd, &c, 1) != 1) { - rmtaborted(fd); - return (0); - } - if (i < sizeof(mts)) + if (_niread(fd, &c, 1) != 1) + return (rmtaborted(fd)); + + if (i < sizeof(struct mtget)) *cp++ = c; } /* @@ -605,10 +661,10 @@ * work if one system is running Linux. The Linux mtget structure * is completely incompatible (mt_type is long instead of short). */ - return (&mts); + return (n); } -LOCAL int +LOCAL Llong rmtcmd(fd, name, cbuf) int fd; char *name; @@ -626,8 +682,8 @@ { int buflen = strlen(cbuf); - errno = 0; - if (write(fd, cbuf, buflen) != buflen) + seterrno(0); + if (_niwrite(fd, cbuf, buflen) != buflen) rmtaborted(fd); } @@ -640,7 +696,7 @@ register char *cp; for (cp = line; cp < &line[count]; cp++) { - if (read(fd, cp, 1) != 1) + if (_niread(fd, cp, 1) != 1) return (rmtaborted(fd)); if (*cp == '\n') { @@ -648,35 +704,37 @@ return (cp - line); } } + if (rmt_debug) + errmsgno(EX_BAD, "Protocol error (in rmtgetline).\n"); return (rmtaborted(fd)); } -LOCAL int +LOCAL Llong rmtgetstatus(fd, name) int fd; char *name; { char cbuf[CMD_SIZE]; char code; - int number; + Llong number; rmtgetline(fd, cbuf, sizeof(cbuf)); code = cbuf[0]; - number = atoi(&cbuf[1]); + astoll(&cbuf[1], &number); if (code == 'E' || code == 'F') { rmtgetline(fd, cbuf, sizeof(cbuf)); if (code == 'F') /* should close file ??? */ rmtaborted(fd); - if (debug) - errmsgno(number, "Remote status(%s): %d '%s'.\n", + if (rmt_debug) + errmsgno(number, "Remote status(%s): %lld '%s'.\n", name, number, cbuf); - errno = number; - return (-1); + seterrno(number); + return ((Llong)-1); } if (code != 'A') { /* XXX Hier kommt evt Command not found ... */ - if (debug) + if (rmt_debug) errmsgno(EX_BAD, "Protocol error (got %s).\n", cbuf); return (rmtaborted(fd)); } @@ -687,12 +745,50 @@ rmtaborted(fd) int fd; { - if (debug) + if (rmt_debug) errmsgno(EX_BAD, "Lost connection to remote host ??\n"); /* if fd >= 0 */ /* close file */ - if (errno == 0) - errno = EIO; + if (geterrno() == 0) { +/* errno = EIO;*/ + seterrno(EPIPE); + } + /* + * BSD used EIO but EPIPE is better for something like sdd -noerror + */ return (-1); } + #endif /* USE_REMOTE */ + +#ifndef USE_REMOTE +#include +#include + +EXPORT char *rmtfilename __PR((char *name)); +#endif + +EXPORT char * +rmtfilename(name) + char *name; +{ + char *ret; + + if (name[0] == '/') + return (NULL); /* Absolut pathname cannot be remote */ + if (name[0] == '.') { + if (name[1] == '/' || (name[1] == '.' && name[2] == '/')) + return (NULL); /* Relative pathname cannot be remote*/ + } + if ((ret = strchr(name, ':')) != NULL) { + if (name[0] == ':') { + /* + * This cannot be a remote filename as the host part + * has zero length. + */ + return (NULL); + } + ret++; /* Skip the colon. */ + } + return (ret); +} diff -ruN star-1.3.1/star/remote.h star-1.4/star/remote.h --- star-1.3.1/star/remote.h Sun Nov 12 16:23:06 2000 +++ star-1.4/star/remote.h Wed Aug 1 23:32:12 2001 @@ -1,4 +1,4 @@ -/* @(#)remote.h 1.1 00/11/12 Copyright 1996 J. Schilling */ +/* @(#)remote.h 1.7 01/08/02 Copyright 1996 J. Schilling */ /* * Prototypes for rmt client subroutines * @@ -23,16 +23,63 @@ #ifndef _REMOTE_H #define _REMOTE_H +#ifndef _INCL_SYS_TYPES_H +#include +#define _INCL_SYS_TYPES_H +#endif + +/* + * Definitions for the new RMT Protocol version 1 + * + * The new Protocol version tries to make the use + * of rmtioctl() more portable between different platforms. + */ +#define RMTIVERSION -1 +#define RMT_NOVERSION -1 +#define RMT_VERSION 1 + +/* + * Support for commands bejond MTWEOF..MTNOP (0..7) + */ +#define RMTICACHE 0 +#define RMTINOCACHE 1 +#define RMTIRETEN 2 +#define RMTIERASE 3 +#define RMTIEOM 4 +#define RMTINBSF 5 + +/* + * Old MTIOCGET copies a binary version of struct mtget back + * over the wire. This is highly non portable. + * MTS_* retrieves ascii versions (%d format) of a single + * field in the struct mtget. + * NOTE: MTS_ERREG may only be valid on the first call and + * must be retrived first. + */ +#define MTS_TYPE 'T' /* mtget.mt_type */ +#define MTS_DSREG 'D' /* mtget.mt_dsreg */ +#define MTS_ERREG 'E' /* mtget.mt_erreg */ +#define MTS_RESID 'R' /* mtget.mt_resid */ +#define MTS_FILENO 'F' /* mtget.mt_fileno */ +#define MTS_BLKNO 'B' /* mtget.mt_blkno */ +#define MTS_FLAGS 'f' /* mtget.mt_flags */ +#define MTS_BF 'b' /* mtget.mt_bf */ + /* * remote.c */ +extern int rmtdebug __PR((int dlevel)); +extern char *rmtfilename __PR((char *name)); +extern char *rmthostname __PR((char *hostname, char *rmtspec, int size)); extern int rmtgetconn __PR((char* host, int size)); extern int rmtopen __PR((int fd, char* fname, int fmode)); extern int rmtclose __PR((int fd)); extern int rmtread __PR((int fd, char* buf, int count)); extern int rmtwrite __PR((int fd, char* buf, int count)); -extern int rmtseek __PR((int fd, long offset, int whence)); +extern off_t rmtseek __PR((int fd, off_t offset, int whence)); extern int rmtioctl __PR((int fd, int cmd, int count)); -extern struct mtget* rmtstatus __PR((int fd)); +#ifdef MTWEOF +extern int rmtstatus __PR((int fd, struct mtget* mtp)); +#endif #endif /* _REMOTE_H */ diff -ruN star-1.3.1/star/remove.c star-1.4/star/remove.c --- star-1.3.1/star/remove.c Thu Jan 1 01:00:00 1970 +++ star-1.4/star/remove.c Wed Apr 24 23:09:50 2002 @@ -0,0 +1,201 @@ +/* @(#)remove.c 1.44 02/04/25 Copyright 1985 J. Schilling */ +#ifndef lint +static char sccsid[] = + "@(#)remove.c 1.44 02/04/25 Copyright 1985 J. Schilling"; +#endif +/* + * remove files an file trees + * + * Copyright (c) 1985 J. Schilling + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include "star.h" +#include "table.h" +#include /*XXX Wegen S_IFLNK */ +#include +#include +#include + +#ifdef JOS +# include +#else +# include +# define EMISSDIR ENOENT +#endif +#include "starsubs.h" + + +extern FILE *tty; +extern FILE *vpr; +extern BOOL interactive; +extern BOOL force_remove; +extern BOOL ask_remove; +extern BOOL remove_first; +extern BOOL remove_recursive; + +EXPORT BOOL remove_file __PR((char* name, BOOL isfirst)); +LOCAL BOOL _remove_file __PR((char* name, BOOL isfirst, int depth)); +LOCAL BOOL remove_tree __PR((char* name, BOOL isfirst, int depth)); + +EXPORT BOOL +remove_file(name, isfirst) + register char *name; + BOOL isfirst; +{ + static int depth = -10; + static int dinit = 0; + + if (!dinit) { +#ifdef _SC_OPEN_MAX + depth += sysconf(_SC_OPEN_MAX); +#else + depth += getdtablesize(); +#endif + dinit = 1; + } + return (_remove_file(name, isfirst, depth)); +} + +LOCAL BOOL +_remove_file(name, isfirst, depth) + register char *name; + BOOL isfirst; + int depth; +{ + char buf[32]; + char ans = '\0'; + int err = EX_BAD; + BOOL fr_save = force_remove; + BOOL rr_save = remove_recursive; + BOOL ret; + + if (remove_first && !isfirst) + return (FALSE); + if (!force_remove && (interactive || ask_remove)) { + fprintf(vpr, "remove '%s' ? Y(es)/N(o) :", name);fflush(vpr); + fgetline(tty, buf, 2); + } + if (force_remove || + ((interactive || ask_remove) && (ans = toupper(buf[0])) == 'Y')) { + + /* + * only unlink non directories or empty directories + */ + if (rmdir(name) < 0) { + err = geterrno(); + if (err == ENOTDIR) { + if (unlink(name) < 0) { + err = geterrno(); + goto cannot; + } + return (TRUE); + } +#if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST + if (err == EEXIST || err == ENOTEMPTY) { +#else + if (err == EEXIST) { +#endif + if (!remove_recursive) { + if (ans == 'Y') { + fprintf(vpr, + "Recursive remove nonempty '%s' ? Y(es)/N(o) :", + name); + fflush(vpr); + fgetline(tty, buf, 2); + if (toupper(buf[0]) == 'Y') { + force_remove = TRUE; + remove_recursive = TRUE; + } else { + goto nonempty; + } + } else { + nonempty: + errmsgno(err, + "Nonempty directory '%s' not removed.\n", + name); + return (FALSE); + } + } + ret = remove_tree(name, isfirst, depth); + + force_remove = fr_save; + remove_recursive = rr_save; + return (ret); + } + goto cannot; + } + return (TRUE); + } +cannot: + errmsgno(err, "File '%s' not removed.\n", name); + return (FALSE); +} + +LOCAL BOOL +remove_tree(name, isfirst, depth) + register char *name; + BOOL isfirst; + int depth; +{ + DIR *d; + struct dirent *dir; + BOOL ret = TRUE; + char xn[PATH_MAX]; /* XXX A bad idea for a final solution */ + char *p; + + if ((d = opendir(name)) == NULL) { + return (FALSE); + } + depth--; + + strcpy(xn, name); + p = &xn[strlen(name)]; + *p++ = '/'; + + while ((dir = readdir(d)) != NULL) { + + if (streql(dir->d_name, ".") || + streql(dir->d_name, "..")) + continue; + + strcpy(p, dir->d_name); + + if (depth <= 0) { + closedir(d); + } + if (!_remove_file(xn, isfirst, depth)) + ret = FALSE; + if (depth <= 0 && (d = opendir(name)) == NULL) { + return (FALSE); + } + } + + closedir(d); + + if (ret == FALSE) + return (ret); + + if (rmdir(name) >= 0) + return (ret); + + errmsg("Directory '%s' not removed.\n", name); + return (FALSE); +} diff -ruN star-1.3.1/star/star.1 star-1.4/star/star.1 --- star-1.3.1/star/star.1 Sat Apr 14 13:12:56 2001 +++ star-1.4/star/star.1 Thu May 9 15:35:20 2002 @@ -1,4 +1,4 @@ -. \" @(#)star.1 1.18 01/04/14 Copyr 1982-1995 J. Schilling +. \" @(#)star.1 1.47 02/05/09 Copyr 1982-2001 J. Schilling . \" Manual Seite fuer star . \" .if t .ds a \v'-0.55m'\h'0.00n'\z.\h'0.40n'\z.\v'0.55m'\h'-0.40n'a @@ -13,12 +13,25 @@ .if n .ds o oe .if n .ds u ue .if n .ds s sz -.TH STAR 1 "Release 1.1" "J\*org Schilling" "Schily\'s USER COMMANDS" +.TH STAR 1 "02/05/09" "J\*org Schilling" "Schily\'s USER COMMANDS" .SH NAME star \- unique standard tape archiver .SH SYNOPSIS -.B -star +.B "star\ " +.I command +[ +.I options +] +.I file1 .\|.\|. filen +.br +.B ustar +.I command +[ +.I options +] +.I file1 .\|.\|. filen +.br +.B "tar\ \ " .I command [ .I options @@ -26,17 +39,17 @@ .I file1 .\|.\|. filen .SH DESCRIPTION .B Star -is a tape archiver similar to +is a very fast .BR tar (1) -but faster than -.BR tar (1) -and with improved functionality. +like tape archiver with improved functionality. .PP .B Star archives and extracts multiple files to and from a single file called a .I tarfile. -A tarfile is usually a magnetic tape, but it can be any file. +A +.I tarfile +is usually a magnetic tape, but it can be any file. In all cases, appearance of a directory name refers to the files and (recursively) subdirectories of that directory. .PP @@ -48,7 +61,24 @@ acts may be modified by additional options. .SH FEATURES .B Star -uses a fifo to optimize data flow from/to tape. This results in +includes the first free implementation of +.B POSIX.1\-2001 +extended +.B tar +headers. The extended +.B tar +headers define a new standard way +for going beyond the limitations of the historic +.B tar +format. +They allow (among others) to archive all UNIX time stamps in sub\-second +resolution, files of arbitrary size and filenames without length limitation +using +.B UNICODE UTF\-8 +coding for best exchange compatibility. +.PP +.B Star +by default uses a fifo to optimize data flow from/to tape. This results in a normally streaming tape during the whole backup. See .B \-fifo @@ -61,16 +91,29 @@ processed. This gives a convenient interface for archiving and restoring complex lists of files. In conjunction with the .B \-w -flag it is easy to merge a tar archive into an existing file tree. See also +flag it is easy to merge a +.B tar +archive into an existing file tree. See also .B \-U option. In create mode use the .B pat= -option to specify select or exclude patterns, in extract or list mode -all file type arguments are interpreted as select or exclude patterns. +option to specify either select or exclude patterns (depending on +the +.B \-V +flag). In extract or list mode +all file type arguments are interpreted as select patterns while +the patterns specified with the +.B pat= +option may be used as select or exclude patterns (depending on +the +.B \-V +flag). Have a look at the description of the .B \-C -option to learn how to distribute files to a list of directories. +option to learn how fetch files from a list of directories +(in create mode) or to distribute files to a list of directories +(in extract mode). .PP .B Star includes a sophisticated diff command. Several diff options @@ -82,12 +125,19 @@ option for more details. .PP .B Star -has no limitation on filename length. Pathnames and linknames up to -1024\ bytes may be archived. Later versions may be able to deal with +has no limitation on filename length. Pathnames and linknames up to +.I PATH_MAX +(1023\ bytes with old OS versions and 4095\ bytes with POSIX.1\-2001) +may be archived. Later versions may be able to deal with longer pathnames. .PP .B Star -deals with all 3 times, available for files on UNIX systems. +deals with all 3 times, available for files on UNIX systems if the +archive format is either chosen from the star specific formats or +is a format that uses POSIX.1\-2001 extended headers. +This is either done in second resolution by using a star specific +POSIX.1\-1988 compatible extension or in sub second resolution by +using POSIX.1\-2001 extended headers. .B Star is able to store and restore all 3 times (mtime, atime and even ctime). On Solaris 2.x systems, @@ -96,15 +146,34 @@ .PP If used with the .BI H= ustar -option, star is 100% ansi compliant. +option, or if called as +.B ustar +or +.B tar +while the +.BR H= headertype +option is not used, +.B star +is 100% POSIX compliant. .PP .B "Star's -new default format +default format (if called as +.BR star ) +is .I xstar -is as posix compliant as possible. Deviations from the standard that -prevent correct extraction with a fully ansi compliant tar -implementation occur, when the pathname is longer than 100+130 chars -or when archiving sparse files with the \-sparse option in effect. +and is as posix compliant as possible. Enhancements to the standard that +prevent correct extraction of single files when using a different +.B tar +implementation that is only POSIX.1\-1988 compliant may occur, +but they only affect single files with a pathname that is longer than 100+130 chars +or when archiving sparse files with the +.B \-sparse +option in effect. +All other files will extract correctly. +See the description for the +.BI H= headertype +option below for more information on archive formats and possible archive +interchange problems. .PP .B Star makes it easy to repair corrupted filesystems. After a fsck \-y @@ -113,7 +182,7 @@ is able to restore only the missing files automatically. Use then -.I "star -diff +.I "star \-diff to check for differences (see EXAMPLES for more information). .PP .B Star @@ -125,18 +194,74 @@ See the .BR H= headertype option for more details. +To be able to do this, +.B star +adds hidden fingerprints to the archive header that allows to recognise +all star specific archive formats. The GNU tar format is recognised by +the way it deviates from the standard. .PP .B Star automatically recognizes and handles byte swapped archives. There is no option to manually control byte swapping. +.PP +.B Star +automatically recognizes and handles compressed archives inside plain +files. +.PP +.B Star +is able to archive and restore +.B "Access Control Lists +for files using POSIX.1\-2001 extended headers. .SH COMMAND +.PP +In native mode, +.B star +is compatible to the command line syntax of a typical POSIX command +and for this reason expects +.I commands +and +.I options +to start with a single dash (\-). In this case, commands +and options may be specified separately, all boolean or increment type +options may be specified either separately or combined. +For compatibility with GNU programs, long options may alternatively +start with a double dash. +In compatibility mode to POSIX +.BR tar , +.B star +expects commands and options to appear as one single string that does not start +with a dash. +In POSIX tar compatibilitx mode, +additional non POSIX options may be specified but must appear after the +POSIX options and their args and need to start with a dash. .TP .B \-c Create a new .I tarfile -and write named files onto it. +and write named files into it. Writing starts at the beginning of .I tarfile. +See \-v option for information on how to increase verbosity while the +archive is written. +.TP +.B \-diff +Compare the content and the attributes of the files from the archive in +.I tarfile +to the filesystem. +This may also be used to compare two file trees in the filesystem and +gives with a good choice of +.I diffopts +- in some cases - a more readable output than diff \-r. +See +.I diffopts +for more details. +.TP +.B \-n +No extraction. Show what +.B star +would do, in case the +.B \-x +command had been specified. .TP .B \-r Replace files in a @@ -146,27 +271,6 @@ This implies that later, the appropriate files will be found more than once on the .I tarfile. -This command is currently not implemented. -.TP -.B \-u -Update a -.I tarfile. -The named files are written to the end of -.I tarfile -if they are not already there. -The \-r and \-u command only work if the tar archives is a regular file or -if the tar archive is an unblocked tape that may backspace. -This command is currently not implemented. -.TP -.B \-x -Extract the named files from the -.I tarfile. -If no filename argument or pattern is specified, the entire content of the -.I tarfile -is restored. -If the \-U flag is not used, -.B star -extracts no file which is older than the corresponding file on disk. .TP .B \-t Table of contents. @@ -179,9 +283,12 @@ and .B \-ctime have a different meaning if the archive is in -.I star +.BR star , +.BR xstar , +.BR xustar , +.BR exustar , or -.I xstar +.B pax format. The option .B \-a @@ -191,29 +298,35 @@ .B \-ctime lists the file creation time instead of the modification time. .TP -.B \-n -No extraction. Show what -.B star -would do, in case the -.B \-x -command had been specified. +.B \-u +Update a +.I tarfile. +The named files are written to the end of +.I tarfile +if they are not already there or if the files are newer than the files +of the same name found in the archive. +The \-r and \-u command only work if the +.B tar +archives is a regular file or +if the +.B tar +archive is an unblocked tape that may backspace. .TP -.B \-diff -Diff the contents of the +.B \-x +Extract the named files from the +.I tarfile. +If no filename argument or pattern is specified, the entire content of the .I tarfile -to the filesystem. -This may also be used to compare two file trees in the filesystem and -gives with a good choice of -.I diffopts -- in some cases - a more readable output than diff \-r. -See -.I diffopts -for more details. +is restored. +If the \-U flag is not used, +.B star +extracts no file which is older than the corresponding file on disk. .PP -One of the commands above must be specified. +Exactly one of the commands above must be specified. .PP If one or more pattern are specified, they apply to any of the command listed above. + .SH OPTIONS .TP .B \-help @@ -224,20 +337,173 @@ Print a summary of the less important options for .BR star (1). .TP +.B \-/ +Don't strip leading slashes from file names when extracting an archive. +Tar archives containing absolute pathnames are usually a bad idea. +With other +.B tar +implementations, +they may possibly never be extracted without clobbering existing files. +.B Star +for that reason, by default strips leading slashes from filenames +when in extract mode. +As it may be impossible to create an archive where leading slashes have +been stripped while retaining correct path names, +.B star +does not strip leading slashes in create mode. +.TP +.B \-acl +Handle +.B "Access Control List +(ACL) information in create and extract mode. +If +.B \-acl +has been specified, +.B star +is in create mode and the header type is +.BR exustar ", " star +will add ACL information to the archive using POSIX.1\-2001 extended headers. +If +.B \-acl +has been specified and +.B star +is in extract mode, +.B star +will try to restore ACL information. If there is no ACL information for +one or all files in the archive, +.B star +will clear the ACL information for the specific file. +Note that if +.B \-acl +has not been specified, +.B star +will not handle ACL information at all and files may inherit ACL +information from the parent directories. +If the +.B \-acl +option has been specified, +.B star +assumes that the +.B \-p +option has been specified too. +.TP +.B \-ask_remove +obsoleted by \-ask\-remove +.TP +.B \-ask\-remove +Ask to remove non writable files on extraction. +By default, +.B star +will not overwrite files that are read only. +If this option is in effect, +.B star +will ask whether it should remove these files to allow the extraction of a file +in the following way: +.RS +.IP +.BI "remove '" filename "' ? Y(es)/N(o) : +.RE +.TP +.BR \-atime ", " \-a +Reset access time of files after storing them to +.I tarfile. +On Solaris 2.x, (if invoked by root) +.B star +uses the +.I _FIOSATIME +ioctl to do this. This enables +.B star +not to trash the +.I ctime +while resetting the +.I atime +of the files. +If the +.B \-atime +option is used in conjunction with the list command, +.B star +lists access time instead of modification time. (This works only in +conjunction with the +.BR star , +.BR xstar , +.BR xustar , +.BR exustar , +and with the +.B pax +format.) +Another option to retain the access time for the the files that +are going to be archives is to readonly mount a +.B "UFS snapshot +and to archive files from the mount point of the UFS snapshot. +.TP +.B \-B +Force +.B star +to perform multiple reads (if necessary) to fill a block. +This option exists so that +.B star +can work across the Ethernet, since pipes and sockets return partial blocks +even when more data is coming. +If +.B star +uses +.I stdin +as archive file, +.B star +behaves as if it has been called with the +.B \-B +option. +For this reason, the option \-B in practice is rarely needed. +.TP +.B \-block\-number +Print the archive block number (archive offset / 512) at the beginning of +each line when in verbose mode. This allows to write backup scripts +that archive the offsets for files and that use +.sp +.BI " mt fsr" " blockno" +.sp +to skip to the tape block number of interest in a fast way +if a single file needs to be restored. +.TP .BR blocks= "#, " b= "#" Set the blocking factor of the .I tarfile -to #\ times 512\ bytes. The default is to use a blocking factor of 20 i.e. +to #\ times 512\ bytes (unless a different multiplication factor has +been specified - see +.B bs= +option for posible multiplication factors). +Changing the blocking factor only makes sense +when the archive is located on a real tape device or when +the archive is accessed via the remote tape protocol (see +.B f= +option below). +The default is to use a blocking factor of 20 i.e. 10\ kBytes. -Increasing the blocksize will speed up the backup. For portability with very -old tar implementations (pre BSD\ 4.2 or pre AT&T\ SVR4), +Increasing the blocksize will speed up the backup. +For portability with very old +.B tar +implementations (pre BSD\ 4.2 or pre AT&T\ SVR4), blocksize should not be more than 10\ kBytes. -Most systems have a hardware limitation for the blocksize, 32\ kBytes +For POSIX.1\-1988 compatibility, blocksize should be no more than 10\ kBytes. +For POSIX.1\-2001 compatibility, blocksize should be no more than 32\ kBytes. +Most systems also have a hardware limitation for the blocksize, 32\ kBytes and 63\ kBytes are common limits on many systems. The upper limit in any case is the size of the buffer RAM in the tape drive. Make a test if you want to make sure that the target system will handle the intended blocksize. -If you want to determine the blocking factor of an unknown tar archive +If you use +.B star +for data exchange via tape, it is a good idea to use a blocksize of 10\ kBytes +unless you are sure that the reading system will handle a larger blocksize. +If you use +.B star +for backup purposes with recent hardware, a blocksize of 256\ kBytes +results in sufficient speed and seems to be a good choice. +.B Star +allows block sizes up to 2 GByte if the system does not impose a smaller limit. +If you want to determine the blocking factor when reading an unknown +.B tar +archive on tape, specify a blocking factor that is higher than the supposed blocking factor of the tape. .B Star @@ -251,51 +517,525 @@ Where # is the blocking factor in multiples of 512 bytes. The .I blocks= -option is now obsoleted by the +option +and the .I bs= -option described below. +option are equivalent methods to specify the tape block size. +The +.B blocks= +option is preferred by people who like to use an option that behaves +similar to the interface of the historic +.BR tar (1) +implementations. .RE .TP -.B \-copylinks -This option allows to copy hard/symlinks targets -rather than creating a link. -It helps to extract tar files on systems that do not implement -links (e.g. OS/2). -To extract and copy all symlinks correctly, you may need to call +.BR bs= # +Set output block size to #. +You may use the same method as in +.BR dd (1) +and +.BR sdd (1). +The number representing the size is taken in bytes unless otherwise specified. +If a number is followed directly by the letter `.', `w', `b', `k', `m', `g', +`t', or `p', +the size is multiplied by 1, 2, 512, 1024, 1024*1024, 1024*1024*1024, +1024*1024*1024*1024 or 1024*1024*1024*1024*1024. +If the size consists of numbers separated by `x' or `*', multiplication of the +two numbers is performed. +Thus +.I "bs=7x8k +will specify a blocksize of 56\ kBytes. +Blocksize must be a multiple of 512 bytes. +See also the description of the +.I blocks= +option for more details on blocksizes. +The option +.B bs= +is preferred by people who like to use an option that behaves +similar to the interface used by +.BR dd (1) +and +.BR sdd (1). +.TP +.B \-bz +run the input or output through a +.B bzip2 +pipe - see option +.B \-z +below. +As both the +.B \-bz +and the +.B \-z +option are non standard, it makes sense to omit the +.B \-bz +and the +.B \-z +inside shell scripts if you are going to extract a compressed +archive that is located inside a plain file as .B star -twice as +will auto detect compression and choose the right decompression +option to extract. +.TP +.BI C= dir +Perform a +.BR chdir (2) +operation to +.I dir +before storing or extracting the next files. +In all cases, +.B star +will perform the +.BR chdir (2) +operation relative to the current working directory of the shell. +.RS +.TP +.B \(bu +In list mode (with the +.B \-t +flag), .B star -cannot copy files that appear in the archive later than a symlink -pointing to them. +ignores all +.I \-C +options. .TP -.BR file= "tarfilename, " f= "tarfilename" -Use -.I tarfilename -as the name for the tar archive. -.B Star -normally uses -.IR stdin / stdout -for the tar archive because the most common way to use +.B \(bu +In create mode (with the +.BR \-c ", " \-r " and " \-u +flag), .B star -is in conjunction with pipes. -If +walks through all +.I \-C +options and file type arguments. +While a BSD derived +.BR tar (1) +implementation +goes back to the current working directory after storing +one file argument that immediately follows the +.I \-C +option, .B star -is installed suid root, +changes the directory only if a new +.B \-C +option follows. +To emulate the behavior of a BSD derived +.BR tar (1), +add a +.BI \-C " ." +option after the file argument. +.TP +.B \(bu +In extract mode (with the +.BR \-x ", " \-n " and " \-diff +flag), +.B star +builds a pattern list together with corresponding directories and +performs a +.BR chdir (2) +to the corresponding directory of a matching pattern. +All +.B pat= +options in this case are interpreted as if they were preceded by +a +.BI \-C " ." +option. +See EXAMPLES for more information. +.RE +.TP +.B \-copylinks +This option allows to copy hard/symlinks targets +rather than creating a link. +It helps to extract +.B tar +files on systems that do not implement +links (e.g. OS/2). +To extract and copy all symlinks correctly, you may need to call +.B star +twice as +.B star +cannot copy files that appear in the archive later than a symlink +pointing to them. +.TP +.B \-ctime +If used with the list command, this lists +.I ctime +rather than +.I mtime +if the archive format is +.BR star , +.BR xstar , +.BR xustar , +.BR exustar , +or +.BR pax . +If used with the extract command and the same archive formats, +this tries to restore even the +.I ctime +of a file by generating time storms. +You should not do this when in multi user mode because this may +confuse programs like cron and the news system. +If used with the create command this changes the behavior of the +.I newer= +option. +.BR Star , +in this case compares the +.I ctime +of all files to the +.I mtime +of the stamp file rather then comparing the +.I mtimes +of both files. +.TP +.B \-D +Do not descend directories. +Normally, +.B star +descends the whole tree if it encounters a directory in +in its file parameters. +The option +.B \-D +is in effect by default if the +.BI list= file +option is used. +If you like +.B star +to descend directories found in the list file, use the +.B \-dodesc +option (see below). +.TP +.B \-d +Do not store/create directories. +Old versions of +.B tar +such as published with the seventh edition of UNIX +are not able to deal with directories in +.B tar +archives. +If a +.B tar +archive is generated without directories this avoids +problems with +.B tar +implementations found on SYSVr3 and earlier. +.TP +.B \-debug +Print debug messages. Among other things, this gives debug messages for +header type recognition, +.B tar +type properties, EOF recognition, opening +of remote archives and fifo internals. +.TP +.BI diffopts= optlst +Comma separated list of diffopts. +Valid members in +.I optlst +are: +.RS +.TP 10 +.B help +Print a summary of possible members of the diffopts list. +.TP 10 +.B ! +.TP 10 +.B not +Invert the meaning of all members in the diffopts list i.e. exclude +all present options from an initially complete set compare list. +When using +.BR csh (1) +you might have problems to use +.B ! +due to its strange parser. +This is why the +.B not +alias exists. +.TP 10 +.B perm +Compare file permissions. With this option in effect, +.B star +compares the low order 12 bits of the st_mode field. +.TP 10 +.B mode +Same as +.I perm. +.TP 10 +.B type +Compare file type. +Note that +.B star +cannot compare the file type in case of a hard link. +.TP 10 +.B nlink +Compare link count on hardlinks (currently not supported). +.TP 10 +.B uid +Compare numerical user id of file. +.TP 10 +.B gid +Compare numerical group id of file. +.TP 10 +.B uname +Compare ASCII version of user id of file. +The user name is mapped via the file /etc/passwd. +.TP 10 +.B gname +Compare ASCII version of group id of file. +The group name is mapped via the file /etc/group. +.TP 10 +.B id +Compare all user/group related info of file. +Note that this will always find differences if the source and +target system use different user or group mappings. +.TP 10 +.B size +Compare file size. +Note that +.B star +cannot compare the file size in case of a hard link. +.TP 10 +.B nlink +Compare link count on hardlinks (currently not supported). +.TP 10 +.B data +Compare content of file. +If +.B star +already found that the size of the files differ, it will not +compare the content anymore. +.TP 10 +.B cont +Same as +.I data. +.TP +.B rdev +Compare major/minor numbers for device nodes. +.TP 10 +.B hardlink +Compare target of hardlinks. +.TP 10 +.B symlink +Compare target of symlinks. This evaluates the value returned by the +readlink(2) call. +.TP 10 +.B atime +Compare access time of file. +This only works with if the archive format is +.BR star , +.BR xstar , +.BR xustar , +.BR exustar , +or +.BR pax . +.TP 10 +.B mtime +Compare modification time of file. +.TP 10 +.B ctime +This only works with if the archive format is +.BR star , +.BR xstar , +.BR xustar , +.BR exustar , +or +.BR pax . +.TP 10 +.B times +Shorthand for: +.IR "atime,mtime,ctime" . +.PP +If +.I optlst +starts with a ! the meaning of all members in +.I optlst +is inverted as with the +.I not +optlist member. +.PP +If +.I diffopts +are not specified, +.B star +compares everything but the access time of the files. +.RE +.TP +.B \-dirmode +If in create mode (i.e. when storing files to archive), +.B star +stores directories past the corresponding files. This guarantees that even old +.B tar +implementations without a directory cache will be able to restore the +correct times of directories. +.TP +.B \-dodesc +Force +.B star +to descend directories found in a +.BI list= file. +See also the +.B \-D +option above. +.TP +.B \-dump +This currently is an experimental option to make it easier to implement a +.B star +version that supports +.IR "true incremental dumps" . +.B Star +currently sets the archive type to +.B exustar +and archives more inode meta data inside POSIX.1-2001 extended headers. +.TP +.BR \-F , \-FF " ..." +Fast and simple exclude option for create mode. +With one +.B \-F +argument, +.B star +ignores all directories called +.IR SCCS " and " RCS. +With two +.B \-F +arguments, +.B star +in addition ignores all files called +.I core errs a.out +all files ending with +.IR .o . +.IR OBJ/ . +With three +.B \-F +arguments, +.B star +ignores all sub trees starting from a directory that +includes a file +.I .mirror +or +.I .exclude +and all object files and files called +.I core errs a.out +all files ending with +.IR .o . +With four +.B \-F +arguments, +.B star +ignores all sub trees starting from a directory that +includes a file +.I .mirror +or +.I .exclude +the latter files are excluded too as well as +and all object files and files called +.I core errs a.out +all files ending with +.IR .o . +With five +.B \-F +arguments, +.B star +in addition again excludes +all directories called +.IR SCCS " and " RCS. +.TP +.B \-fifo +Use a +.I fifo +to optimize data flow from/to +.I tarfile. +This option is in effect by default (it may be changed at compile time). +The default fifo size is 8 MBytes on all platforms except Linux versions +that do not support mmap() (4 MB because kernels +before 2.4 did not handle big shared memory areas) and Sun/mc68000 (1 MB). +This will +.B star +make even work on a tiny machine like +a Sun 3/50. The fifo size may be modified with the +.I fs= +option. A rule of dumb for the fifo size is to use more than the buffer size +of the tape drive and less then half of the real memory of the machine. +A good choice would be to use a fifo size between 8 and 256 MB. +This may increase backup speed up to 5% compared to the speed achieved +with the default fifo size. Note that with a DLT drive that gives 12MB/s +transfer rate, a fifo of 256 MB size will keep the tape at least streaming +in units of 20 seconds. +All options that start with the +.B \-f +sequence are sensitive to typo problems, see BUGS section for more information. +.TP +.B \-fifostats +Print fifo statistics at the end of a +.B star +run when the fifo has been in effect. +All options that start with the +.B \-f +sequence are sensitive to typo problems, see BUGS section for more information. +.TP +.BR file= "tarfilename, " f= "tarfilename" +Use +.I tarfilename +as the name for the +.B tar +archive. Currently up to 100 +.B file= +options are possible. Specifying more then one +.B file= +option make sense in multi volume mode. In this case +.B star +will use the next name in the list every time a media change is needed. +To make +.B star +behave consistent with the single file case, +.B star +loops over the list of known archive files. +Note that if +.B star +is installed suid root and the first tarfile is a remote archive, +only the connection to this archive will be created with root privilleges. +After this connection has been established as root, +.B star +switches back to the id of the caller. +If any of the other archives in the list is located on a different host, +.B star +will not be able to open this archive later on, unless run by root. +.sp +.B Star +normally uses +.IR stdin / stdout +for the +.B tar +archive because the most common way to use +.B star +is in conjunction with pipes. +If +.B star +is installed suid root or if it has been called by root, .I tarfilename -may be in remote syntax: user@host:filename as in rcp(1) even if +may be in remote syntax: user@host:filename as in +.BR rcp (1) +even if invoked by non root users. See SUID NOTES for more information. .sp -Note that star talks to an old +To make a file local although it includes a colon (:), the filename +must start with: +.IR "'/'" , +.IR "'./'" " or" +.I "'../'" +.sp +Note that if +.B star +talks to an old .B rmt -remote tape server, it does not open a remote tape with the +remote tape server that does not support symbolic open modes, +it does not open a remote tape with the .B O_CREAT open flag because this would be extremely dangerous. If the .B rmt server on the other side is the .B rmt -server that comes with star or the GNU +server that comes with +.B star +or the GNU .B rmt server, .B star @@ -307,106 +1047,59 @@ .B rmt server that comes with .BR star . +It is the only +.B rmt +server that gives platform independent compatibility with BSD, Sun and GNU +.B rmt +clients and it includes security features that may be set up in /etc/default/rmt. +All options that start with the +.B \-f +sequence are sensitive to typo problems, see BUGS section for more information. .TP -.B \-T -If the option -.B file= -or -.B f= -is omitted and the \-T option is present, -.B star -will use the device indicated by the -.SB TAPE -environment variable, -if set. -.TP -.B \-fifo -Use a -.I fifo -to optimize data flow from/to -.I tarfile. -This option is in effect by default (this may be changed at compile time). -The default fifo size is 1MByte. This will even work on a tiny machine like -a Sun 3/50. The fifo size may be modified with the -.I fs= -option. A rule of dumb for the fifo size is to use more than the buffer size -of the tape drive and less then half of the real memory of the machine. -A good choice would be to use 8 or 16 MB. This may increase backup speed up -to 5% compared to the speed achieved with the default fifo size. -.TP -.B \-hpdev -Allow 24 bits for the minor device number using 8 octal digits. -Note that although it allows to create tar archives -that can be read with HP-UX tar, this creates tar archives -which violate POSIX. -.TP -.B \-modebits -This options allows you to create tar archives that include -more than 12 bits from st_mode. Note this create tar archives -that violate POSIX but some tar implementations insist in reading -such nonstandard archives. -.TP -.B \-no_fifo -obsoleted -.TP -.B \-no-fifo -Don't use a -.I fifo -to optimize data flow from/to -.I tarfile. -Currently the -.I \-fifo -option is used as default. (This may be changed at compile time.) +.B \-force_hole +obsoleted by \-force\-hole .TP -.B \-shm -Use System V shared memory for fifo. -Normally -.B star -is compiled to use mapped /dev/zero pages for the fifo, if the operating system -supports this. -If -.B star -is compiled to have both code for mapped pages and for System V shared memory, -.B star -will use shared memory instead of the default. -If the -.I \-help -menu doesn't show the -.I \-shm -flag you have no choice. -When using System V shared memory, you may have to raise the system's internal -limit for shared memory resourses to get enough shared memory for -.BR star . +.B \-force\-hole +Try to extract all files with holes. This even works with files that +are created without the +.B \-sparse +option. +.BR Star , +in this case examines +the content of the files in the archive and replaces writes to parts containing +binary zeroes with seeks. This option should be used with extreme care +because you sometimes get in trouble when files get unattended holes. +All options that start with the +.B \-f +sequence are sensitive to typo problems, see BUGS section for more information. .TP -.B \-v -Be verbose. -This normally results in more output during operation. -See also in the description for the -.I \-t -flag. -Normally, -.B star -does its work silently. +.B \-force_remove +obsoleted by \-force\-remove .TP -.B \-tpath -Use this option together with the -.I \-t -option to get only a list of the -pathnames of the files in the archive. -This may be used in shell scripts to generate a name list. -If used together with the -.I \-diff -option, +.B \-force\-remove +Force to remove non writable files on extraction. +By default, .B star -will only print the names of the files that differ. -A second run of -.B star -may then be used to restore all files that had differences to the archive. -Use the -.I list= -option to specify the namelist in this case. +will not overwrite files that are read only. +If this option is in effect, +.B star +will silently remove these files to allow the extraction of a file. +All options that start with the +.B \-f +sequence are sensitive to typo problems, see BUGS section for more information. .TP -.BR H= headertype +.BR fs= # +Set fifo size to #. +See +.I bs= +for the possible syntax. +The default size of the fifo is 1 Mbyte on Sun mc68000 systems, +4 Mbytes on non mmap() aware Linux systems and 8 Mbytes on all other systems. +See +.B \-fifo +option for hints on using the right fifo size. +.TP +.BI H= headertype Generate a tape archive in .I headertype format. @@ -414,20 +1107,39 @@ .B star to interpret the headers to be of type .I headertype. +As +.B star +even in case of a user selected extract archive format does format checking, +it may be that you will not be able to unpack a specific archive with all +possible forced archive formats. Selecting the old +.B tar +format for extraction will always work though. Valid parameter for .I headertype are: .RS .TP 10 .B help -Print a help message about possible headertypes. +Print a help message about possible header types. .TP 10 .B tar -Old UNIX tar format. +Old UNIX +.B tar +format. This archive format may only store plain files, directories and symbolic links. -Pathnames longer than 99 chars may not be archived. -See also the \-d option as a note to some implementations. +Pathnames or linknames longer than 99 chars may not be archived. +See also the +.B \-d +option as a note to some even older tar implementations. +.sp +If the +.B tar +format has been selected, +.B star +will not use enhancements to the historic tar format. +File size is limited to 2 GB - 2 bytes, uid/gid is limited to 262143. +Sparse files will be filled up with zeroes. .TP 10 .B star Old @@ -435,20 +1147,39 @@ standard format. This is an upward/downward compatible enhancement of the .I old -UNIX tar format. +(pre Posix) UNIX +.B tar +format. It has been introduced in 1985 and therefore is not Posix compliant. -.B Star +The +.B star format allows to archive special files (even sockets) and records access time and -creation time. Newer versions of the old +creation time besides the modification time. Newer versions of the old .B star -format allow very long filenames (\ >\ 100+155 chars) and sparse files. -This format is able to copy the non Posix compliant device nodes on HP-UX -that have 24 bits in the minor device number, which is more then the maximum -allowed which is 21 bits. +format allow very long filenames (100+155\ chars and above), linknames > 100 chars +and sparse files. +This format is able to copy the device nodes on HP\-UX +that have 24 bits in the minor device number, which is more then the 21 bits +that are possible with the POSIX\-1003.1\-1988 archive format. .TP 10 .B gnutar -This is a commonly used, not Posix compliant enhancement to the old tar +This is a commonly used, but unfortunately not Posix compliant +(although designed after 1987) +enhancement to the old +.B tar format. +Do not use the +.B gnutar +archive format unless you want to create an archive for a target system +that is known to have only the gnutar program available. +The +.B gnutar +archive format violates basic rules for any (even the historic) tar archive format. +Using the +.B gnutar +archive format causes a high risk that the resulting archive may only be read +by gnutar or by +.BR star . The implementation of the gnutar archive format within .B star is not complete, but @@ -456,312 +1187,512 @@ See NOTES for more information. .TP 10 .B ustar -IEEE/Posix1003/IEC-9945-1 Standard Data Interchange format. +IEEE/Posix1003/IEC\-9945\-1\-1988 Standard Data Interchange format. With this option in effect, .B star -will generate 100% ansi compliant -tar archives. -Files with pathnames longer than 100+155 chars may not be archived. +will generate 100% POSIX.1\-1988 compliant +.B tar +archives. +Files with pathnames longer than 100+155 chars or linknames longer than +100 chars may not be archived. If .B star is called as .B ustar the default archive format is .BR ustar . +.sp +If the +.B ustar +format has been selected, +.B star +will not use enhancements to the POSIX.1\-1988 tar format, the archive +will be strictly conforming. +File size is limited to 8 GB, uid/gid/major/minor is limited to 2097151. +Sparse files will be filled up with zeroes. +.TP 10 +.B pax +The IEEE/Posix1003/IEC\-9945\-1\-1988 successor, +the POSIX\-1003.1\-2001 Standard Data Interchange format. +.sp +If the +.B pax +format has been selected, +.B star +will not use enhancements to the POSIX.1\-2001 tar format, the archive +will be strictly conforming. +File size is unlimited, uid/gid/uname/gidname is unlimited, +major/minor is limited to 2097151. +Sparse files will be filled up with zeroes. .TP 10 .B xstar -Extended standard tar format. +Extended standard +.B tar +format. .B Star uses the .B xstar format as default archive format. This is an upward/downward compatible enhancement -of the IEEE/Posix1003/IEC-9945-1 Standard Data Interchange format. -It allows among others very long filenames (\ >\ 100+155 chars) +of the IEEE/Posix1003/IEC\-9945\-1 Standard Data Interchange format. +It allows among others very long filenames (100+130\ chars and above) and records access time and creation time. +The +.B xstar +format is the default format when +.B star +is neither called as +.B tar +nor called as +.BR ustar . .TP .B xustar -New (exerimental) format that omits the +New format introduced 1998, that omits the .I tar -signature at the end of the tar header. It is otherwise identical +signature at the end of the +.B tar +header. It is otherwise identical to the .B xstar format. -As some tar implementations do not follow the POSIX rules and compute -the checksum for less than 512 bytes of the tar header, this format may help -to avoid problems with these tar implementations. +As some +.B tar +implementations do not follow the POSIX rules and compute +the checksum for less than 512 bytes of the +.B tar +header, this format may help +to avoid problems with these +.B tar +implementations. +The main other difference to the +.B xstar +format is that the +.xustar +format uses POSIX.1\-2001 extended headers to overcome limitations of the +historic +.B tar +format while the +.B xstar +format uses proprietary extensions. +The +.B xustar +format is the default format when +.B star +is called as +.BR tar . +.sp +File size is unlimited, uid/gid/uname/gidname is unlimited, +major/minor is unlimited. +Sparse files will be archived correctly. +.TP +.B exustar +A format similar to the +.B xustar +format but with forced POSIX.1\-2001 extended headers. +If this format is used together with the +.B \-acl +option, +.B star +records Access Control Lists (ACLs) in POSIX.1\-2001 extended headers. +.sp +File size is unlimited, uid/gid/uname/gidname is unlimited, +major/minor is unlimited. +Sparse files will be archived correctly. +.TP +.B suntar +The extended header format found on Solaris 7/8. This format is similar to the +.B pax +format but does not handle +.I atime +and +.I ctime +and in addition uses 'X' as the typeflag for the extended headers instead of +the standard 'x'. +.sp +File size is unlimited, uid/gid/uname/gidname is unlimited, +major/minor is unlimited. +Sparse files will be filled up with zeroes. + .PP -All tar archive formats may be interchanged if the archive contains -no files that may not be archived by using the old tar format. +All +.B tar +archive formats may be interchanged if the archive contains +no files that may not be archived by using the old +.B tar +format. Archives in the .I xstar -format may be extracted by any 100% ansi compliant tar -implementation if they contain no files with pathnames >100+130 chars +format may be extracted by any 100% POSIX compliant +.B tar +implementation if they contain no files with pathnames >\ 100+130\ chars and if they contain no sparse files that have been archived by using -the \-sparse option. +the +.B \-sparse +option. .RE .TP -.BR C= dir -Perform a -.BR chdir (2) -operation to -.I dir -before storing next files. -In all cases, -.B star -will perform the -.BR chdir (2) -operation relative to the current working directory of the shell. -.RS -.TP -.B \(bu -In list mode (with the -.B \-t -flag), +.B \-h, \-L +Follow symbolic links as if they were files. +Normally .B star -ignores all -.I \-C -options. +will not follow symbolic links but stores their values in +.I tarfile. +See also the +.B \-L +option. .TP -.B \(bu -In create mode (with the -.BR \-c ", " \-r " and " \-u -flag), +.B \-hardlinks +In extract mode, this option tells .B star -walks through all -.I \-C -options and file type arguments. -While -.BR tar (1) -goes back to the current working directory after storing -one file argument that immediately follows the -.I \-C -option, +to try to create a hardlink whenever a symlink is encountered in the archive. +In create mode, this option tells .B star -changes the directory only if a new -.B \-C -option follows. -To emulate the behavior of -.BR tar (1), -add a -.BI \-C " ." -option after the file argument. +to try to archive a hardlink whenever a symlink is encountered in the +file system. .TP -.B \(bu -In extract mode (with the -.BR \-x ", " \-n " and " \-diff -flag), +.B \-hpdev +Allow 24 bits for the minor device number using 8 octal digits. +Note that although it allows to create +.B tar +archives +that can be read with HP\-UX tar, this creates +.B tar +archives +which violate POSIX.1\-1988. +This option is only needed if you like to use a POSIX.1\-1988 based archive +format that does not include extensions. +If you use the +.B xstar +format, .B star -builds a pattern list together with corresponding directories and -performs a -.BR chdir (2) -to the corresponding directory of a matching pattern. -All -.B pat= -options in this case are interpreted as if they were preceded by -a -.BI \-C " ." -option. -See EXAMPLES for more information. -.RE +will use a base 256 extension that allows bigger major/minor numbers by default, +if you use the +.B xustar +or the +.B exustar +format there is no limitation at all as these formats use POSIX.1\-2001 +extended headers to archive the major/minor numbers by default. .TP -.B \-z -run the input or output through a -.B gzip -pipe. -This is currently a quick and dirty hack, that mainly will cover -the most common usage to compress the tar output if it is a file. -No reblocking will be done, so this option will currently only make sense -on plain files. -The environment variable -.B STAR_COMPRESS_FLAG -may be used to specify one option for gzip. -If you want to write write compressed archives to tape, you should use -.br -.I "star -c . | gzip | sdd ibs=4k obs=32k -fill of=/dev/nrst0 -.br -or -.br -.I "star -c . | gzip | sdd ibs=4k obs=32k -fill ovsize=60m of=/nrst0 -.br -if the tape can hold 60 MB. +.B \-i +Ignore checksum errors on +.B tar +headers. +If this option is specified, +.B star +will not exit if a header with a bad checksum is found but search for the +next valid header. .TP -.B \-bz -run the input or output through a -.B bzip2 -pipe - see option -z above. +.B \-I +Obsolete option, otherwise identical to +.BR \-w . .TP -.B \-B -Force -.B star -to perform multiple reads (if necessary) to fill a block. -This option exists so that -.B star -can work across the Ethernet, since pipes and sockets return partial blocks -even when more data is coming. -If -.B star -uses -.I stdin -as archive file, +.B \-keep_old_files +obsoleted by \-keep\-old\-files +.TP +.BR \-keep\-old\-files ", " \-k +Keep existing files rather than restoring them from +.I tarfile. +This saves files from being clobbered even if +.I tarfile +contains a more recent version of the corresponding file. +.TP +.B \-L, \-h +Follow symbolic links as if they were files. +Normally .B star -behaves as if it has been called with the -.B \-B +will not follow symbolic links but stores their values in +.I tarfile. +See also the +.B \-h option. .TP -.B \-i -Ignore checksum errors on tar headers. -If this option is specified, +.B \-l +Do not print a warning message if not all links to hard linked files +could be dumped. This option is evaluated in the opposite way to historic +.BR tar (1) +implementations and to POSIX.1. +POSIX.1 requests that by default no warning messages will be printed +and +.B \-l +will enable warning messages when not all links could be archived. +.TP +.B \-link\-dirs +When in create mode, try to find hard linked directories. +Using +.B \-link\-dirs +will force .B star -will not exit if a header with a bad checksum is found but search for the -next valid header. +to keep track of all directories that will go into the archive and thus +causes a lot more memory to be allocated than in the default case. +.sp +Note that not all filesystem allow to create hard links to directories. +Also note that even though a non-root user is able detect and archive +hard linked directories, all known operating systems require the extraction +to be done as root in order to be able to create or remove hard links to directories. +For this reason its only recommended to use this option when doing accurate +backups and when hard links to directories are expected. +.sp +When the option +.B \-link\-dirs +is not used and hard links to directories are present, the appendant sub-tree +will appear more than once on the archive and +.B star +will print +.I "Linkcount below zero +warnings for non directory hard links inside the sub-tree. .TP -.B \-d -Do not store/create directories. -Old versions of -.B tar -such as published with the seventh edition of UNIX -are not able to deal with directories in tar archives. -If a tar archive is generated without directories this avoids -problems with tar implementations found on SYSVr3 and earlier. +.BR list= filename +Read filenames for store/create/list command from +.I filename. +The file +.I filename +must contain a list of filenames, each on a separate line. +This option implies the +.B \-D +option. +To force +.B star +to descend directories, use the +.B \-dodesc +option in this case. +.TP +.B \-M +Do not descend mount points. +This is useful when doing backups of complete filesystems. +See NOTES for more information. .TP .B \-m Do not restore access an modification time. (Access time is only available if .B star -is reading -.IR star " or " xstar -archives.) If +is reading +.BR star , +.BR xstar , +.BR xustar , +.BR exustar , +or +.B pax +archives). If +.B star +extracts other archive types, the +.B \-m +flag only refers to the modification time. + +.TP +.BR maxsize= # +Do not store files in +.I tarfile +if they are bigger than #. +See +.I bs= +for the possible syntax. +By default, the number is multiplied by +1024, so the value counts in units of kBytes. +If the size specifier ends with a valid multiplication character +(e.g '.' for bytes or 'M' for MB) the specified size is used as specified +and not multiplied by 1024. +See +.B bs= +option for all possible multipliers. +.TP +.B \-meta +This currently is an experimental option. In create mode, it causes +.B star +to archive all +.B meta +data of the file (e.g. uid, permissions, ...) bit not the +file content. In extract mode, it causes +.B star +to restore all +.B meta +data but not the file content. In addition, in extract mode +no plain file, special file or directory will be created. +.B Meta +files are needed in future .B star -extracts other archive types, the -.I \-m -flag only referres to the modification time. +versions that support incremental backups. +.sp +Warning: Do not try to extract +.B star +archives containing +.B meta +files using other tar implementations if they are not aware of the +.B meta +file extensions of +.BR star . +.B Star +tries to force all tar implementations that are not standard compliant to abort. +.B Star +also tries to make all non POSIX.1-2001 compliant tar implementations unable +to find a valid filename. However when other POSIX.1-2001 aware tar implementations +come up and don't know about +.B meta +files, they will destroy files on disk. +.sp +The problems result from the only current fallback in the POSIX standard that +tells tar implementations to treat all unknown file types as if they were +plain files. As +.B meta +files are needed for incremental backups, I am looking for people and companies +who like to support me to be able to add the +.B meta +file concept to the POSIX.1-2005 standard. .TP -.B \-nochown -Do not restore owner and group of files. -This may be used if super user privileges are needed to overwrite -existing files but the local ownership of the existing files should -not change. +.B \-modebits +This options allows you to create +.B tar +archives that include +more than 12 bits from st_mode. Note this create +.B tar +archives +that violate POSIX but some +.B tar +implementations insist in reading +such nonstandard archives. .TP -.BR \-atime ", " \-a -Reset access time of files after storing them to +.BR newer= filename +Do not store files to +.I tarfile +if their modification time is not newer than the modification time of +.I filename. +See +.B \-ctime +option for changing this behavior. +.TP +.B \-newest +In conjunction with the list command this lists you only the newest file in .I tarfile. -On Solaris 2.x, (if invoked by root) -.B star -uses the -.I _FIOSATIME -ioctl to do this. This enables -.B star -not to trash the -.I ctime -while resetting the -.I atime -of the files. -If the -.B \-atime -option is used in conjunction with the list command, -.B star -lists access time instead of modification time. (This works only in -conjunction with -.B star -and -.B xstar -format.) .TP -.B \-p -Restore filemodes of directories. Without this option directories are -created using the present -.BR umask (2). -If in create mode i.e. storing files to archive, -.B star -stores directories past the corresponding files. This guarantees that even old -tar implementations will be able to restore the correct times of -directories. +.B \-newest_file +obsoleted by \-newest\-file .TP -.B \-l -Do not print a warning message if not all links to hard linked files -could be dumped. This option is evaluated in the opposite way to -.BR tar (1). +.B \-newest\-file +In conjunction with the list command this lists you only the newest regular +file in +.I tarfile. .TP -.B \-L -Follow symbolic links as if they were files. -Normally -.B star -will not follow symbolic links but stores their values in +.BI new\-volume\-script= script +Call +.I script +at end of each tape if in multi volume mode. +If this option is not in effect, +.B star +will ask the user to confirm the volume change. +.TP +.B \-nodump +If this option is set, +.B star +will not dump files that have the +.B nodump +flag set. Note that this currently only works on BSD\-4.4 derivates +and on Linux. +On Linux, using this option will cause a performance degradation +(the system time increases by 10%) because of the unlucky kernel interface. +.TP +.B \-no_fifo +obsoleted by \-no\-fifo +.TP +.B \-no\-fifo +Don't use a +.I fifo +to optimize data flow from/to .I tarfile. +Currently the +.I \-fifo +option is used as default. (This may be changed at compile time.) .TP -.B \-D -Do not descend directories. -Normally, -.B star -descends the whole tree if it encounters a directory in -in its file parameters. -This option is in effect if the -.BI list= file -option is used. +.BR \-nochown ", " \-o +Do not restore owner and group of files. +This may be used if super user privileges are needed to overwrite +existing files but the local ownership of the existing files should +not change. .TP -.B \-dodesc -Force +.B \-no_statistics +obsoleted by \-no\-statistics +.TP +.B \-no\-statistics +Do not print statistic messages at the end of a .B star -to descend directories found in a -.BI list= file. +run. .TP -.B \-M -Do not descend mount points. -This is useful when doing backups of complete filesystems. -See NOTES for more information. +.BR \-not ", " \-V +Invert the meaning of the pattern list. i.e. use those files which do not match +any of the pattern. +Note that this option only applies to patterns that have been specified +via the +.BR pattern= "pattern or " pat= pattern +option. Patterns specified as file type arguments will not be affected. .TP -.B \-I -Obsolete option, otherwise identical to -.BR \-I . +.B \-nowarn +Do not print warning messages. +This sometimes is useful to make the output more readable +(e.g. when hundreds of files that are going to be extracted are not newer +in the archive then on the filesystem). .TP -.B \-w -Do interactive creation, extraction or renaming. -For every file that matches the list of patterns and that has a more -recent modification time in the tar archive (if in extract mode and -the \-U option is not specified) -.B star -prints its name and asks: -.RS -.IP -.B -get/put ? Y(es)/N(o)/C(hange name) : -.PP -You may answer either `N' for No or to skip this file. -If you answer `Y' the file is extracted or archived on tape with its -original name. -If you answer `C', you are prompted for a new name. This name is used -for the filename on disk if -.B star -is in extract mode or for the archive name if -.B star -is in create mode. -.RE +.B \-numeric +Use the numeric user/group fields in the listing rather than the +default. +The default allows to list the ASCII version of user/group of the file +and to extract the owners of the files based on numeric values rather +than the names. +In create mode, no user/groups names are put on the archive. +The +.B \-numeric +option also applies when ACLs are going to be archived or extracted. .TP .B \-O -Be compatible to old versions of tar. +Be compatible to old versions of +.BR tar . If .B star is invoked with this option, .B star generates archives which are -fully compatible with old UNIX tar archives. If in extract mode, +fully compatible with old UNIX +.B tar +archives. If in extract mode, .B star ignores any additional info in the headers. This implies neither that archives generated with this option are -binary equal with archives generated by old tar versions nor that +binary equal with archives generated by old +.B tar +versions nor that .B star -is trying to comprehend all bugs that are found in old tar +is trying to comprehend all bugs that are found in old +.B tar versions. -The bug in old tar versions that cause a reversal of a space and a NULL byte +The bug in old +.B tar +versions that cause a reversal of a space and a NULL byte in the checksum field is not repeated. If you want to have signed checksums you have to specify the -.I \-singed-checksum +.I \-singed\-checksum +option too. +If you want directories not to be archived in order to be compatible +to very old historic tar archives, you need to specify the +.I \-d option too. +.sp This option is superseeded by the .BR H= headertype option. .TP +.BR \-o ", " \-nochown +Do not restore owner and group of files. +This may be used if super user privileges are needed to overwrite +existing files but the local ownership of the existing files should +not change. +.TP +.BR \-onull ", " \-nullout +Do not actually write to the archive but compute and add the sizes. +This is useful when trying to figure out if a tape may hold +the current backup. +Please only use the +.B \-onull +option as it is a similar option as used by the +.BR sdd (1) +command. +.TP .B \-P Allow .B star @@ -771,402 +1702,336 @@ writes each record with the same size. This option is useful on unblocked tapes i.e. cartridge tapes like QIC tapes as well as with archives that are located in files. +If you use this option on local files, the size of the archive will be smaller. +If you use this option on cartridge tapes, is makes sure that later - in extract mode - +.B star +will read up to the end of file marker on the tape and the next call to +.B star +will read from the next archive on the same tape. .TP -.B \-S -Do not store/create special files. -You need to be super user to extract special files. -.TP -.B \-U -Restore files unconditionally. -By default, an older file will not replace a corresponding newer file on -disk. -.TP -.BR diffopts= optlst -Comma separated list of diffopts. -Valid members in -.I optlst -are: -.RS -.TP 10 -.B help -Print a summary of possible members of the diffopts list. -.TP 10 -.B not -Invert the meaning of all members in the diffopts list i.e. exclude -all present options from the compare list. -.TP 10 -.B perm -Compare file permissions. With this option in effect, -.B star -compares the low order 12 bits of the st_mode field. -.TP 10 -.B mode -Same as -.I perm. -.TP 10 -.B type -Compare file type. -.TP 10 -.B nlink -Compare link count on hardlinks (currently not supported). -.TP 10 -.B uid -Compare numerical user id of file. -.TP 10 -.B gid -Compare numerical group id of file. -.TP 10 -.B uname -Compare ASCII version of user id of file. -.TP 10 -.B gname -Compare ASCII version of group id of file. -.TP 10 -.B id -Compare all user/group related info of file. -.TP 10 -.B size -Compare file size. -.TP 10 -.B data -Compare content of file. -.TP 10 -.B cont -Same as -.I data. -.TP -.B rdev -Compare major/minor numbers for device nodes. -.TP 10 -.B hardlink -Compare target of hardlinks. -.TP 10 -.B symlink -Compare target of symlinks. This evaluates the value returned by the -readlink(2) call. -.TP 10 -.B atime -Compare access time of file. -This only works with tar archives in -.I star -and -.I xstar -format. -.TP 10 -.B mtime -Compare modification time of file. -.TP 10 -.B ctime -Compare creation time of file. -This only works with tar archives in -.I star -and -.I xstar -format. -.TP 10 -.B times -Shorthand for: -.IR "atime,mtime,ctime" . -.PP -If -.I optlst -starts with a ! the meaning of all members in -.I optlst -is inverted as with the -.I not -optlist member. -.PP -If -.I diffopts -are not specified, +.B \-p +Restore filemodes of directories. Without this option directories are +created using the present +.BR umask (2). +If in create mode (i.e. when storing files to archive), .B star -compares everything but the access time of the files. -.RE +stores directories past the corresponding files. This guarantees that even old +.B tar +implementations will be able to restore the correct times of +directories. +If the archive contains Access Control Lists (ACLs) in +POSIX.1\-2001 extended headers, +.B star +will restore the access control lists from the archive for files +if the \-acl option is specified. +If the option \-acl has not been specified, ACLs are not restored at all. .TP .BR pattern= "pattern, " pat= pattern Set matching pattern to .I pattern. A maximum of 100 pattern=pat options may be specified. +As each pattern is unlimited in length, this is no real limitation. If more than one pattern is specified, a file matches if any of the specified pattern matches. Patterns may be used in create mode to select or exclude files from the list of file type arguments or the files located in a sub tree of a file type argument directory. In extract or list mode, all file type arguments are interpreted to be -select or exclude patterns. -Note that the method to restore subtrees used by -.BR tar (1) -does not work -with -.BR star . +select pattern and all option type patterns may be either select or exclude patterns +depending on the presence or absence of the +.B \-not +option. +If you use file type select patterns, they work exactly like the method +used by other (non pattern aware) +.BR tar (1) +implementations. +File type select patterns do not offer pattern matching but allow to restore subtrees. To extract a complete sub tree from the directory .I dir with .B star -use +using the +.B pattern= +option, use +.B pattern= .I "dir/\\\\* -instead of simply +if you like to select a subtree by using the historic method, use .I "dir/ -(see manual page for match(1) for more details of the pattern matcher). +as file type argument. +See manual page for +.BR match (1) +for more details of the pattern matcher. All patterns are selection patterns by default. To make them exclude patterns, use the -.B -V -option. -.TP -.BR \-not ", " \-V -Invert the meaning of the pattern list. i.e. use those files which do not match -any of the pattern. -.TP -.BR \-F , \-FF " ..." -Fast and simple exclude option for create mode. -With one -.B \-F -argument, -.B star -ignores all directories called -.IR SCCS " and " RCS. -With two -.B \-F -arguments, -.B star -in addition ignores all files called -.I core errs a.out -all files ending with -.I .o -and all directories -.IR OBJ/ . -With three -.B \-F -arguments, -.B star -in addition ignores all sub trees starting from a directory that -includes a file -.I .mirror -or -.I .exclude -.TP -.BR list= filename -Read filenames for store/create/list command from -.I filename. -The file -.I filename -must contain a list of filenames, each on a separate line. -This option implies the -.B \-D +.B \-not +or the +.B \-V option. -To force -.B star -to descend directories, use the -.B \-dodesc -option in this case. .TP -.BR VOLHDR= name -Use -.I name -to generate a volume header. +.B \-qic24 +Set tape volume size to 61440 kBytes. +See +.BI tsize= # +option for more information. .TP -.B \-xdir -Extract directories even if the corresponding directories on the -archive are not newer. -This is useful when for some reason, the directories are recorded -after their content, or when the permissions of some directories -must be set in any case. +.B \-qic120 +Set tape volume size to 128000 kBytes. +See +.BI tsize= # +option for more information. .TP -.B \-keep_old_files -obsoleted +.B \-qic150 +Set tape volume size to 153600 kBytes. +See +.BI tsize= # +option for more information. .TP -.BR \-keep-old-files ", " \-k -Keep existing files rather than restoring them from -.I tarfile. -This saves files from being clobbered even if -.I tarfile -contains a more recent version of the corresponding file. +.B \-qic250 +Set tape volume size to 256000 kBytes. +See +.BI tsize= # +option for more information. .TP .B \-refresh_old_files -obsoleted +obsoleted by \-refresh\-old\-files .TP -.B \-refresh-old-files +.B \-refresh\-old\-files .TP .B \-refresh Do not create new files. Only already existing files may be overwritten from .I tarfile if either newer versions are present in the archive or if the .B \-U -flag ise used. +flag is used. This allows to overwrite files by more recent files from an archive that contains more files than the target directory should contain. +The option +.B \-refresh\-old\-files +is the same as the +.B \-refresh +option. .TP -.B \-/ -Don't strip leading slashes from file names. -Tar archives containing absolute pathnames are usually a bad idea. -With other -.B tar -implementations, -they may possibly never extracted without clobbering existing files. -.B Star -for that reason, by default strips leading slashes from filenames. +.B \-remove_first +obsoleted by \-remove\-first .TP -.BR maxsize= # -Do not store files in -.I tarfile -if they are bigger than # kBytes. +.B \-remove\-first +Remove files before extraction. +If this option is in effect, +.B star +will remove files before extracting a file from the archive. +This is needed if you want to change the file type or if you need +to break a hard link. +If you do not use either +.B \-ask\-remove +or +.B \-force\-remove +together with +.BR \-remove\-first , +this option is useless and no files will be removed. .TP -.BR newer= filename -Do not store files to -.I tarfile -if their modification time is not newer than the modification time of -.I filename. -See -.B \-ctime -option for changing this behavior. +.B \-remove_recursive +obsoleted by \-remove\-recursive .TP -.B \-ctime -If used with the list command, this lists -.I ctime -rather than -.I mtime. -If used with the extract command, this tries to restore even the -.I ctime -of a file by generating time storms. -You should not do this when in multi user mode because this may -confuse programs like cron and the news system. -If used with the create command this changes the result of the -.I newer= -option. -.BR Star , -in this case compares the -.I ctime -of all files to the -.I mtime -of the stamp file rather then comparing the -.I mtimes -of both files. +.B \-remove\-recursive +Remove files recursive. +If removing of a file is permitted, +.B star +will only remove files, specials and empty directories. +If this option is in effect, +.B star +will be allowed to recursively removes non empty directories too. .TP -.BR bs= # -Set output block size to #. -You may use the same method as in -.BR dd (1) -and -.BR sdd (1). -The number representing the size is taken in bytes unless otherwise specified. -If a number is followed directly by the letter `b', `k' or `m', -the size is multiplied by 512, 1024 or 1024*1024. -If the size consists of numbers separated by `x' or `*', multiplication of the -two numbers is performed. -Thus -.I "bs=7x8k -will specify a blocksize of 56\ kBytes. -Blocksize must be a multiple of 512 bytes. -See also the description of the obsolete -.I blocks= -option for more details on blocksizes. +.B \-S +Do not store/create special files. +A special files is any file except plain files, symbolic links and directories. +You need to be super user to extract special files. .TP -.BR fs= # -Set fifo size to #. -See -.I bs= -for possible syntax. -The default size of the fifo is 1 Mbyte. -See -.B \-fifo -option for hints on using the right fifo size. +.B \-shm +Use System V shared memory for fifo. +Normally +.B star +is compiled to use mapped /dev/zero pages for the fifo, if the operating system +supports this. +If +.B star +is compiled to have both code for mapped pages and for System V shared memory, +.B star +will use shared memory instead of the default. +If the +.I \-help +menu doesn't show the +.I \-shm +flag you have no choice. +When using System V shared memory, you may have to raise the system's internal +limit for shared memory resources to get enough shared memory for +.BR star . .TP -.BR tsize= # -Set tape volume size to # 512 byte blocks. With this option in effect, -.B star -is able to archive filesystems that are bigger then the tape size. -Files that do not fit on a single tape may not be stored with the -current version of -.BR star . +.B \-signed_checksum +obsoleted by \-signed\-checksum .TP -.B \-qic24 -Set tape volume size to 61440 kBytes. +.B \-signed\-checksum +Use signed chars to calculate checksums. This violates the +.B tar +specs but old +versions of +.B tar +derived from the seventh edition of UNIX are implemented in this way. +Note: Only filenames and linknames containing chars with the most +significant bit set may trigger this problem because all +other fields only contain 7 bit ASCII characters, octal digits or binary +zeroes. .TP -.B \-qic120 -Set tape volume size to 128000 kBytes. +.B \-silent +Suppress informational messages like +.IR "foobar is sparse" . .TP -.B \-qic150 -Set tape volume size to 153600 kBytes. +.B \-sparse +Handle files with holes effectively on store/create. +Note that sparse files may not be archived this way if the archive format is +.BR tar , +.BR ustar , +.BR pax , +or +.BR suntar . +On Solaris-2.3 ... Solaris-2.5.1 there is a special ioctl() called +.I _FIOAI +that allows root to get the allocation info more efficiently. +Other operating systems lack support to get the real allocation list +and force +.B star +to scan the files to look for blocks that only contain null characters. +This may +.B star +to assume more holes to be present than the number that the file really contains. .TP -.B \-qic250 -Set tape volume size to 256000 kBytes. +.B \-symlinks +This option tells +.B star +in extract mode to try to create a symlink whenever a hardlink is encountered +in the archive. .TP -.B \-nowarn -Do not print warning messages. -This sometimes is useful to make the output more readable. +.B \-T +If the option +.B file= +or +.B f= +is omitted and the \-T option is present, +.B star +will use the device indicated by the +.SB TAPE +environment variable, +if set. .TP .B \-time Print timing info. See DIAGNOSTICS for more information. .TP -.B \-no_statistics -obsoleted -.TP -.B \-no-statistics -Do not print statistic messages at the end of a -.B star -run. -.TP -.B \-fifostats -Print fifo statistics at the end. -.TP -.B \-numeric -Use the numeric user/group fields in the listing rather than the -default. -The default is to list the ASCII version of user/group of the file. -.TP -.B \-newest -In conjunction with the list command this lists you only the newest file in -.I tarfile. +.B \-to_stdout +obsoleted by \-to\-stdout .TP -.B \-newest_file -obsoleted +.B \-to\-stdout +Extract files to stdout. This option may be used to extract +.I tarfiles +containing +.I tarfiles +(see examples below). .TP -.B \-newest-file -In conjunction with the list command this lists you only the newest regular -file in -.I tarfile. +.B \-tpath +Use this option together with the +.I \-t +option to get only a list of the +pathnames of the files in the archive. +This may be used in shell scripts to generate a name list. +If used together with the +.I \-diff +option, +.B star +will only print the names of the files that differ. +A second run of +.B star +may then be used to restore all files that had differences to the archive. +Use the +.I list= +option to specify the namelist in this case. .TP -.B \-signed_checksum -obsoleted +.BR tsize= # +Set tape volume size to # to enable multi volume tape support. +See +.I bs= +for the possible syntax. +By default, the number is multiplied by +512, so the value counts in units of 512 byte blocks. +If the size specifier ends with a valid multiplication character +(e.g '.' for bytes or 'M' for MB) the specified size is used as specified +and not multiplied by 512. +With this option in effect, +.B star +is able to archive filesystems that are bigger then the tape size. +Files that do not fit on a single tape may not be stored with the +current version of +.BR star . .TP -.B \-signed-checksum -Use signed chars to calculate checksums. This violates the tar specs but old -versions of -.B tar -derived from the seventh edition of UNIX are implemented in this way. -Note: Only filenames and linknames containing chars with the most -significant bit set may trigger this problem because all -other fields only contain 7 bit ASCII characters, octal digits or binary -zeroes. +.B \-U +Restore files unconditionally. +By default, an older file from the archive will not replace a corresponding newer file on +disk. .TP -.B \-sparse -Handle files with holes effectively on store/create. -On Solaris 2.x there may be a special ioctl() called -.I _FIOAI -that allows root to get the allocation info more efficiently. +.B \-v +Increment verbose level by one. +This normally results in more output during operation. +See also in the description for the +.I \-t +flag. +Normally, +.B star +does its work silently. +If the verbose level is 2 or more and +.B star +is in create or update mode, +.B star +will produce a listing to the format of the ls \-l output. .TP -.B \-force_hole -obsoleted +.BR \-V ", " \-not +Invert the meaning of the pattern list. i.e. use those files which do not match +any of the pattern. +Note that this option only applies to patterns that have been specified +via the +.BR pattern= "pattern or " pat= pattern +option. Patterns specified as file type arguments will not be affected. .TP -.B \-force-hole -Try to extract all files with holes. This even works with files that -are created without the -.B \-sparse -option. -.BR Star , -in this case examines -the content of the files in the archive and replaces writes to parts containing -binary zeroes with seeks. This option should be used with extreme care -because you sometimes get in trouble when files get unattended holes. +.B \-version +Print version information and exit. .TP -.B \-to_stdout -obsoleted +.BR VOLHDR= name +Use +.I name +to generate a volume header. .TP -.B \-to-stdout -Extract files to stdout. This option may be used to extract tarfiles -containing tarfiles (see examples below). +.B \-w +Do interactive creation, extraction or renaming. +For every file that matches the list of patterns and that has a more +recent modification time in the +.B tar +archive (if in extract mode and +the \-U option is not specified) +.B star +prints its name and asks: +.RS +.IP +.B +get/put ? Y(es)/N(o)/C(hange name) : +.PP +You may answer either `N' for No or to skip this file. +If you answer `Y' the file is extracted or archived on tape with its +original name. +If you answer `C', you are prompted for a new name. This name is used +for the filename on disk if +.B star +is in extract mode or for the archive name if +.B star +is in create mode. +.RE .TP .B \-wready This option is added as a hack for a bug in the SunOS/Solaris @@ -1177,77 +2042,57 @@ waits up to one minute for the drive to become ready if this option is specified. .TP -.B \-force_remove -obsoleted -.TP -.B \-force-remove -Force to remove non writable files on extraction. -By default, -.B star -will not overwrite files that are read only. -If this option is in effect, -.B star -will silently remove these files to allow the extraction of a file. -.TP -.B \-ask_remove -obsoleted -.TP -.B \-ask-remove -Ask to remove non writable files on extraction. -By default, -.B star -will not overwrite files that are read only. -If this option is in effect, -.B star -will ask whether it should remove these files to allow the extraction of a file -in the following way: -.RS -.IP -.BI "remove '" filename "' ? Y(es)/N(o) : -.RE +.B \-xdir +Extract directories even if the corresponding directories on the +archive are not newer. +This is useful when for some reason, the directories are recorded +after their content (see +.B \-dirmode +option), or when the permissions of some directories +must be set in any case. .TP -.B \-remove_first -obsoleted +.B \-xfflags +Store and extract extended file flags as found on BSD and Linux systems. +This option only makes sense when creating or extracting +.B exustar +archives as it is based on POSIX.1\-2001 extended tar headers. .TP -.B \-remove-first -Remove files before extraction. -If this option is in effect, +.B \-z +run the input or output through a +.B gzip +pipe. +This is currently a quick and dirty hack, that mainly will cover +the most common usage to compress the +.B tar +output if it is a file. +No reblocking will be done, so this option will currently only make sense +on plain files. +The environment variable +As both the +.B \-bz +and the +.B \-z +option are non standard, it makes sense to omit the +.B \-bz +and the +.B \-z +inside shell scripts if you are going to extract a compressed +archive that is located inside a plain file as .B star -will remove files before extracting a file from the archive. -This is needed if you want to change the file type or if you need -to break a hard link. -If you do not use either -.B \-ask-remove +will auto detect compression and choose the right decompression +option to extract. +.B STAR_COMPRESS_FLAG +may be used to specify one option for gzip. +If you want to write write compressed archives to tape, you should use +.br +.I "star \-c . | gzip | sdd ibs=4k obs=32k \-fill of=/dev/rmt/1bn +.br or -.B \-force-remove -together with -.BR \-remove-first , -this option is useless and no files will be removed. -.TP -.B \-remove_recursive -obsoleted -.TP -.B \-remove-recursive -Remove files recursive. -If removing of a file is permitted, -.B star -will only remove files, specials and empty directories. -If this option is in effect, -.B star -will be allowed to recursively removes non empty directories too. -.TP -.BR \-onull ", " \-nullout -Do not actually write to the archive but compute and add the sizes. -This is useful when trying to figure out if a tape may hold -the current backup. -.TP -.B \-debug -Print debug messages. Among other things, this gives debug messages for -headertype recognition, tar type properties, EOF recognition, opening -of remote archives and fifo internals. -.TP -.B \-version -Print version information and exit. +.br +.I "star \-c . | gzip | sdd ibs=4k obs=32k \-fill ovsize=60m of=/dev/rmt/1bn +.br +if the tape can hold 60 MB. + .SH SIGNALS .PP If @@ -1276,49 +2121,66 @@ .B star prints statistics and continues with the current operation. This is useful to watch the progress of the current operation. + .SH EXAMPLES .PP To get a listing in a way similar to ls \-l one might use: .IP .B -example% star \-tv f=/dev/nrst1 +example% star \-tv f=/dev/rmt/1bn +.PP +The same command as listed above in a +.B "POSIX tar +command line syntax compliant way is: +.IP +.B +example% star tvf /dev/rmt/1mbn .PP To copy the directory tree in -.I /home/jes +.I /home/someuser to the directory .I /home/fs use: .IP .nf .B -example% (cd /home/jes; star \-c .) | (cd /home/fs ; star \-xp) +example% (cd /home/someuser; star \-c .) | (cd /home/fs ; star \-xp) .fi .PP -or by using the change directory options of +or by using the change directory option of .BR star : .IP .B .nf -example% star \-c -C /home/jes . | star \-xp -C /home/fs +example% star \-c \-C /home/someuser . | star \-xp \-C /home/fs +.fi +.PP +To copy a file tree including the +.B "Access Control List +entries for all files use: +.IP +.B +.nf +example% star \-c \-Hexustar \-acl \-C /home/someuser . | star \-xp \-acl \-C /home/fs .fi .PP To compare the content of a tape to the filesystem one might use: .IP .B -example% star \-diff \-v f=/dev/nrst1 +example% star \-diff \-v f=/dev/rmt/1bn .PP To compare two directory trees one might use: .IP .B .nf -example% star \-c . | (cd todir ; star \-diff \-v diffopts=!times) +example% star \-c . | star \-C todir \-diff \-v diffopts=!times .fi .PP To extract a backup of the /usr tree without all files residing below /usr/openwin one might use: .IP .B -example% star \-xp \-V pat=openwin/\\* f=/dev/nrst1 +example% star \-xp \-V pat=openwin/\\* f=/dev/rmt/1bn .PP To extract all .I .c @@ -1332,14 +2194,20 @@ .IP .B .nf -example% star \-xp -C src '*.c' -C obj '*.o' -C /tmp '*' f=/dev/nrst1 +example% star \-xp \-C src '*.c' \-C obj '*.o' \-C /tmp '*' f=/dev/rmt/1bn .fi .PP -To extract a zipped tar file that is located on a read only filesystem -e.g. a CD in /tmp while having the shell's working directory on the CD one might use: +To extract files from a zipped +.B tar +archive that is located on a read only filesystem +e.g. a CD while having the shell's working directory on the CD one might use: .IP .B -example% star \-zxp \-C /tmp f=star-1.1.tar.gz +example% star \-zxp \-C /tmp f=star\-1.1.tar.gz +.PP +to extract the files from the +.B tar +archive to the /tmp directory. .PP To backup a list of files generated by the .BR find (1) @@ -1347,18 +2215,30 @@ .IP .B .nf -example% find . \fIfind_options\fP \-print | star \-c list=\- f=/dev/nrst1 +example% find . \fIfind_options\fP \-print | star \-c list=\- f=/dev/rmt/1bn .fi .PP -To extract tarfiles that contain tarfiles one might use: +Note that this does not work if the file names from output of the +.B find +command include new line characters. +.PP +To extract a +.I tarfile +that contains a +.I tarfile +one might use: .IP .B .nf -example% star \-x \-to-stdout f=/dev/nrst1 pat=\fIpat\fP | star \-xp +example% star \-x \-to\-stdout f=/dev/rmt/1bn pat=\fIpat\fP | star \-xp .fi .PP .I Pat, -in this case should match the tarfile in the tarfile on tape that +in this case should match the +.I tarfile +in the +.I tarfile +on tape that should be extracted. .PP To make a backup of the root filesystem to a tape drive connected to a @@ -1369,16 +2249,18 @@ .br .B .nf -example# star \-cM bs=63k f=tape@remotehost:/dev/nrst1 . +example# star \-cM fs=128m bs=63k f=tape@remotehost:/dev/rmt/1bn . .fi .PP You need a line in /etc/passwd like the following to enable this: .IP .B -tape:NP:60001:60001:Tape:/etc/tapehome:/etc/rmt +tape:NP:60001:60001:Tape:/etc/tapehome:/opt/schily/sbin/rmt .PP And a .rhosts file in /etc/tapehome to allow remote connections from the appropriate hosts. +Make sure that the file /etc/default/rmt exists and allows remote access +to the requested tape drive. .PP To repair a corrupted filesystem for which no recent backup exists, do the following: @@ -1393,13 +2275,13 @@ example# cd /filesys .br .B -example# star \-xpk f=/dev/nrst1 +example# star \-xpk f=/dev/rmt/1bn .br .B -example# mt \-f /dev/nrst1 rewind +example# mt \-f /dev/rmt/1bn rewind .br .B -example# star \-diff \-v diffopts=!times f=/dev/nrst1 +example# star \-diff \-v diffopts=!times f=/dev/rmt/1bn .PP Now check the differences and decide whether to restore additional files. This may be done by generating a list containing the needed @@ -1410,16 +2292,51 @@ differences you may use: .IP .B -example# star \-diff \-tpath diffopts=!times f=/dev/nrst1 +example# star \-diff \-tpath diffopts=!times f=/dev/rmt/1bn .PP If you are looking for files that changed the type or the access permission because this is a common case on still corrupted files, use: .IP .B -example# star \-diff \-tpath diffopts=type,perm f=/dev/nrst1 +example# star \-diff \-tpath diffopts=type,perm f=/dev/rmt/1bn +.SH ENVIRONMENT +.TP +.B STAR_COMPRESS_FLAG +If you like +.B star +to always create compressed files that use maximum compression, you may set +the environment variable +.B STAR_COMPRESS_FLAG +to \-9. +.TP +.B STAR_FIFO_SIZE +If you like to by default let +.B star +use a different fifo size, set this environment variable to the desired size. +.TP +.B TAPE +Unlike other +.BR tar (1) +implementations, +.B star +defaults to use stdin/stdout for the archive. +If you like +.B star +to use the file name from the +.B TAPE +environment instead, you need to specify the +.B \-T +option too. .SH FILES -None. +Currently none except the files implied be the command line from +.BR star . +.PP +In future, +.B star +may use +.B /etc/default/star +to set up global defaults. .SH "SEE ALSO" .BR tar (1), .BR cpio (1), @@ -1430,7 +2347,8 @@ .BR dd (1), .BR sdd (1), .BR star (4/5), -.BR rcmd (3) +.BR rcmd (3), +.BR fssnap (1m) .SH DIAGNOSTICS star: f records + p bytes (total of x bytes = d.nnk). .PP @@ -1440,14 +2358,53 @@ star: Total time x.yyysec (z kBytes/sec) .PP The time used and the transfer speed from/to the archive. +.PP +If there have been non fatal errors during the archive processing, +.B star +will display a delayed error summary before exiting. + .SH NOTES .PP +The POSIX command line syntax for the tar command deviates from the +command line syntax defined for all other commands. While the +.B "POSIX command line syntax +requests +all options to start with a dash (\-) and allows to either write options separately +or combined (in case of boolean flags), the +.B POSIX tar +command line syntax +requires all options to be combined into a single string that does not start with +a dash. +.B Star +by default assumes a command line syntax like a typical POSIX command and includes +a compatibility mode that allows to specify a command line syntax as documented +for the +.B POSIX tar +command. +If you believe that you found a bug in the way +.B star +parses the command line, please first check your command line for correctness before +you make a bug report for +.BR star . +.PP +If you like to write portable shell scripts that call tar, use the +.B POSIX tar +command line syntax (i.e. a single option string and no dash), choose the +commands and options from the following set of characters ( +.I "rxtuc vxfblmo" +) and check the shell script with both, your local tar and +.B star +for correct behavior. It you expect the script to call gnutar, do not include +the +.B \-o +option as gnutar implements this option in a way that violates POSIX. +.PP .B Star strips leading ./ sequences from pathnames. This lets .B star in many cases store longer pathnames than other implementations. .PP -The ansi method (ustar format) of storing files with pathnames that are +The POSIX.1\-1988 method (ustar format) of storing files with pathnames that are longer than 100 chars has some limitations: .IP The name field (100 chars) an inserted slash (`/') @@ -1460,75 +2417,146 @@ Linknames longer than 100 chars may not be archived too. .PP The -.I star, -.I xstar +.IR star , +.IR xstar , +.IR xustar , +.IR exustar , +.IR pax , and .I gnutar archive formats don't have these limitations. While gnutar uses a -method that makes it impossible for other tar implementations (except +method that makes it impossible for other +.B tar +implementations (except .BR star ) to restore filenames that are longer than 100 chars, the -.I xstar -archive format uses a method that allows an ansi compliant way of -storing filenames, if the ansi method would allow this. +.IR xstar , +.IR xustar , +.IR exustar +and +.I pax +archive format uses a method that allows an POSIX.1\-1988 compliant way of +storing filenames, if the POSIX method would allow this. +When the archive format is +.IR xustar , +.IR exustar +or +.I pax +very long filenames are stored using extended headers from the POSIX.1\-2001 standard. .PP -Some buggy tar implementations will generate incorrect filenames -during a restore operation if the archive contains pathnames of +Some buggy +.B tar +implementations will generate incorrect filenames +during a restore operation if the archive contains pathnames or linknames of exactly 100 chars length. .PP .B Star adds a .I tar -signature in the last four bytes of each tar header. This is no problem +signature in the last four bytes of each +.B tar +header if the archive format is +.I star +or +.IR xstar . +This is no problem with the .B star -archive format. +archive format as it is an extension of the old pre POSIX.1\-1988 tar format. On the other side, the .B xstar -archive format claims to be as Posix compliant as possible. +archive format claims to be as POSIX.1\-1988 compliant as possible. Inserting this .I tar signature is a minor deviation from the standard that has the last 12 bytes -of each header reserved for future use. On the other side, tar implementations -such as +of each header reserved for future use. On the other side, +.B tar +implementations +such as some .B pax -that only compute checksums on the first 500 bytes of the header -are violating the standard. All tar implementations that are 100% Posix +implementations that only compute checksums on the first 500 bytes of the header +are violating the standard that requests the checksum to be computed on all +512 bytes of the tar header. All +.B tar +implementations that are 100% Posix compliant will be able to extract .B xstar archives as long as no new standard is defined that claims the last 12 bytes of the header for a different use. -But then the version number should be changed from `00' +But then the +.B "ustar version +number should be changed from `00' to `01'. +Now, that the POSIX\-2001 standard has been accepted, it is even predictable +that all extensions to the standard +.B tar +format will go into the POSIX.1\-2001 extended headers +which are extensible to include any feature without future limitation. +The only known +.B tar +implementation that also uses the last 12 bytes of the +.B tar +header is Sun's +.B tar +which uses these 12 bytes for files that are split over +several archives. Such archives created by Sun's tar are not +readable by the buggy +.B pax +implementation too. The Sun extension is not incompatible to the +.B star +signature because Sun expects an octal number at the beginning of the +12 byte field which is a null character in the +.B star +case. .PP .B Star uses these four bytes since 1985 without problems. -If for some reason a new standard will use the reserved bytes, -it will be easy to change the -.B xstar -format so that it will be 100% Posix compliant. -The probability of falsely detecting other tar formats as -.B xstar -format however will be higher in this case. +If you need a 100% POSIX.1\-1988 and 100% POSIX.1\-2001 compliant tar archive, +you may use the +.IR xustar , +.IR exustar +or the +.I pax +archive format. +The probability of falsely detecting other +.B tar +formats as +.B xustar +or +.B exustar +format however is higher. .PP There is no way to ask for the -.IR n -th +.IR n \-th occurrence of a file. .PP -The way EOF is handled differs, whether the fifo is in effect or not. +The way EOF is handled by +.B star +differs, whether the fifo is in effect or not. If the fifo is not used, .B star stops reading the archive if it encounters a logical EOF record in the archive. If the fifo is used, .B star -reads until the real EOF mark on tape is reached. +may read until the fifo is full or until the real EOF mark on tape is reached. +How much data +.B star actually reads depends on the time when the +.B star +foreground process sends a fifo shutdown signal to the background fifo read +process. .PP -Gnu tar often creates tar archives with incorrect logical EOF marks. +Gnu tar often creates +.B tar +archives with incorrect logical EOF marks. The standard requires two blocks that are completely zeroed, whereas gnutar often only adds one of them. .PP -Old versions of tar found on SYSVr3 and eralier cannot read tar archives +Old versions of +.B tar +found on SYSVr3 and earlier cannot read +.B tar +archives with a blocksize greater than 10\ kBytes. .PP The method of storing @@ -1541,28 +2569,40 @@ .BR star . If the author decides to change this method, later versions of .B star -may not be able to restore sparse files from tar +may not be able to restore sparse files from +.B tar archives made by the current version of .BR star . .PP -Some tar implementations violate the standard in using only the first 500 -Bytes of the header for checksum computation. These tar implementations +Some +.B tar +implementations violate the standard in using only the first 500 +Bytes of the header for checksum computation. These +.B tar +implementations will not accept .I star and .I xstar -type tar archives. +type +.B tar +archives. .PP -Sun's Solaris 2.x tar implementation violates the Posix standard. Tar +Sun's Solaris 2.x +.B tar +implementation violates the Posix standard. Tar archives generated by .B star -cause Sun's tar to print tar: impossible file type messages. You may +cause Sun's +.B tar +to print tar: impossible file type messages. You may ignore these messages. .PP -Gnutar's dumpdirs are currently not implemented. +Gnutar's dumpdirs are non standard and are currently not implemented. .PP If gnutar archives sparse files with more than four holes, it produces -archives that violate the standard in a way that prevents other tar +archives that violate the standard in a way that prevents other +.B tar implementations to read these archives. .B Star knows about that and is able to handle these gnutar archives. @@ -1582,18 +2622,55 @@ .PP .B Star resets its effective uid back to the real user id immediately after setting up -the remote connection to the rmt server. +the remote connection to the rmt server and before opening any other file. .SH LIMITATIONS -.B Star -currently handles files up to a size of 2 GB and -archives up to 2000000 TB. -The maximum file size limitation of 2 GB may easily be expanded to 8 GB. -With a non standard extension -.B star -will handle files up to 200000000 TB. -.PP -Access control list are currently not handled. +If +.B star +is running on a large file aware platform, +.B star +is able to handle files up to 8 GB in a mode that is compliant to the POSIX.1\-1988 +.B ustar +format. With a nonstandard +.B star +specific extension, up to 95 bits may be used to code the filesize. +This will handle files up to 200,000,000 TB. +With the new POSIX.1\-2001 extended headers +used by the +.IR xustar , +.I exustar +and +.I pax +format, any filesize may be archived. .SH BUGS +The fact that the +.B \-f +option has to be implemented in a way that is compatible with old tar +implementations gives several problems. +The options +.BR \-fifostats , +.BR \-force\-hole , +.B \-force\-remove +and +.B \-fifo +interfere with the +.B \-f +option and the fact that they exist prevents users from using filenames like +e.g. +.B ifo +using the traditional way where the filename directly follows the string +.B \-f +without any space between the option name and the file name. +However, there is no problem to use a file named +.B ifo +by by calling +.BR "\-f ifo" , +.BR f=ifo , +.BR \-f=ifo +or +.BR "\-f= ifo" . +Be careful not to make typos with the above options. The result could be +that a file is created as a result of the mistyped option. +.PP There is currently no way to set the fifo lowwater and highwater marks. .PP There is currently no way to automatically delete files in the target file tree @@ -1609,21 +2686,20 @@ .B Star is not able to make a complete backup of a filesystem if files are hidden by a mount that is in effect on a directory of this -filesystem. This could be avoided if the loopback filesystem had an +filesystem. +This may be avoided in case of the ufs filesystem +if the backup is made off a ufs snapshot (see the man page for +.BR fssnap (1m) +It could be avoided for any filesystem if the loopback filesystem had an option that tells .I lofs not to traverse mountpoints. -.PP -The actual version of the IEC-9945-1 standard has been changed to -allow character specials, block specials and fifo files to have -garbage sizes in the tar archive header. The current version of -.B star -does not implement this. This implies that tape archives that use -this feature may not be processed by -.BR star . + .SH HISTORY .B Star -was first created in 1982 to extract tapes on a UNIX clone that had no tar command. +was first created in 1982 to extract tapes on a UNIX clone that had no +.B tar +command. In 1985 the first fully functional version has been released as .B mtar. .PP @@ -1632,7 +2708,7 @@ format extensions have been introduced in 1985, it was renamed to .B star (Schily tar). -In 1994, Posix 1003.1 extensions were added and +In 1994, Posix 1003.1\-1988 extensions were added and .B star was renamed to .B star @@ -1642,7 +2718,7 @@ .nf J\*org Schilling Seestr. 110 -D-13353 Berlin +D\-13353 Berlin Germany .fi .PP @@ -1652,7 +2728,7 @@ schilling@fokus.gmd.de or .B -js@cs.tu-berlin.de +js@cs.tu\-berlin.de or .B -joerg@schily.isdn.cs.tu-berlin.de +joerg@schily.isdn.cs.tu\-berlin.de diff -ruN star-1.3.1/star/star.c star-1.4/star/star.c --- star-1.3.1/star/star.c Mon Apr 30 18:04:39 2001 +++ star-1.4/star/star.c Fri May 17 11:26:31 2002 @@ -1,10 +1,10 @@ -/* %Z%%M% %I% %E% Copyright 1985, 88-90, 92-96, 98, 99, 2000-2001 J. Schilling */ +/* @(#)star.c 1.122 02/05/17 Copyright 1985, 88-90, 92-96, 98, 99, 2000-2002 J. Schilling */ #ifndef lint static char sccsid[] = - "%Z%%M% %I% %E% Copyright 1985, 88-90, 92-96, 98, 99, 2000-2001 J. Schilling"; + "@(#)star.c 1.122 02/05/17 Copyright 1985, 88-90, 92-96, 98, 99, 2000-2002 J. Schilling"; #endif /* - * Copyright (c) 1985, 88-90, 92-96, 98, 99, 2000-2001 J. Schilling + * Copyright (c) 1985, 88-90, 92-96, 98, 99, 2000-2002 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify @@ -24,10 +24,9 @@ #include #include -#include -#include #include #include +#include #include #include "star.h" #include "diff.h" @@ -47,13 +46,19 @@ LOCAL char *dogetwdir __PR((void)); LOCAL BOOL dochdir __PR((const char *dir, BOOL doexit)); LOCAL void openlist __PR((void)); +LOCAL void susage __PR((int ret)); LOCAL void usage __PR((int ret)); LOCAL void xusage __PR((int ret)); LOCAL void dusage __PR((int ret)); LOCAL void husage __PR((int ret)); LOCAL void gargs __PR((int ac, char *const* av)); -LOCAL long number __PR((char* arg, int* retp)); +LOCAL Llong number __PR((char* arg, int* retp)); LOCAL int getnum __PR((char* arg, long* valp)); +/*LOCAL int getllnum __PR((char* arg, Llong* valp));*/ +LOCAL int getlldefault __PR((char* arg, Llong* valp, int mult)); +LOCAL int getbnum __PR((char* arg, Llong* valp)); +LOCAL int getknum __PR((char* arg, Llong* valp)); +LOCAL int addtarfile __PR((const char *tarfile)); EXPORT const char *filename __PR((const char *name)); LOCAL BOOL nameprefix __PR((const char *patp, const char *name)); LOCAL int namefound __PR((const char* name)); @@ -72,7 +77,8 @@ LOCAL void sigintr __PR((int sig)); LOCAL void sigquit __PR((int sig)); LOCAL void getstamp __PR((void)); -EXPORT void *__malloc __PR((unsigned int size)); +EXPORT void *__malloc __PR((size_t size, char *msg)); +EXPORT void *__realloc __PR((void *ptr, size_t size, char *msg)); EXPORT char *__savestr __PR((char *s)); LOCAL void docompat __PR((int *pac, char *const **pav)); @@ -93,7 +99,7 @@ #define YEAR (365 * DAY) #define LEAPYEAR (366 * DAY) -char strvers[] = "1.3.1"; +char strvers[] = "1.4"; struct star_stats xstats; @@ -106,22 +112,28 @@ LOCAL int *aux[NPAT]; LOCAL int alt[NPAT]; LOCAL int *state; -const unsigned char *pat[NPAT]; -const char *dirs[NPAT]; +LOCAL const Uchar *pat[NPAT]; +LOCAL const char *dirs[NPAT]; + +#define NTARFILE 100 FILE *tarf; FILE *listf; FILE *tty; FILE *vpr; -char *tarfile; +const char *tarfiles[NTARFILE]; +int ntarfiles; +int tarfindex; +char *newvol_script; char *listfile; char *stampfile; const char *wdir; const char *currdir; const char *dir_flags = NULL; char *volhdr; -long tape_dev; -long tape_ino; +dev_t tape_dev; +ino_t tape_ino; +BOOL tape_isreg = FALSE; #ifdef FIFO BOOL use_fifo = TRUE; #else @@ -132,7 +144,10 @@ long bs; int nblocks = 20; int uid; -Ulong curfs; +dev_t curfs = NODEV; +/* + * Change default header format into XUSTAR in 2004 (see below in gargs()) + */ long hdrtype = H_XSTAR; /* default header format */ long chdrtype= H_UNDEF; /* command line hdrtype */ int version = 0; @@ -142,7 +157,9 @@ BOOL no_stats= FALSE; BOOL do_fifostats= FALSE; BOOL numeric = FALSE; -BOOL verbose = FALSE; +int verbose = 0; +BOOL silent = FALSE; +BOOL prblockno = FALSE; BOOL tpath = FALSE; BOOL cflag = FALSE; BOOL uflag = FALSE; @@ -159,6 +176,7 @@ BOOL nomtime = FALSE; BOOL nochown = FALSE; BOOL acctime = FALSE; +BOOL pflag = FALSE; BOOL dirmode = FALSE; BOOL nolinkerr = FALSE; BOOL follow = FALSE; @@ -185,24 +203,37 @@ BOOL remove_recursive = FALSE; BOOL nullout = FALSE; -Ulong maxsize = 0L; -Ulong Newer = 0L; -Ulong tsize = 0L; +Ullong maxsize = 0; +time_t Newer = 0; +Ullong tsize = 0; long diffopts= 0L; BOOL nowarn = FALSE; BOOL Ctime = FALSE; +BOOL nodump = FALSE; BOOL listnew = FALSE; BOOL listnewf= FALSE; BOOL hpdev = FALSE; BOOL modebits= FALSE; BOOL copylinks= FALSE; +BOOL hardlinks= FALSE; +BOOL symlinks= FALSE; +BOOL doacl = FALSE; +BOOL dofflags= FALSE; +BOOL link_dirs= FALSE; +BOOL dodump = FALSE; +BOOL dometa = FALSE; -BOOL fcompat = FALSE; +BOOL tcompat = FALSE; /* Tar compatibility (av[0] is tar/ustar) */ +BOOL fcompat = FALSE; /* Archive file compatibility was requested */ int intr = 0; -char *opts = "C*,help,xhelp,version,debug,time,no_statistics,no-statistics,fifostats,numeric,v,tpath,c,u,r,x,t,n,diff,diffopts&,H&,force_hole,force-hole,sparse,to_stdout,to-stdout,wready,force_remove,force-remove,ask_remove,ask-remove,remove_first,remove-first,remove_recursive,remove-recursive,nullout,onull,fifo,no_fifo,no-fifo,shm,fs&,VOLHDR*,list*,file*,f*,T,bs&,blocks#,b#,z,bz,B,pattern&,pat&,i,d,m,nochown,a,atime,p,l,L,D,dodesc,M,I,w,O,signed_checksum,signed-checksum,P,S,F+,U,xdir,k,keep_old_files,keep-old-files,refresh_old_files,refresh-old-files,refresh,/,not,V,maxsize#L,newer*,ctime,tsize#L,qic24,qic120,qic150,qic250,nowarn,newest_file,newest-file,newest,hpdev,modebits,copylinks"; +/* + * Achtung: Optionen wie f= sind problematisch denn dadurch dass -ffilename geht, + * werden wird bei Falschschreibung von -fifo evt. eine Datei angelegt wird. + */ +char *opts = "C*,help,xhelp,version,debug,time,no_statistics,no-statistics,fifostats,numeric,v+,block-number,tpath,c,u,r,x,t,n,diff,diffopts&,H&,force_hole,force-hole,sparse,to_stdout,to-stdout,wready,force_remove,force-remove,ask_remove,ask-remove,remove_first,remove-first,remove_recursive,remove-recursive,nullout,onull,fifo,no_fifo,no-fifo,shm,fs&,VOLHDR*,list*,new-volume-script*,file&,f&,T,z,bz,bs&,blocks&,b&,B,pattern&,pat&,i,d,m,o,nochown,a,atime,p,dirmode,l,h,L,D,dodesc,M,I,w,O,signed_checksum,signed-checksum,P,S,F+,U,xdir,k,keep_old_files,keep-old-files,refresh_old_files,refresh-old-files,refresh,/,not,V,maxsize&,newer*,ctime,nodump,tsize&,qic24,qic120,qic150,qic250,nowarn,newest_file,newest-file,newest,hpdev,modebits,copylinks,hardlinks,symlinks,acl,xfflags,link-dirs,dump,meta,silent"; EXPORT int main(ac, av) @@ -214,8 +245,7 @@ save_args(ac, av); - if (ac > 1 && av[1][0] != '-') - docompat(&cac, &cav); + docompat(&cac, &cav); gargs(cac, cav); --cac,cav++; @@ -246,6 +276,12 @@ #endif comerr("Panic cannot set back efective uid.\n"); } + /* + * WARNING: We now are no more able to open a new remote connection + * unless we have been called by root. + * It you like to do a remote multi-tape backup to different hosts + * and do not call star from root, you are lost. + */ opentape(); @@ -256,6 +292,7 @@ setprops(chdrtype); /* Set up properties for archive format */ dev_init(debug); /* Init device macro handling */ + xbinit(); /* Initialize buffer for extended headers */ #ifdef FIFO if (use_fifo) @@ -327,7 +364,7 @@ break; if (intr) break; - curfs = -1L; + curfs = NODEV; create(cav[0]); } } @@ -339,9 +376,14 @@ checklinks(); if (!use_fifo) closetape(); +#ifdef FIFO + if (use_fifo) + fifo_exit(); +#endif - while (wait(0) >= 0) + while (wait(0) >= 0) { ; + } prstats(); if (checkerrs()) { if (!nowarn && !no_stats) { @@ -375,7 +417,7 @@ */ if (getfiles(acp, avp, &opts[3]) < 0) { errmsgno(EX_BAD, "Badly placed Option: %s.\n", *avp[0]); - usage(EX_BAD); + susage(EX_BAD); } } if (debug) /* temporary */ @@ -396,9 +438,7 @@ if (getcwd(dir, PATH_MAX) == NULL) comerr("Cannot get working directory\n"); - ndir = malloc(strlen(dir)+1); - if (ndir == NULL) - comerr("Cannot alloc space for working dir.\n"); + ndir = __malloc(strlen(dir)+1, "working dir"); strcpy(ndir, dir); return (ndir); } @@ -438,6 +478,25 @@ comerr("Cannot open '%s'.\n", listfile); } +/* + * Short usage + */ +LOCAL void +susage(ret) + int ret; +{ + error("Usage:\t%s cmd [options] file1 ... filen\n", get_progname()); + error("\nUse\t%s -help\n", get_progname()); + error("and\t%s -xhelp\n", get_progname()); + error("to get a list of valid cmds and options.\n"); + error("\nUse\t%s H=help\n", get_progname()); + error("to get a list of valid archive header formats.\n"); + error("\nUse\t%s diffopts=help\n", get_progname()); + error("to get a list of valid diff options.\n"); + exit(ret); + /* NOTREACHED */ +} + LOCAL void usage(ret) int ret; @@ -450,6 +509,7 @@ error("Options:\n"); error("\t-help\t\tprint this help\n"); error("\t-xhelp\t\tprint extended help\n"); + error("\t-version\tprint version information and exit\n"); error("\tblocks=#,b=#\tset blocking factor to #x512 Bytes (default 20)\n"); error("\tfile=nm,f=nm\tuse 'nm' as tape instead of stdin/stdout\n"); error("\t-T\t\tuse $TAPE as tape instead of stdin/stdout\n"); @@ -459,7 +519,8 @@ error("\t-shm\t\tuse SysV shared memory for fifo\n"); #endif #endif - error("\t-v\t\tbe verbose\n"); + error("\t-v\t\tincrement verbose level\n"); + error("\t-block-number\tprint the block numbers where the TAR headers start\n"); error("\t-tpath\t\tuse with -t to list path names only\n"); error("\tH=header\tgenerate 'header' type archive (see H=help)\n"); error("\tC=dir\t\tperform a chdir to 'dir' before storing next file\n"); @@ -469,11 +530,11 @@ error("\t-i\t\tignore checksum errors\n"); error("\t-d\t\tdo not store/create directories\n"); error("\t-m\t\tdo not restore access and modification time\n"); - error("\t-nochown\tdo not restore owner and group\n"); + error("\t-o,-nochown\tdo not restore owner and group\n"); error("\t-a,-atime\treset access time after storing file\n"); error("\t-p\t\trestore filemodes of directories\n"); error("\t-l\t\tdo not print a message if not all links are dumped\n"); - error("\t-L\t\tfollow symbolic links as if they were files\n"); + error("\t-h,-L\t\tfollow symbolic links as if they were files\n"); error("\t-D\t\tdo not descend directories\n"); error("\t-M\t\tdo not descend mounting points\n"); error("\t-I,-w\t\tdo interactive creation/extraction/renaming\n"); @@ -493,23 +554,34 @@ error("Usage:\tstar cmd [options] file1 ... filen\n"); error("Extended options:\n"); error("\tdiffopts=optlst\tcomma separated list of diffopts (see diffopts=help)\n"); + error("\t-debug\t\tprint additional debug messages\n"); + error("\t-silent\t\tno not print informational messages\n"); error("\t-not,-V\t\tuse those files which do not match pattern\n"); error("\tVOLHDR=name\tuse name to generate a volume header\n"); error("\t-xdir\t\textract dir even if the current is never\n"); + error("\t-dirmode\t\twrite directories after the files they contain\n"); + error("\t-link-dirs\tlook for hard linked directories in create mode\n"); + error("\t-dump\t\texperimental option for incremental dumps (more ino metadata)\n"); + error("\t-meta\t\texperimental option to use inode metadata only\n"); error("\t-keep-old-files,-k\tkeep existing files\n"); error("\t-refresh-old-files\trefresh existing files, don't create new files\n"); + error("\t-refresh\trefresh existing files, don't create new files\n"); error("\t-/\t\tdon't strip leading '/'s from file names\n"); error("\tlist=name\tread filenames from named file\n"); error("\t-dodesc\t\tdo descend directories found in a list= file\n"); error("\tpattern=p,pat=p\tset matching pattern\n"); - error("\tmaxsize=#\tdo not store file if it is bigger than # kBytes\n"); + error("\tmaxsize=#\tdo not store file if bigger than # (default mult is kB)\n"); error("\tnewer=name\tstore only files which are newer than 'name'\n"); + error("\tnew-volume-script=script\tcall 'scipt' at end of each volume\n"); error("\t-ctime\t\tuse ctime for newer= option\n"); + error("\t-nodump\t\tdo not dump files that have the nodump flag set\n"); + error("\t-acl\t\thandle access control lists\n"); + error("\t-xfflags\t\thandle extended file flags\n"); error("\tbs=#\t\tset (output) block size to #\n"); #ifdef FIFO error("\tfs=#\t\tset fifo size to #\n"); #endif - error("\ttsize=#\t\tset tape volume size to # 512 byte blocks\n"); + error("\ttsize=#\t\tset tape volume size to # (default multiplier is 512)\n"); error("\t-qic24\t\tset tape volume size to %d kBytes\n", TSIZE(QIC_24_TSIZE)/1024); error("\t-qic120\t\tset tape volume size to %d kBytes\n", @@ -530,6 +602,8 @@ error("\t-hpdev\t\tuse HP's non POSIX compliant method to store dev numbers\n"); error("\t-modebits\tinclude all 16 bits from stat.st_mode, this violates POSIX-1003.1\n"); error("\t-copylinks\tCopy hard and symlinks rather than linking\n"); + error("\t-hardlinks\tExtract symlinks as hardlinks\n"); + error("\t-symlinks\tExtract hardlinks as symlinks\n"); error("\t-signed-checksum\tuse signed chars to calculate checksum\n"); error("\t-sparse\t\thandle file with holes effectively on store/create\n"); error("\t-force-hole\ttry to extract all files with holes\n"); @@ -579,11 +653,14 @@ { error("Header types:\n"); error("\ttar\t\told tar format\n"); - error("\tstar\t\tstar format\n"); - error("\tgnutar\t\tgnu tar format\n"); - error("\tustar\t\tstandard tar (ieee 1003.1) format\n"); - error("\txstar\t\textended standard tar format\n"); + error("\tstar\t\told star format from 1985\n"); + error("\tgnutar\t\tgnu tar format (violates POSIX, use with care)\n"); + error("\tustar\t\tstandard tar (ieee POSIX 1003.1-1988) format\n"); + error("\txstar\t\textended standard tar format (star 1994)\n"); error("\txustar\t\textended standard tar format without tar signature\n"); + error("\texustar\t\textended standard tar format without tar signature (always x-header)\n"); + error("\tpax\t\textended (ieee POSIX 1003.1-2001) standard tar format\n"); + error("\tsuntar\t\tSun's extended pre-POSIX.1-2001 Solaris 7/8 tar format\n"); exit(ret); /* NOTREACHED */ } @@ -599,25 +676,49 @@ BOOL oldtar = FALSE; BOOL no_fifo = FALSE; BOOL usetape = FALSE; + BOOL xlinkerr= FALSE; BOOL dodesc = FALSE; BOOL qic24 = FALSE; BOOL qic120 = FALSE; BOOL qic150 = FALSE; BOOL qic250 = FALSE; const char *p; + Llong llbs = 0; -/*char *opts = "C*,help,xhelp,version,debug,time,no_statistics,no-statistics,fifostats,numeric,v,tpath,c,u,r,x,t,n,diff,diffopts&,H&,force_hole,force-hole,sparse,to_stdout,to-stdout,wready,force_remove,force-remove,ask_remove,ask-remove,remove_first,remove-first,remove_recursive,remove-recursive,nullout,onull,fifo,no_fifo,no-fifo,shm,fs&,VOLHDR*,list*,file*,f*,T,bs&,blocks#,b#,z,bz,B,pattern&,pat&,i,d,m,nochown,a,atime,p,l,L,D,dodesc,M,I,w,O,signed_checksum,signed-checksum,P,S,F+,U,xdir,k,keep_old_files,keep-old-files,refresh_old_files,refresh-old-files,refresh,/,not,V,maxsize#L,newer*,ctime,tsize#L,qic24,qic120,qic150,qic250,nowarn,newest_file,newest-file,newest,hpdev,modebits,copylinks";*/ +/*char *opts = "C*,help,xhelp,version,debug,time,no_statistics,no-statistics,fifostats,numeric,v+,block-number,tpath,c,u,r,x,t,n,diff,diffopts&,H&,force_hole,force-hole,sparse,to_stdout,to-stdout,wready,force_remove,force-remove,ask_remove,ask-remove,remove_first,remove-first,remove_recursive,remove-recursive,nullout,onull,fifo,no_fifo,no-fifo,shm,fs&,VOLHDR*,list*,new-volume-script*,file&,f&,T,z,bz,bs&,blocks&,b&,B,pattern&,pat&,i,d,m,o,nochown,a,atime,p,dirmode,l,h,L,D,dodesc,M,I,w,O,signed_checksum,signed-checksum,P,S,F+,U,xdir,k,keep_old_files,keep-old-files,refresh_old_files,refresh-old-files,refresh,/,not,V,maxsize&,newer*,ctime,nodump,tsize&,qic24,qic120,qic150,qic250,nowarn,newest_file,newest-file,newest,hpdev,modebits,copylinks,hardlinks,symlinks,acl,xfflags,link-dirs,dump,meta,silent";*/ p = filename(av[0]); if (streql(p, "ustar")) { + /* + * If we are called as "ustar" we are as POSIX-1003.1-1988 + * compliant as possible. There are no enhancements at all. + */ hdrtype = H_USTAR; + } else if (streql(p, "tar")) { + /* + * If we are called as "tar" we are mostly POSIX compliant + * and use POSIX-1003.1-2001 extensions. The differences of the + * base format compared to POSIX-1003.1-1988 can only be + * regocnised by star. Even the checsum bug of the "pax" + * reference implementation is not hit by the fingerprint + * used to allow star to discriminate XUSTAR from USTAR. + */ + hdrtype = H_XUSTAR; } + /* + * Current default archive format in all other cases is XSTAR (see + * above). This will not change until 2004 (then the new XUSTAR format + * is recognised by star for at least 5 years and we may asume that + * all star installations will properly handle it. + * XSTAR is USTAR with extensions similar to GNU tar. + */ + --ac,++av; if (getallargs(&ac, &av, opts, &dir_flags, &help, &xhelp, &prvers, &debug, &showtime, &no_stats, &no_stats, &do_fifostats, - &numeric, &verbose, &tpath, + &numeric, &verbose, &prblockno, &tpath, #ifndef lint &cflag, &uflag, @@ -635,20 +736,24 @@ getnum, &fs, &volhdr, &listfile, - &tarfile, &tarfile, + &newvol_script, + addtarfile, NULL, + addtarfile, NULL, &usetape, + &zflag, &bzflag, getnum, &bs, - &nblocks, &nblocks, - &zflag, &bzflag, &multblk, + getbnum, &llbs, + getbnum, &llbs, + &multblk, addpattern, NULL, addpattern, NULL, &ignoreerr, &nodir, - &nomtime, &nochown, + &nomtime, &nochown, &nochown, &acctime, &acctime, - &dirmode, - &nolinkerr, - &follow, + &pflag, &dirmode, + &xlinkerr, + &follow, &follow, &nodesc, &dodesc, &nomount, @@ -661,10 +766,11 @@ &refresh_old, &refresh_old, &refresh_old, &abs_path, ¬pat, ¬pat, - &maxsize, + getknum, &maxsize, &stampfile, &Ctime, - &tsize, + &nodump, + getbnum, &tsize, &qic24, &qic120, &qic150, @@ -673,9 +779,15 @@ #endif /* lint */ &listnewf, &listnewf, &listnew, - &hpdev, &modebits, ©links) < 0){ + &hpdev, &modebits, + ©links, &hardlinks, &symlinks, + &doacl, &dofflags, + &link_dirs, + &dodump, /* Experimental */ + &dometa, /* Experimental */ + &silent) < 0) { errmsgno(EX_BAD, "Bad Option: %s.\n", av[0]); - usage(EX_BAD); + susage(EX_BAD); } if (help) usage(0); @@ -683,36 +795,46 @@ xusage(0); if (prvers) { printf("star %s (%s-%s-%s)\n\n", strvers, HOST_CPU, HOST_VENDOR, HOST_OS); - printf("Copyright (C) 1985, 88-90, 92-96, 98, 99, 2000-2001 Jörg Schilling\n"); + printf("Copyright (C) 1985, 88-90, 92-96, 98, 99, 2000-2002 Jörg Schilling\n"); printf("This is free software; see the source for copying conditions. There is NO\n"); printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); exit(0); } if ((xflag + cflag + uflag + rflag + tflag + nflag + diff_flag) > 1) { - errmsgno(EX_BAD, "Only one of -x -c -u -r -t or -n.\n"); - usage(EX_BAD); + errmsgno(EX_BAD, "Too many commaands, only one of -x -c -u -r -t -n or -diff is allowed.\n"); + susage(EX_BAD); } if (!(xflag | cflag | uflag | rflag | tflag | nflag | diff_flag)) { - errmsgno(EX_BAD, "Must specify -x -c -u -r -t -n -diff.\n"); - usage(EX_BAD); + errmsgno(EX_BAD, "Missing command, must specify -x -c -u -r -t -n or -diff.\n"); + susage(EX_BAD); } if (uflag || rflag) { cflag = TRUE; no_fifo = TRUE; /* Until we are able to reverse the FIFO */ } if (nullout && !cflag) { - errmsgno(EX_BAD, "-nullout only make sense in create mode.\n"); - usage(EX_BAD); + errmsgno(EX_BAD, "-nullout only makes sense in create mode.\n"); + susage(EX_BAD); } if (no_fifo || nullout) use_fifo = FALSE; #ifndef FIFO if (use_fifo) { errmsgno(EX_BAD, "Fifo not configured in.\n"); - usage(EX_BAD); + susage(EX_BAD); } #endif + +/*#define TAR_COMPAT*/ +#ifdef TAR_COMPAT + nolinkerr = xlinkerr ^ tcompat; +#else + nolinkerr = xlinkerr; +#endif + + if (dodump) + chdrtype = H_EXUSTAR; if (oldtar) chdrtype = H_OTAR; if (chdrtype != H_UNDEF) { @@ -735,31 +857,54 @@ diffopts = D_DEFLT; } else if (diffopts != 0) { errmsgno(EX_BAD, "diffopts= only makes sense with -diff\n"); - usage(EX_BAD); + susage(EX_BAD); } if (fs == 0L) { char *ep = getenv("STAR_FIFO_SIZE"); if (ep) { - if (getnum(ep, &fs) != 1) - comerr("Bad fifo size environment '%s'.\n", + if (getnum(ep, &fs) != 1) { + comerrno(EX_BAD, + "Bad fifo size environment '%s'.\n", ep); + } } } + if (llbs != 0 && bs != 0) { + errmsgno(EX_BAD, "Only one of blocks= b= bs=.\n"); + susage(EX_BAD); + } + if (llbs != 0) { + bs = llbs; + if (bs != llbs) { + errmsgno(EX_BAD, "Blocksize used with blocks= or b= too large.\n"); + susage(EX_BAD); + } + } if (bs % TBLOCK) { - errmsgno(EX_BAD, "Invalid blocksize %ld.\n", bs); - usage(EX_BAD); + errmsgno(EX_BAD, "Invalid block size %ld.\n", bs); + susage(EX_BAD); } if (bs) nblocks = bs / TBLOCK; if (nblocks <= 0) { - errmsgno(EX_BAD, "Invalid blocksize %d blocks.\n", nblocks); - usage(EX_BAD); + errmsgno(EX_BAD, "Invalid block size %d blocks.\n", nblocks); + susage(EX_BAD); } bs = nblocks * TBLOCK; + if (debug) { + errmsgno(EX_BAD, "Block size %d blocks (%ld bytes).\n", nblocks, bs); + } + if (tsize > 0) { + if (tsize % TBLOCK) { + errmsgno(EX_BAD, "Invalid tape size %llu.\n", tsize); + susage(EX_BAD); + } + tsize /= TBLOCK; + } if (tsize > 0 && tsize < 3) { errmsgno(EX_BAD, "Tape size must be at least 3 blocks.\n"); - usage(EX_BAD); + susage(EX_BAD); } if (tsize == 0) { if (qic24) tsize = QIC_24_TSIZE; @@ -771,12 +916,13 @@ nodesc = TRUE; if (oldtar) nospec = TRUE; - if (!tarfile) { + if (!tarfiles[0]) { if (usetape) { - tarfile = getenv("TAPE"); + tarfiles[0] = getenv("TAPE"); } - if (!tarfile) - tarfile = "-"; + if (!tarfiles[0]) + tarfiles[0] = "-"; + ntarfiles++; } if (interactive || ask_remove || tsize > 0) { #ifdef JOS @@ -789,44 +935,77 @@ if (nflag) { xflag = TRUE; interactive = TRUE; - verbose = TRUE; + if (verbose == 0) + verbose = 1; } if (to_stdout) { force_hole = FALSE; } - if (remove_recursive) - comerrno(EX_BAD, "-remove_recursive not implemented\n"); - if (keep_old && refresh_old) - comerrno(EX_BAD, "Cannot use -keep_old_files and -refresh_old_files together.\n"); + if (keep_old && refresh_old) { + errmsgno(EX_BAD, "Cannot use -keep-old-files and -refresh-old-files together.\n"); + susage(EX_BAD); + } + if ((copylinks + hardlinks + symlinks) > 1) { + errmsgno(EX_BAD, "Only one of -copylinks -hardlinks -symlinks.\n"); + susage(EX_BAD); + } + + /* + * keep compatibility for some time. + */ + if (pflag) + dirmode = TRUE; + + /* + * -acl includes -p + */ + if (doacl) + pflag = TRUE; } -LOCAL long +LOCAL Llong number(arg, retp) register char *arg; int *retp; { - long val = 0; + Llong val = (Llong)0; if (*retp != 1) return (val); - if (*arg == '\0') + if (*arg == '\0') { *retp = -1; - else if (*(arg = astol(arg, &val))) { - if (*arg == 'm' || *arg == 'M') { + } else if (*(arg = astoll(arg, &val))) { + if (*arg == 'p' || *arg == 'P') { val *= (1024*1024); + val *= (1024*1024*1024); arg++; - } - else if (*arg == 'k' || *arg == 'K') { + + } else if (*arg == 't' || *arg == 'T') { + val *= (1024*1024); + val *= (1024*1024); + arg++; + + } else if (*arg == 'g' || *arg == 'G') { + val *= (1024*1024*1024); + arg++; + + } else if (*arg == 'm' || *arg == 'M') { + val *= (1024*1024); + arg++; + + } else if (*arg == 'k' || *arg == 'K') { val *= 1024; arg++; - } - else if (*arg == 'b' || *arg == 'B') { - val *= TBLOCK; + + } else if (*arg == 'b' || *arg == 'B') { + val *= 512; arg++; - } - else if (*arg == 'w' || *arg == 'W') { + + } else if (*arg == 'w' || *arg == 'W') { val *= 2; arg++; + } else if (*arg == '.') { /* 1x multiplier */ + arg++; } if (*arg == '*' || *arg == 'x') val *= number(++arg, retp); @@ -841,11 +1020,87 @@ char *arg; long *valp; { + Llong llval; + int ret = 1; + + llval = number(arg, &ret); + *valp = llval; + if (*valp != llval) { + errmsgno(EX_BAD, + "Value %lld is too large for data type 'long'.\n", + llval); + ret = -1; + } + return (ret); +} + +/* + * not yet needed +LOCAL int +getllnum(arg, valp) + char *arg; + Llong *valp; +{ int ret = 1; *valp = number(arg, &ret); return (ret); } +*/ + +LOCAL int +getlldefault(arg, valp, mult) + char *arg; + Llong *valp; + int mult; +{ + int ret = 1; + int len = strlen(arg); + + if (len > 0) { + len = (Uchar)arg[len-1]; + if (!isdigit(len)) + mult = 1; + } + *valp = number(arg, &ret); + if (ret == 1) + *valp *= mult; + return (ret); +} + +LOCAL int +getbnum(arg, valp) + char *arg; + Llong *valp; +{ + return (getlldefault(arg, valp, 512)); +} + +LOCAL int +getknum(arg, valp) + char *arg; + Llong *valp; +{ + return (getlldefault(arg, valp, 1024)); +} + +LOCAL int +addtarfile(tarfile) + const char *tarfile; +{ +/* if (debug)*/ +/* error("Add tar file '%s'.\n", tarfile);*/ + + if (ntarfiles >= NTARFILE) + comerrno(EX_BAD, "Too many tar files (max is %d).\n", NTARFILE); + + if (streql(tarfile, "-") || (ntarfiles > 0 && streql(tarfiles[0], "-"))) + comerrno(EX_BAD, "Cannot handle multi volume archives from/to stdin/stdout.\n"); + + tarfiles[ntarfiles] = tarfile; + ntarfiles++; + return (TRUE); +} EXPORT const char * filename(name) @@ -903,7 +1158,7 @@ for (i=0; i < npat; i++) { ret = (char *)patmatch(pat[i], aux[i], - (const unsigned char *)name, 0, + (const Uchar *)name, 0, strlen(name), alt[i], state); if (ret != NULL && *ret == '\0') break; @@ -934,14 +1189,13 @@ if (npat >= NPAT) comerrno(EX_BAD, "Too many patterns (max is %d).\n", NPAT); plen = strlen(pattern); - pat[npat] = (const unsigned char *)pattern; + pat[npat] = (const Uchar *)pattern; if (plen > maxplen) maxplen = plen; - if ((aux[npat] = malloc(plen*sizeof(int))) == NULL) - comerr("Cannot alloc space for compiled pattern.\n"); - if ((alt[npat] = patcompile((const unsigned char *)pattern, + aux[npat] = __malloc(plen*sizeof(int), "compiled pattern"); + if ((alt[npat] = patcompile((const Uchar *)pattern, plen, aux[npat])) == 0) comerrno(EX_BAD, "Bad pattern: '%s'.\n", pattern); dirs[npat] = currdir; @@ -962,7 +1216,7 @@ if (narg >= NPAT) comerrno(EX_BAD, "Too many patterns (max is %d).\n", NPAT); - pat[narg] = (const unsigned char *)pattern; + pat[narg] = (const Uchar *)pattern; dirs[narg] = currdir; narg++; return (TRUE); @@ -993,8 +1247,7 @@ havepat = TRUE; if (npat > 0) { - if ((state = malloc((maxplen+1)*sizeof(int))) == NULL) - comerr("Cannot alloc space for pattern state.\n"); + state = __malloc((maxplen+1)*sizeof(int), "pattern state"); } } @@ -1124,6 +1377,12 @@ type = H_XSTAR; } else if (streql(optstr, "xustar")) { type = H_XUSTAR; + } else if (streql(optstr, "exustar")) { + type = H_EXUSTAR; + } else if (streql(optstr, "pax")) { + type = H_PAX; + } else if (streql(optstr, "suntar")) { + type = H_SUNTAR; } else if (streql(optstr, "help")) { husage(0); } else { @@ -1230,14 +1489,31 @@ } EXPORT void * -__malloc(size) - unsigned int size; +__malloc(size, msg) + size_t size; + char *msg; { void *ret; ret = malloc(size); if (ret == NULL) { - comerr("No memory.\n"); + comerr("Cannot allocate memory for %s.\n", msg); + /* NOTREACHED */ + } + return (ret); +} + +EXPORT void * +__realloc(ptr, size, msg) + void *ptr; + size_t size; + char *msg; +{ + void *ret; + + ret = realloc(ptr, size); + if (ret == NULL) { + comerr("Cannot realloc memory for %s.\n", msg); /* NOTREACHED */ } return (ret); @@ -1247,7 +1523,7 @@ __savestr(s) char *s; { - char *ret = __malloc(strlen(s)+1); + char *ret = __malloc(strlen(s)+1, "saved string"); strcpy(ret, s); return (ret); @@ -1260,9 +1536,69 @@ * tar implementations. The old syntax has a risk to damage files * which is avoided with the 'fcompat' flag (see opentape()). * + * The UNIX-98 documentation lists the following tar options: + * Function Key: crtux + * c Create + * r Append + * t List + * u Update + * x Extract + * Additional Key: vwfblmo + * v Verbose + * w Wait for confirmation + * f Archive file + * b Blocking factor + * l Report missing links + * m Do not restore mtime from archive + * o Do not restore owner/group from archive + * + * Incompatibilities with UNIX-98 tar: + * l works the oposite way round as with star, but + * if TAR_COMPAT is defined, star will behaves + * as documented in UNIX-98 if av[0] is either + * "tar" or "ustar". + * + * Additional functions from historic UNIX tar vesions: + * 0..7 magtape_0 .. magtape_7 + * + * Additional functions from historic BSD tar vesions: + * p Extract dir permissions too + * h Follow symbolic links + * i ignore directory checksum errors + * B do multiple reads to reblock pipes + * F Ommit unwanted files (e.g. core) + * + * Additional functions from historic Star vesions: + * T Use $TAPE environment as archive + * L Follow symbolic links + * d do not archive/extract directories + * k keep old files + * n do not extract but tell what to do + * + * Additional functions from historic SVr4 tar vesions: + * e Exit on unexpected errors + * X Arg is File with unwanted filenames + * + * Additional functions from historic GNU tar vesions: + * z do inline compression + * + * Missing in star (from SVr4/Solaris tar): + * E Extended headers + * P Supress '/' at beginning of filenames + * q quit after extracting first file + * Incompatibilities with SVr4/Solaris tar: + * I Arg is File with filenames to be included + * P SVr4/solaris: Supress '/', star: last partial + * k set tape size for multi volume archives + * n non tape device (do seeks) + * + * Incompatibilities with GNU tar: + * There are many. GNU programs in many cases make smooth + * coexistence hard. + * * Problems: * The 'e' and 'X' option are currently not implemented. - * The 'h' option can only be implemented if the -help + * The 'h' option can only be implemented if the -help XXX DONE * shortcut in star is removed. * There is a collision between the BSD -I (include) and * star's -I (interactive) which may be solved by using -w instead. @@ -1272,22 +1608,33 @@ int *pac; char *const **pav; { - int ac = *pac; + int ac = *pac; char *const *av = *pav; int nac; char **nav; char nopt[3]; - char *copt = "crtuxbfXBFTLdeiklmnopvwz01234567"; - char *p; + char *copt = "crtuxbfXBFTLdehiklmnopvwz01234567"; +const char *p; char c; char *const *oa; char **na; + p = filename(av[0]); + if (streql(p, "tar") || streql(p, "ustar")) + tcompat = TRUE; + + if (ac <= 1) + return; + + if (av[1][0] == '-') /* Do not convert new syntax */ + return; + if (strchr(av[1], '=') != NULL) /* Do not try to convert bs= */ return; nac = ac + strlen(av[1]); - nav = __malloc(nac-- * sizeof(char *)); /* keep space for NULL ptr */ + nav = __malloc(nac-- * sizeof(char *), /* keep space for NULL ptr */ + "compat argv"); oa = av; na = nav; *na++ = *oa++; @@ -1299,7 +1646,7 @@ for (p=av[1]; (c = *p) != '\0'; p++) { if (strchr(copt, c) == NULL) { errmsgno(EX_BAD, "Illegal option '%c' for compat mode.\n", c); - usage(EX_BAD); + susage(EX_BAD); } nopt[1] = c; *na++ = __savestr(nopt); diff -ruN star-1.3.1/star/star.h star-1.4/star/star.h --- star-1.3.1/star/star.h Sat Apr 7 10:25:50 2001 +++ star-1.4/star/star.h Sat May 11 17:12:49 2002 @@ -1,6 +1,6 @@ -/* @(#)star.h 1.33 01/04/07 Copyright 1985, 1995 J. Schilling */ +/* @(#)star.h 1.62 02/05/11 Copyright 1985, 1995-2001 J. Schilling */ /* - * Copyright (c) 1985, 1995 J. Schilling + * Copyright (c) 1985, 1995-2001 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify @@ -18,10 +18,21 @@ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef _STAR_H +#define _STAR_H + #include #include -#define tarblocks(s) (((s) + (TBLOCK-1)) / TBLOCK) +#ifndef _INCL_SYS_TYPES_H +#include +#define _INCL_SYS_TYPES_H +#endif + +/* + * Be careful not to overflow off_t when computing tarblocks() + */ +#define tarblocks(s) (((s) / TBLOCK) + (((s)%TBLOCK)?1:0)) #define tarsize(s) (tarblocks(s) * TBLOCK) /* @@ -33,24 +44,41 @@ #define H_TYPE(t) ((int)(H_ISSWAPPED(t) ? ((-1)*(t)):(t))) #define H_UNDEF 0 #define H_TAR 1 /* tar unbekanntes format */ -#define H_OTAR 2 /* tar altes format */ -#define H_STAR 3 /* star format */ -#define H_GNUTAR 4 /* gnu tar format */ -#define H_USTAR 5 /* ieee 1003.1 format */ -#define H_XSTAR 6 /* extended 1003.1 format */ -#define H_XUSTAR 7 /* extended 1003.1 format without "tar" signature */ -#define H_RES8 8 /* Reserved */ -#define H_BAR 9 /* SUN bar format */ -#define H_CPIO 10 /* XXX entfällt */ -#define H_CPIO_BIN 10 /* cpio Binär */ -#define H_CPIO_CHR 11 /* cpio -c format */ -#define H_CPIO_NBIN 12 /* cpio neu Binär */ -#define H_CPIO_CRC 13 /* cpio crc Binär */ -#define H_CPIO_ASC 14 /* cpio ascii expanded maj/min */ -#define H_CPIO_ACRC 15 /* cpio crc expanded maj/min */ -#define H_MAX_ARCH 15 /* Highest possible # */ +#define H_OTAR 2 /* tar altes format (1978 ???) */ +#define H_STAR 3 /* altes star format (1985) */ +#define H_GNUTAR 4 /* gnu tar format (1989) */ +#define H_USTAR 5 /* ieee 1003.1-1988 format (1987 ff.) */ +#define H_XSTAR 6 /* extended 1003.1-1988 format (1994) */ +#define H_XUSTAR 7 /* ext 1003.1-1988 format without "tar" signature (1998) */ +#define H_EXUSTAR 8 /* ext 1003.1-2001 format without "tar" signature (2001) */ +#define H_PAX 9 /* ieee 1003.1-2001 extended ustar format called PAX */ +#define H_SUNTAR 10 /* Sun's tar implementaion from Solaris 7/8/9 */ +#define H_RES11 11 /* Reserved */ +#define H_RES12 12 /* Reserved */ +#define H_RES13 13 /* Reserved */ +#define H_RES14 14 /* Reserved */ +#define H_BAR 15 /* SUN bar format */ +#define H_CPIO_BASE 16 /* cpio Basis */ +#define H_CPIO_BIN 16 /* cpio Binär */ +#define H_CPIO_CHR 17 /* cpio -c format */ +#define H_CPIO_NBIN 18 /* cpio neu Binär */ +#define H_CPIO_CRC 19 /* cpio crc Binär */ +#define H_CPIO_ASC 20 /* cpio ascii expanded maj/min */ +#define H_CPIO_ACRC 21 /* cpio crc expanded maj/min */ +#define H_CPIO_MAX 21 /* cpio Ende */ +#define H_MAX_ARCH 21 /* Highest possible # */ + +/* + * Return codes from compression type checker. + */ +#define C_NONE 0 /* Not compressed or unknown compression */ +#define C_GZIP 1 /* Compression may be unpacked with 'bzip' */ +#define C_BZIP2 2 /* Compression may be unpacked with 'bzip2' */ +/* + * POSIX.1-1988 field size values and magic. + */ #define TBLOCK 512 #define NAMSIZ 100 #define PFXSIZ 155 @@ -70,6 +98,44 @@ #define TGNMLEN 32 #define TDEVLEN 8 +/* + * The maximum number that we may handle with a 32 bit int + */ +#define MAXINT32 0x7FFFFFFFL + +/* + * Large file summit: max size of a non-large file (2 GB - 2 Bytes) + */ +#define MAXNONLARGEFILE (MAXINT32 - 1) + +/* + * Max POSIX.1-1988 limit for numeric 12 byte fields such as size/mtime + */ +#ifdef USE_LONGLONG +#define MAXOCTAL11 077777777777ULL +#else +#define MAXOCTAL11 MAXINT32 +#endif + +/* + * Max POSIX.1-1988 limit for numeric 8 byte fields such as uid/gid/dev + */ +#define MAXOCTAL7 07777777 + +/* + * Pre POSIX.1-1988 limit for numeric 8 byte fields such as uid/gid/dev + */ +#define MAXOCTAL6 0777777 + +/* + * Non POSIX.1-1988 limit used by HP-UX tar for 8 byte devmajor/devminor + */ +#define MAXOCTAL8 077777777 + + +/* + * POSIX.1-1988 typeflag values + */ #define REGTYPE '0' #define AREGTYPE '\0' #define LNKTYPE '1' @@ -81,17 +147,28 @@ #define CONTTYPE '7' /* - * star/gnu tar extensions: + * POSIX.1-2001 typeflag extensions. + * POSIX.1-2001 calls the extended USTAR format PAX although it is definitely + * derived from and based on USTAR. The reason may be that POSIX.1-2001 + * calls the tar program outdated and lists the pax program as the successor. + */ +#define LF_GHDR 'g' /* POSIX.1-2001 global extended header */ +#define LF_XHDR 'x' /* POSIX.1-2001 extended header */ + +/* + * star/gnu/Sun tar extensions: */ /* Note that the standards committee allows only capital A through capital Z for user-defined expansion. This means that defining something as, say '8' is a *bad* idea. */ -#define LF_ACL 'A' /* Access Control List */ +#define LF_ACL 'A' /* Solaris Access Control List */ #define LF_DUMPDIR 'D' /* This is a dir entry that contains the names of files that were in the dir at the time the dump was made */ +#define LF_EXTATTR 'E' /* Solaris Extended Attribute File */ +#define LF_META 'I' /* Inode (metadata only) no file content*/ #define LF_LONGLINK 'K' /* Identifies the NEXT file on the tape as having a long linkname */ #define LF_LONGNAME 'L' /* Identifies the NEXT file on the tape @@ -104,6 +181,26 @@ #define LF_SPARSE 'S' /* This is for sparse files */ #define LF_VOLHDR 'V' /* This file is a tape/volume header */ /* Ignore it on extraction */ +#define LF_VU_XHDR 'X' /* POSIX.1-2001 xtended (VU version) */ + +/* + * Definitions for the t_mode field + */ +#define TSUID 04000 /* Set UID on execution */ +#define TSGID 02000 /* Set GID on execution */ +#define TSVTX 01000 /* On directories, restricted deletion flag */ +#define TUREAD 00400 /* Read by owner */ +#define TUWRITE 00200 /* Write by owner special */ +#define TUEXEC 00100 /* Execute/search by owner */ +#define TGREAD 00040 /* Read by group */ +#define TGWRITE 00020 /* Write by group */ +#define TGEXEC 00010 /* Execute/search by group */ +#define TOREAD 00004 /* Read by other */ +#define TOWRITE 00002 /* Write by other */ +#define TOEXEC 00001 /* Execute/search by other */ + +#define TALLMODES 07777 /* The low 12 bits mentioned in the standard */ + /* * This is the ustar (Posix 1003.1) header. @@ -140,7 +237,7 @@ #define STGNMLEN 15 /* star group name length */ /* - * This is the old (pre Posix 1003.1) star header defined in 1985. + * This is the old (pre Posix 1003.1-1988) star header defined in 1985. */ struct star_header { char t_name[NAMSIZ]; /* 0 Dateiname */ @@ -152,6 +249,8 @@ char t_chksum[8]; /* 148 Checksumme */ char t_linkflag; /* 156 Linktyp der Datei */ char t_linkname[NAMSIZ];/* 157 Zielname des Links */ + /* --- Ende historisches TAR */ + /* --- Anfang star Erweiterungen */ char t_vers; /* 257 Version v. star */ char t_filetype[8]; /* 258 Interner Dateityp */ char t_type[12]; /* 266 Dateityp (UNIX) */ @@ -171,7 +270,7 @@ }; /* - * This is the new (post Posix 1003.1) xstar header. + * This is the new (post Posix 1003.1-1988) xstar header defined in 1994. * * t_prefix[130] is garanteed to be '\0' to prevent ustar compliant * implementations from failing. @@ -240,6 +339,11 @@ char t_isextended; }; +typedef struct { + off_t sp_offset; + off_t sp_numbytes; +} sp_t; + /* * gnu tar header specific definitions */ @@ -247,23 +351,22 @@ #define GMAGIC "ustar "/* gnu tar magic */ #define GMAGLEN 8 /* "ustar" two blanks and a NULL */ -typedef struct { - unsigned long sp_offset; - unsigned long sp_numbytes; -} sp_t; - -struct gnu_in_header { - char t_fill[386]; - struct sparse t_sp[SIH];/* 386 */ - char t_isextended; /* 482 */ - char t_realsize[12]; /* true size of the sparse file *//* 483 */ -}; - -struct gnu_extended_header { - struct sparse t_sp[SEH]; - char t_isextended; -}; - +/* + * This is the GNUtar header defined in 1989. + * + * The nonstandard stuff could not be found in in the first pubslished versions + * of the program. The first version I am aware of, is a program called SUGtar + * published at the Sun User Group meeting in december 1987, a different + * publishing of the same program which has been originally written by + * John Gilmore was called PDtar. In 1987 PDtar/SUGtar was implementing a true + * subset of the 1987 POSIX-1003 draft (missing only the long name splitting). + * + * FSF people then later added t_atime... making GNU tar non POSIX compliant. + * When FSF added the sparse file handling stuff, this was done in a way that + * even violates any tar document available since the late 1970's. + * + * GNU tar is not tar... + */ struct gnu_header { char t_name[NAMSIZ]; /* 0 Dateiname */ char t_mode[8]; /* 100 Zugriffsrechte */ @@ -279,23 +382,31 @@ char t_gname[TGNMLEN]; /* 297 Gruppenname */ char t_devmajor[8]; /* 329 Major bei Geraeten */ char t_devminor[8]; /* 337 Minor bei Geraeten */ + +/* Jay Fenlason (hack@ai.mit.edu) */ /* these following fields were added by JF for gnu */ /* and are NOT standard */ char t_atime[12]; /* 345 */ char t_ctime[12]; /* 357 */ char t_offset[12]; /* 369 */ char t_longnames[4]; /* 381 */ -#ifdef xxx -#ifdef NEEDPAD - char pad; /* 385 */ -#endif - struct sparse t_sp[SPARSE_IN_HDR];/* 386 */ - char t_isextended; /* 482 */ - char t_realsize[12]; /* true size of the sparse file *//* 483 */ - /* char ending_blanks[12];*//* number of nulls at the *//* 495 */ - /* end of the file, if any */ -#endif /* xxx */ + /* + * for the rest see struct gnu_in_header + */ +}; + +struct gnu_in_header { + char t_fill[386]; + struct sparse t_sp[SIH];/* 386 4 sparse structures (2 x 12 bytes) */ + char t_isextended; /* 482 an extended header follows */ + char t_realsize[12]; /* 483 true size of the sparse file */ +}; + +struct gnu_extended_header { + struct sparse t_sp[SEH];/* 0 21 sparse structures (2 x 12 bytes) */ + char t_isextended; /* 504 another extended header follows */ }; + #undef SIH #undef SEH @@ -305,26 +416,33 @@ #define BAR_SYMTYPE '2' #define BAR_SPECIAL '3' -#define BAR_VOLHEAD "V" +#define BAR_VOLHEAD "V" /* The BAR Volume "magic" */ +/* + * The Sun BAR header format as introduced with the Roadrunner Intel machines + * + * All header parts marked with "*VH" are set only in the volheader + * and zero on any other headers. + */ struct bar_header { char mode[8]; /* 0 file type and mode (top bit masked) */ - char uid[8]; /* 8 Benutzernummer */ - char gid[8]; /* 16 Benutzergruppe */ - char size[12]; /* 24 Dateigroesze */ + char uid[8]; /* 8 Benutzernummer */ + char gid[8]; /* 16 Benutzergruppe */ + char size[12]; /* 24 Dateigroesze */ char mtime[12]; /* 36 Zeit d. letzten Aenderung */ - char t_chksum[8]; /* 48 Checksumme */ + char t_chksum[8]; /* 48 Checksumme */ char rdev[8]; /* 56 Major/Minor bei Geraeten */ - char linkflag; /* 64 Linktyp der Datei */ - char bar_magic[2]; /* 65 xxx */ - char volume_num[4]; /* 67 Volume Nummer */ - char compressed; /* 71 Compress Flag */ - char date[12]; /* 72 Aktuelles Datum */ - char start_of_name[1]; /* 84 Dateiname */ + char linkflag; /* 64 Linktyp der Datei */ + char bar_magic[2]; /* 65 *VH xxx */ + char volume_num[4]; /* 67 *VH Volume Nummer */ + char compressed; /* 71 *VH Compress Flag */ + char date[12]; /* 72 *VH Aktuelles Datum YYMMDDhhmm */ + char start_of_name[1]; /* 84 Dateiname */ }; typedef union hblock { char dummy[TBLOCK]; + long ldummy[TBLOCK/sizeof(long)]; /* force long alignement */ struct star_header dbuf; struct star_header star_dbuf; struct xstar_header xstar_dbuf; @@ -335,8 +453,27 @@ struct gnu_in_header gnu_in_dbuf; struct gnu_extended_header gnu_ext_dbuf; struct bar_header bar_dbuf; -}TCB ; +} TCB; +/* + * Our internal OS independant structure to hold file metadata. + * + * Some remarks to the different file type structure members: + * + * f_xftype The new tar general (x-tended) file type. + * This includes values XT_LINK XT_SPARSE XT_LONGNAME ... + * + * f_rxftype The 'real' general file type. + * Doesn't include XT_LINK XT_SPARSE XT_LONGNAME ... + * This is the 'real' file type and close to what has been + * set up in getinfo(). + * + * f_filetype The coarse file type classification (star 1985 header) + * + * f_typeflag The file type flag used in the POSIX.1-1988 TAR header + * + * f_type The OS specific file type (e.g. UNIX st_mode & S_IFMT) + */ typedef struct { TCB *f_tcb; char *f_name; /* Zeiger auf den langen Dateinamen */ @@ -347,19 +484,22 @@ Ulong f_umaxlen; /* Maximale Länge des Usernamens*/ char *f_gname; /* Group name oder NULL Pointer */ Ulong f_gmaxlen; /* Maximale Länge des Gruppennamens*/ - Ulong f_dev; /* Geraet auf dem sich d. Datei befindet */ - Ulong f_ino; /* Dateinummer */ + dev_t f_dev; /* Geraet auf dem sich d. Datei befindet */ + ino_t f_ino; /* Dateinummer */ Ulong f_nlink; /* Anzahl der Links */ Ulong f_mode; /* Zugriffsrechte */ Ulong f_uid; /* Benutzernummer */ Ulong f_gid; /* Benutzergruppe */ - Ulong f_size; /* Dateigroesze */ - Ulong f_rsize; /* Dateigroesze auf Band */ - Ulong f_offset; /* Offset für Multivol cont. Dateien */ + off_t f_size; /* Dateigroesze */ + off_t f_rsize; /* Dateigroesze auf Band */ + off_t f_contoffset; /* Offset für Multivol cont. Dateien */ Ulong f_flags; /* Bearbeitungshinweise */ - Ulong f_xftype; /* Typ der Datei (neu generell) */ + Ulong f_xflags; /* Flags für x-header */ + Ulong f_xftype; /* Header Dateityp (neu generell)*/ + Ulong f_rxftype; /* Echter Dateityp (neu generell)*/ Ulong f_filetype; /* Typ der Datei (star alt) */ - Ulong f_type; /* Dateityp */ + Uchar f_typeflag; /* Kopie aus TAR Header */ + Ulong f_type; /* Dateityp aus UNIX struct stat*/ Ulong f_rdev; /* Major/Minor bei Geraeten */ Ulong f_rdevmaj; /* Major bei Geraeten */ Ulong f_rdevmin; /* Minor bei Geraeten */ @@ -369,8 +509,16 @@ Ulong f_mnsec; /* nsec Teil " */ time_t f_ctime; /* Zeit d. letzten Statusaend. */ Ulong f_cnsec; /* nsec Teil " */ + Ulong f_fflags; /* File flags */ +#ifdef USE_ACL + char *f_acl_access; /* POSIX Access Control List */ + char *f_acl_default; /* POSIX Default ACL */ +#endif } FINFO; +/* + * Used with f_flags + */ #define F_LONGNAME 0x01 /* Langer Name passt nicht in Header */ #define F_LONGLINK 0x02 /* Langer Linkname passt nicht in Header */ #define F_SPLIT_NAME 0x04 /* Langer Name wurde gesplitted */ @@ -378,11 +526,46 @@ #define F_SPARSE 0x10 /* Datei enthält Löcher */ #define F_TCB_BUF 0x20 /* TCB ist/war vom Buffer alloziert */ #define F_ADDSLASH 0x40 /* Langer Name benötigt Slash am Ende */ +#define F_NSECS 0x80 /* stat() liefert Nanosekunden */ +#define F_NODUMP 0x100 /* Datei hat OS spezifisches NODUMP flag */ + +/* + * Used with f_xflags + */ +#define XF_ATIME 0x0001 /* Zeit d. letzten Zugriffs */ +#define XF_CTIME 0x0002 /* Zeit d. letzten Statusaend. */ +#define XF_MTIME 0x0004 /* Zeit d. letzten Aenderung */ +#define XF_COMMENT 0x0008 /* Beliebiger Kommentar */ +#define XF_UID 0x0010 /* Benutzernummer */ +#define XF_UNAME 0x0020 /* Langer Benutzername */ +#define XF_GID 0x0040 /* Benutzergruppe */ +#define XF_GNAME 0x0080 /* Langer Benutzergruppenname */ +#define XF_PATH 0x0100 /* Langer Name */ +#define XF_LINKPATH 0x0200 /* Langer Link Name */ +#define XF_SIZE 0x0400 /* Dateigröße wenn > 8 GB */ +#define XF_CHARSET 0x0800 /* Zeichensatz für Dateiinhalte */ + +#define XF_DEVMAJOR 0x1000 /* Major bei Geräten */ +#define XF_DEVMINOR 0x2000 /* Major bei Geräten */ -#define F_SPEC 0 -#define F_FILE 1 -#define F_SLINK 2 -#define F_DIR 3 +#define XF_ACL_ACCESS 0x4000 /* POSIX Access Control List */ +#define XF_ACL_DEFAULT 0x8000 /* POSIX Default ACL */ + +#define XF_FFLAGS 0x10000 /* File flags */ + +#define XF_NOTIME 0x10000000 /* Keine extended Zeiten */ + +/* + * Used with f_filetype + * + * This is optimised for the old star (1986) extensions that were the first + * tar extensions which allowed to archive files different from regular files, + * directories and symbolic links. + */ +#define F_SPEC 0 /* Anything not mentioned below */ +#define F_FILE 1 /* A reguar file */ +#define F_SLINK 2 /* A symbolic link */ +#define F_DIR 3 /* A directory */ #define is_special(i) ((i)->f_filetype == F_SPEC) #define is_file(i) ((i)->f_filetype == F_FILE) @@ -393,12 +576,24 @@ #define is_cdev(i) ((i)->f_xftype == XT_CHR) #define is_dev(i) (is_bdev(i) || is_cdev(i)) #define is_fifo(i) ((i)->f_xftype == XT_FIFO) +#define is_door(i) ((i)->f_xftype == XT_DOOR) #define is_link(i) ((i)->f_xftype == XT_LINK) +#define fis_link(i) ((i)->f_rxftype == XT_LINK) /* Filetype unknown */ #define is_volhdr(i) ((i)->f_xftype == XT_VOLHDR) #define is_sparse(i) ((i)->f_xftype == XT_SPARSE) #define is_multivol(i) ((i)->f_xftype == XT_MULTIVOL) +#define is_whiteout(i) ((i)->f_xftype == XT_WHT) +#define is_meta(i) ((i)->f_xftype == XT_META) +#define fis_meta(i) ((i)->f_rxftype == XT_META) /* Really "regular" */ +#ifdef isdigit +#undef isdigit /* Needed for HP-UX */ +#endif +#define isdigit(c) ((c) >= '0' && (c) <= '9') #define isoctal(c) ((c) >= '0' && (c) <= '7') +#ifdef isupper +#undef isupper /* Needed for HP-UX */ +#endif #define isupper(c) ((c) >= 'A' && (c) <= 'Z') #define toupper(c) (isupper(c) ? (c) : (c) - ('a' - 'A')) /* @@ -416,6 +611,9 @@ struct star_stats { int s_staterrs; /* Could not stat(2) file */ +#ifdef USE_ACL + int s_getaclerrs; /* Could not get ACL for file */ +#endif int s_openerrs; /* Open/Create error for file */ int s_rwerrs; /* Read/Write error from file */ int s_sizeerrs; /* File changed size */ @@ -423,12 +621,30 @@ int s_toolong; /* File name too long */ int s_toobig; /* File does not fit on one tape*/ int s_isspecial; /* File is special - not dumped */ + /* + * Extract only.... + */ + int s_settime; /* utimes() on file failed */ + int s_setmodes; /* chmod() on file failed */ +#ifdef USE_ACL + int s_badacl; /* ACL could not be converted */ + int s_setacl; /* set ACL for file failed */ +#endif }; extern struct star_stats xstats; -#include +#ifdef HAVE_SYS_PARAM_H +# include +#endif + +/* + * NODEV may be in sys/param.h keep this definition past the include. + */ +#ifndef NODEV +#define NODEV ((dev_t)-1L) +#endif #if !defined(PATH_MAX) && defined(MAXPATHLEN) #define PATH_MAX MAXPATHLEN @@ -446,3 +662,15 @@ #undef PATH_MAX #define PATH_MAX 1024 #endif + +#ifdef HAVE_LARGEFILES +/* + * XXX Hack until fseeko()/ftello() are available everywhere or until + * XXX we know a secure way to let autoconf ckeck for fseeko()/ftello() + * XXX without defining FILE_OFFSETBITS to 64 in confdefs.h + */ +# define fseek fseeko +# define ftell ftello +#endif + +#endif /* _STAR_H */ diff -ruN star-1.3.1/star/star_unix.c star-1.4/star/star_unix.c --- star-1.3.1/star/star_unix.c Mon Apr 30 18:05:50 2001 +++ star-1.4/star/star_unix.c Sat Apr 27 22:25:54 2002 @@ -1,13 +1,13 @@ -/* @(#)star_unix.c 1.28 01/04/30 Copyright 1985, 1995 J. Schilling */ +/* @(#)star_unix.c 1.51 02/04/28 Copyright 1985, 1995, 2001 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)star_unix.c 1.28 01/04/30 Copyright 1985, 1995 J. Schilling"; + "@(#)star_unix.c 1.51 02/04/28 Copyright 1985, 1995, 2001 J. Schilling"; #endif /* * Stat / mode / owner routines for unix like * operating systems * - * Copyright (c) 1985, 1995 J. Schilling + * Copyright (c) 1985, 1995, 2001 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify @@ -26,10 +26,13 @@ */ #include +#ifndef HAVE_UTIMES +#define utimes __nothing__ /* BeOS has no utimes() but wrong prototype */ +#endif #include -#include #include #include "star.h" +#include "props.h" #include "table.h" #include #include @@ -39,6 +42,14 @@ #include #include "dirtime.h" #include "xutimes.h" +#ifdef __linux__ +#include +#include +#include +#endif +#ifndef HAVE_UTIMES +#undef utimes +#endif #include "starsubs.h" #ifndef HAVE_LSTAT @@ -48,14 +59,26 @@ #define lchown chown #endif +#if S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX \ + && S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC \ + && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC \ + && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC + +#define HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */ +#endif +/*#undef HAVE_POSIX_MODE_BITS*/ + #define ROOT_UID 0 extern int uid; -extern Ulong curfs; +extern dev_t curfs; extern BOOL nomtime; extern BOOL nochown; -extern BOOL dirmode; +extern BOOL pflag; extern BOOL follow; +extern BOOL nodump; +extern BOOL doacl; +extern BOOL dofflags; EXPORT BOOL getinfo __PR((char* name, FINFO * info)); EXPORT void checkarch __PR((FILE *f)); @@ -64,6 +87,29 @@ EXPORT int snulltimes __PR((char* name, FINFO *info)); EXPORT int sxsymlink __PR((FINFO *info)); EXPORT int rs_acctime __PR((int fd, FINFO * info)); +#ifndef HAVE_UTIMES +EXPORT int utimes __PR((char *name, struct timeval *tp)); +#endif +#ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */ +#else +LOCAL int dochmod __PR((const char *name, mode_t tarmode)); +#define chmod dochmod +#endif + +#ifdef USE_ACL +/* + * HAVE_ANY_ACL currently includes HAVE_POSIX_ACL and HAVE_SUN_ACL. + * This definition must be in sync with the definition in acl_unix.c + * As USE_ACL is used in star.h, we are not allowed to change the + * value of USE_ACL before we did include star.h or we may not include + * star.h at all. + * HAVE_HP_ACL is currently not included in HAVE_ANY_ACL. + */ +# ifndef HAVE_ANY_ACL +# undef USE_ACL /* Do not try to get or set ACLs */ +# endif +#endif + EXPORT BOOL getinfo(name, info) @@ -77,17 +123,41 @@ info->f_name = name; info->f_uname = info->f_gname = NULL; info->f_umaxlen = info->f_gmaxlen = 0L; - info->f_dev = (Ulong) stbuf.st_dev; - if (curfs == -1L) + info->f_dev = stbuf.st_dev; + if (curfs == NODEV) curfs = info->f_dev; info->f_ino = stbuf.st_ino; info->f_nlink = stbuf.st_nlink; +#ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */ info->f_mode = stbuf.st_mode & 07777; +#else + /* + * The unexpected case when the S_I* OS mode bits do not match + * the T* mode bits from tar. + */ + { register mode_t m = stbuf.st_mode; + + info->f_mode = ((m & S_ISUID ? TSUID : 0) + | (m & S_ISGID ? TSGID : 0) + | (m & S_ISVTX ? TSVTX : 0) + | (m & S_IRUSR ? TUREAD : 0) + | (m & S_IWUSR ? TUWRITE : 0) + | (m & S_IXUSR ? TUEXEC : 0) + | (m & S_IRGRP ? TGREAD : 0) + | (m & S_IWGRP ? TGWRITE : 0) + | (m & S_IXGRP ? TGEXEC : 0) + | (m & S_IROTH ? TOREAD : 0) + | (m & S_IWOTH ? TOWRITE : 0) + | (m & S_IXOTH ? TOEXEC : 0)); + } +#endif info->f_uid = stbuf.st_uid; info->f_gid = stbuf.st_gid; - info->f_size = 0L; - info->f_rsize = 0L; + info->f_size = (off_t)0; /* Size of file */ + info->f_rsize = (off_t)0; /* Size on tape */ info->f_flags = 0L; + info->f_xflags = props.pr_xdflags; + info->f_typeflag= 0; info->f_type = stbuf.st_mode & ~07777; if (sizeof(stbuf.st_rdev) == sizeof(short)) { @@ -104,12 +174,14 @@ info->f_mtime = stbuf.st_mtime; info->f_ctime = stbuf.st_ctime; #ifdef HAVE_ST_SPARE1 /* if struct stat contains st_spare1 (usecs) */ + info->f_flags |= F_NSECS; info->f_ansec = stbuf.st_spare1*1000; info->f_mnsec = stbuf.st_spare2*1000; info->f_cnsec = stbuf.st_spare3*1000; #else #ifdef HAVE_ST_NSEC /* if struct stat contains st_atim.st_nsec (nanosecs */ + info->f_flags |= F_NSECS; info->f_ansec = stbuf.st_atim.tv_nsec; info->f_mnsec = stbuf.st_mtim.tv_nsec; info->f_cnsec = stbuf.st_ctim.tv_nsec; @@ -118,27 +190,169 @@ #endif /* HAVE_ST_NSEC */ #endif /* HAVE_ST_SPARE1 */ +#ifdef HAVE_ST_FLAGS + /* + * The *BSD based method is easy to handle. + */ + if (dofflags) + info->f_fflags = stbuf.st_flags; + else + info->f_fflags = 0L; + if (info->f_fflags != 0) + info->f_xflags |= XF_FFLAGS; +#ifdef UF_NODUMP /* The *BSD 'nodump' flag */ + if ((stbuf.st_flags & UF_NODUMP) != 0) + info->f_flags |= F_NODUMP; /* Convert it to star flag */ +#endif +#else /* !HAVE_ST_FLAGS */ + /* + * The non *BSD case... + */ +#ifdef USE_FFLAGS + if ((nodump || dofflags) && !S_ISLNK(stbuf.st_mode)) { + get_fflags(info); + if (!dofflags) + info->f_xflags &= ~XF_FFLAGS; + } else { + info->f_fflags = 0L; + } +#else + info->f_fflags = 0L; +#endif +#endif + switch ((int)(stbuf.st_mode & S_IFMT)) { - case S_IFREG: + case S_IFREG: /* regular file */ info->f_filetype = F_FILE; + info->f_xftype = XT_FILE; info->f_rsize = info->f_size = stbuf.st_size; + info->f_rdev = 0; + info->f_rdevmaj = 0; + info->f_rdevmin = 0; break; - case S_IFDIR: +#ifdef S_IFCNT + case S_IFCNT: /* contiguous file */ + info->f_filetype = F_FILE; + info->f_xftype = XT_CONT; + info->f_rsize = info->f_size = stbuf.st_size; + info->f_rdev = 0; + info->f_rdevmaj = 0; + info->f_rdevmin = 0; + break; +#endif + case S_IFDIR: /* directory */ info->f_filetype = F_DIR; + info->f_xftype = XT_DIR; + info->f_rdev = 0; + info->f_rdevmaj = 0; + info->f_rdevmin = 0; break; #ifdef S_IFLNK - case S_IFLNK: + case S_IFLNK: /* symbolic link */ info->f_filetype = F_SLINK; + info->f_xftype = XT_SLINK; + info->f_rdev = 0; + info->f_rdevmaj = 0; + info->f_rdevmin = 0; + break; +#endif +#ifdef S_IFCHR + case S_IFCHR: /* character special */ + info->f_filetype = F_SPEC; + info->f_xftype = XT_CHR; + break; +#endif +#ifdef S_IFBLK + case S_IFBLK: /* block special */ + info->f_filetype = F_SPEC; + info->f_xftype = XT_BLK; break; #endif #ifdef S_IFIFO - case S_IFIFO: + case S_IFIFO: /* fifo */ + info->f_filetype = F_SPEC; + info->f_xftype = XT_FIFO; + break; +#endif +#ifdef S_IFSOCK + case S_IFSOCK: /* socket */ + info->f_filetype = F_SPEC; + info->f_xftype = XT_SOCK; + break; +#endif +#ifdef S_IFNAM + case S_IFNAM: /* Xenix named file */ + info->f_filetype = F_SPEC; + + /* + * 'st_rdev' field is really the subtype + * As S_INSEM & S_INSHD we may safely cast + * stbuf.st_rdev to int. + */ + switch ((int)stbuf.st_rdev) { + case S_INSEM: + info->f_xftype = XT_NSEM; + break; + case S_INSHD: + info->f_xftype = XT_NSHD; + break; + default: + info->f_xftype = XT_BAD; + break; + } + break; +#endif +#ifdef S_IFMPC + case S_IFMPC: /* multiplexed character special */ + info->f_filetype = F_SPEC; + info->f_xftype = XT_MPC; + break; +#endif +#ifdef S_IFMPB + case S_IFMPB: /* multiplexed block special */ + info->f_filetype = F_SPEC; + info->f_xftype = XT_MPB; + break; #endif - default: +#ifdef S_IFDOOR + case S_IFDOOR: /* door */ info->f_filetype = F_SPEC; + info->f_xftype = XT_DOOR; + break; +#endif +#ifdef S_IFWHT + case S_IFWHT: /* whiteout */ + info->f_filetype = F_SPEC; + info->f_xftype = XT_WHT; + break; +#endif + + default: /* any other unknown file type */ + if ((stbuf.st_mode & S_IFMT) == 0) { + /* + * If we come here, we either did not yet + * realize that somebody created a new file + * type with a value of 0 or the system did + * return an "unallocated file" with lstat(). + * The latter happens if we are on old Solaris + * systems that did not yet add SOCKETS again. + * if somebody mounted a filesystem that + * has been written with a *BSD system like + * SunOS 4.x and this FS holds a socket we get + * a pseudo unallocated file... + */ + info->f_filetype = F_SPEC; /* ??? */ + info->f_xftype = XT_NONE; + } else { + /* + * We don't know this file type! + */ + info->f_filetype = F_SPEC; + info->f_xftype = XT_BAD; + } } - info->f_xftype = IFTOXT(info->f_type); + info->f_rxftype = info->f_xftype; #ifdef HAVE_ST_BLOCKS #if defined(hpux) || defined(__hpux) @@ -149,6 +363,24 @@ info->f_flags |= F_SPARSE; #endif +#ifdef USE_ACL + /* + * Only look for ACL's if extended headers are allowed with the current + * archive format. Also don't include ACL's if we are creating a Sun + * vendor unique variant of the extended headers. Sun's tar will not + * grok access control lists. + */ + if ((props.pr_flags & PR_XHDR) == 0 || (props.pr_xc != 'x')) + return (TRUE); + + /* + * If we return (FALSE) here, the file would not be archived at all. + * This is not what we want, so ignore return code from get_acls(). + */ + if (doacl) + (void) get_acls(info); +#endif /* USE_ACL */ + return (TRUE); } @@ -157,8 +389,13 @@ FILE *f; { struct stat stbuf; - extern long tape_dev; - extern long tape_ino; + extern dev_t tape_dev; + extern ino_t tape_ino; + extern BOOL tape_isreg; + + tape_isreg = FALSE; + tape_dev = (dev_t)0; + tape_ino = (ino_t)0; if (fstat(fdown(f), &stbuf) < 0) return; @@ -166,13 +403,16 @@ if (S_ISREG(stbuf.st_mode)) { tape_dev = stbuf.st_dev; tape_ino = stbuf.st_ino; + tape_isreg = TRUE; } else if (((stbuf.st_mode & S_IFMT) == 0) || S_ISFIFO(stbuf.st_mode) || S_ISSOCK(stbuf.st_mode)) { /* * This is a pipe or similar on different UNIX implementations. + * (stbuf.st_mode & S_IFMT) == 0 may happen in stange cases. */ - tape_dev = tape_ino = -1; + tape_dev = NODEV; + tape_ino = (ino_t)-1; } } @@ -180,6 +420,8 @@ setmodes(info) register FINFO *info; { + BOOL didutimes = FALSE; + if (!nomtime && !is_symlink(info)) { /* * With Cygwin32, @@ -187,20 +429,62 @@ * We set the time before we change the access modes to * overcode this problem. */ - if (!is_dir(info)) - sutimes(info->f_name, info); + if (!is_dir(info)) { + didutimes = TRUE; + if (sutimes(info->f_name, info) < 0) + xstats.s_settime++; + } } - if ((!is_dir(info) || dirmode) && !is_symlink(info)) + +#ifndef NEW_P_FLAG + if ((!is_dir(info) || pflag) && !is_symlink(info)) { if (chmod(info->f_name, (int)info->f_mode) < 0) { - ; + xstats.s_setmodes++; } + } +#ifdef USE_ACL + if (pflag && !is_symlink(info)) { + /* + * If there are no additional ACLs, set_acls() will + * simply do a fast return. + */ + if (doacl) + set_acls(info); + } +#endif + if (dofflags && !is_symlink(info)) + set_fflags(info); +#else +/* XXX Checken! macht die Aenderung des Verhaltens von -p Sinn? */ + + if (pflag && !is_symlink(info)) { + if (chmod(info->f_name, (int)info->f_mode) < 0) { + xstats.s_setmodes++; + } +#ifdef USE_ACL + /* + * If there are no additional ACLs, set_acls() will + * simply do a fast return. + */ + if (doacl) + set_acls(info); +#endif + } + if (dofflags && !is_symlink(info)) + set_fflags(info); +#endif if (!nochown && uid == ROOT_UID) { /* * Star will not allow non root users to give away files. */ lchown(info->f_name, (int)info->f_uid, (int)info->f_gid); - if ((!is_dir(info) || dirmode) && !is_symlink(info) && +#ifndef NEW_P_FLAG + if ((!is_dir(info) || pflag) && !is_symlink(info) && +#else +/* XXX Checken! macht die Aenderung des Verhaltens von -p Sinn? */ + if (pflag && !is_symlink(info) && +#endif (info->f_mode & 07000) != 0) { /* * On a few systems, seeting the owner of a file @@ -208,15 +492,22 @@ * We repeat the chmod() in this case. */ if (chmod(info->f_name, (int)info->f_mode) < 0) { + /* + * Do not increment chmod() errors here, + * it did already fail above. + */ + /* EMPTY */ ; } } } if (!nomtime && !is_symlink(info)) { - if (is_dir(info)) + if (is_dir(info)) { sdirtimes(info->f_name, info); - else - sutimes(info->f_name, info); + } else { + if (sutimes(info->f_name, info) < 0 && !didutimes) + xstats.s_settime++; + } } } @@ -266,6 +557,10 @@ int ret; int errsav; +#ifndef HAVE_SETTIMEOFDAY +#undef SET_CTIME +#endif + #ifdef SET_CTIME if (Ctime) { gettimeofday(&curtime, 0); @@ -273,7 +568,7 @@ } #endif ret = utimes(name, tp); - errsav = errno; + errsav = geterrno(); #ifdef SET_CTIME if (Ctime) { @@ -285,10 +580,10 @@ curtime.tv_usec -= 1000000; } settimeofday(&curtime, 0); -/* printf("pasttime.usec: %d\n", pasttime.tv_usec);*/ +/* error("pasttime.usec: %d\n", pasttime.tv_usec);*/ } #endif - errno = errsav; + seterrno(errsav); return (ret); } @@ -324,7 +619,7 @@ } #endif ret = symlink(linkname, name); - errsav = errno; + errsav = geterrno(); #ifdef SET_CTIME if (Ctime) { @@ -336,10 +631,10 @@ curtime.tv_usec -= 1000000; } settimeofday(&curtime, 0); -/* printf("pasttime.usec: %d\n", pasttime.tv_usec);*/ +/* error("pasttime.usec: %d\n", pasttime.tv_usec);*/ } #endif - errno = errsav; + seterrno(errsav); return (ret); } @@ -373,7 +668,10 @@ } #ifndef HAVE_UTIMES + +#define utimes __nothing__ /* BeOS has no utimes() but wrong prototype */ #include +#undef utimes EXPORT int utimes(name, tp) @@ -387,5 +685,32 @@ ut.modtime = tp->tv_sec; return (utime(name, &ut)); +} +#endif + +#ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */ +#else +#undef chmod +LOCAL int +dochmod(name, tarmode) + register const char *name; + register mode_t tarmode; +{ + register mode_t osmode; + + osmode = ((tarmode & TSUID ? S_ISUID : 0) + | (tarmode & TSGID ? S_ISGID : 0) + | (tarmode & TSVTX ? S_ISVTX : 0) + | (tarmode & TUREAD ? S_IRUSR : 0) + | (tarmode & TUWRITE ? S_IWUSR : 0) + | (tarmode & TUEXEC ? S_IXUSR : 0) + | (tarmode & TGREAD ? S_IRGRP : 0) + | (tarmode & TGWRITE ? S_IWGRP : 0) + | (tarmode & TGEXEC ? S_IXGRP : 0) + | (tarmode & TOREAD ? S_IROTH : 0) + | (tarmode & TOWRITE ? S_IWOTH : 0) + | (tarmode & TOEXEC ? S_IXOTH : 0)); + + return (chmod(name, osmode)); } #endif diff -ruN star-1.3.1/star/starsubs.h star-1.4/star/starsubs.h --- star-1.3.1/star/starsubs.h Sun Nov 12 16:24:47 2000 +++ star-1.4/star/starsubs.h Mon May 20 10:48:33 2002 @@ -1,4 +1,5 @@ -/* @(#)starsubs.h 1.14 00/11/12 Copyright 1996 J. Schilling */ + +/* @(#)starsubs.h 1.24 02/05/20 Copyright 1996 J. Schilling */ /* * Prototypes for star subroutines * @@ -22,13 +23,19 @@ #include +#ifndef _INCL_SYS_TYPES_H +#include +#define _INCL_SYS_TYPES_H +#endif + /* * star.c */ extern int main __PR((int ac, char** av)); extern const char *filename __PR((const char* name)); extern BOOL match __PR((const char* name)); -extern void *__malloc __PR((unsigned int size)); +extern void *__malloc __PR((size_t size, char *msg)); +extern void *__realloc __PR((void *ptr, size_t size, char *msg)); extern char *__savestr __PR((char *s)); /* @@ -44,6 +51,8 @@ extern void syncbuf __PR((void)); extern int readblock __PR((char* buf)); extern int readtape __PR((char* buf, int amount)); +extern void filltcb __PR((TCB *ptb)); +extern void movetcb __PR((TCB *from_ptb, TCB *to_ptb)); extern void *get_block __PR((void)); extern void put_block __PR((void)); extern void writeblock __PR((char* buf)); @@ -59,8 +68,8 @@ extern void buf_resume __PR((void)); extern void backtape __PR((void)); extern int mtioctl __PR((int cmd, int count)); -extern long mtseek __PR((long offset, int whence)); -extern int tblocks __PR((void)); +extern off_t mtseek __PR((off_t offset, int whence)); +extern Llong tblocks __PR((void)); extern void prstats __PR((void)); extern BOOL checkerrs __PR((void)); extern void exprstats __PR((int ret)); @@ -134,6 +143,8 @@ /* * header.c */ +extern int get_hdrtype __PR((TCB * ptb, BOOL isrecurse)); +extern int get_compression __PR((TCB * ptb)); extern int get_tcb __PR((TCB * ptb)); extern void put_tcb __PR((TCB * ptb, FINFO * info)); extern void write_tcb __PR((TCB * ptb, FINFO * info)); @@ -142,9 +153,15 @@ extern void info_to_tcb __PR((register FINFO * info, register TCB * ptb)); extern int tcb_to_info __PR((register TCB * ptb, register FINFO * info)); extern BOOL ia_change __PR((TCB * ptb, FINFO * info)); -extern void astoo_cpio __PR((register char* s, Ulong * l, register int cnt)); -extern void astoo __PR((register char* s, Ulong * l)); -extern void otoa __PR((char* s, register Ulong l, register int fieldw)); +extern void stolli __PR((register char* s, Ullong * ull)); +extern void llitos __PR((char* s, Ullong ull, int fieldw)); + +/* + * xheader.c + */ +extern void xbinit __PR((void)); +extern void info_to_xhdr __PR((FINFO * info, TCB * ptb)); +extern int tcb_to_xhdr __PR((TCB * ptb, FINFO * info)); /* * hole.c @@ -161,7 +178,7 @@ * lhash.c */ #ifdef EOF -extern void hash_build __PR((FILE * fp, unsigned int size)); +extern void hash_build __PR((FILE * fp, size_t size)); #endif extern BOOL hash_lookup __PR((char* str)); @@ -196,6 +213,11 @@ extern void printprops __PR((void)); /* + * remove.c + */ +extern BOOL remove_file __PR((char* name, BOOL isfirst)); + +/* * star_unix.c */ extern BOOL getinfo __PR((char* name, FINFO * info)); @@ -206,3 +228,23 @@ extern int snulltimes __PR((char* name, FINFO * info)); extern int sxsymlink __PR((FINFO * info)); extern int rs_acctime __PR((int fd, FINFO * info)); + +/* + * acl_unix.c + */ +extern BOOL get_acls __PR((FINFO *info)); +extern void set_acls __PR((FINFO *info)); + +/* + * unicode.c + */ +extern void to_utf8 __PR((Uchar *to, Uchar *from)); +extern BOOL from_utf8 __PR((Uchar *to, Uchar *from)); + +/* + * fflags.c + */ +extern void get_fflags __PR((FINFO *info)); +extern void set_fflags __PR((FINFO *info)); +extern char *textfromflags __PR((FINFO *info, char *buf)); +extern int texttoflags __PR((FINFO *info, char *buf)); diff -ruN star-1.3.1/star/table.c star-1.4/star/table.c --- star-1.3.1/star/table.c Wed Jun 26 09:05:51 1996 +++ star-1.4/star/table.c Thu May 9 15:33:20 2002 @@ -1,7 +1,7 @@ -/* @(#)table.c 1.7 96/06/26 Copyright 1994 J. Schilling */ +/* @(#)table.c 1.16 02/05/09 Copyright 1994 J. Schilling */ #ifndef lint static char sccsid[] = - "@(#)table.c 1.7 96/06/26 Copyright 1994 J. Schilling"; + "@(#)table.c 1.16 02/05/09 Copyright 1994 J. Schilling"; #endif /* * Conversion tables for efficient conversion @@ -25,16 +25,29 @@ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include "star.h" #include "table.h" -#include +#include #ifndef S_IFIFO /* If system knows no fifo's */ #define S_IFIFO S_IFREG /* Map fifo's to regular files */ #endif +#ifndef S_IFCHR /* If system knows no character special */ +#define S_IFCHR S_IFREG /* Map character spec. to regular files */ +#endif +#ifndef S_IFMPC /* If system knows no multiplexed c */ +#define S_IFMPC S_IFREG /* Map multiplexed c to regular files */ +#endif #ifndef S_IFNAM /* If system knows no named files */ #define S_IFNAM S_IFREG /* Map named files to regular files */ #endif +#ifndef S_IFBLK /* If system knows no block special */ +#define S_IFBLK S_IFREG /* Map block spec. to regular files */ +#endif +#ifndef S_IFMPB /* If system knows no multiplexed b */ +#define S_IFMPB S_IFREG /* Map multiplexed b to regular files */ +#endif #ifndef S_IFCNT /* If system knows no contiguous files */ #define S_IFCNT S_IFREG /* Map contiguous file to regular files */ #endif @@ -44,6 +57,15 @@ #ifndef S_IFSOCK /* If system knows no fifo's */ #define S_IFSOCK S_IFREG /* Map fifo's to regular files */ #endif +#ifndef S_IFDOOR /* If system knows no door's */ +#define S_IFDOOR S_IFREG /* Map door's to regular files */ +#endif +#ifndef S_IFWHT /* If system knows no whiteout's */ +#define S_IFWHT S_IFREG /* Map whiteout's to regular files */ +#endif +#ifndef S_IFEVC /* If system knows no eventcount's */ +#define S_IFEVC S_IFREG /* Map eventcount's to regular files */ +#endif #define S_IFBAD S_IFMT /* XXX Have to use another val if someone */ /* XXX starts to use S_IFMT for a */ /* XXX useful file type */ @@ -53,51 +75,86 @@ /* * UNIX File type to XT_ table + * + * Maps the 16 UNIX (S_XXX >> 12) filetypes to star's internal XT_ types. + * Note that this only works if all S_XXX defines are the same on all + * UNIX versions. Fortunately, this is currently the case and there is no + * big chance that somebody will do it differently. + * + * XXX If really somebody creates a different OS we will need to change this + * XXX table and the associated macros or make this table dynamically + * XXX created at startup of star. + * + * UNIX file types (see table.h): + * 0 Unallocated 1 FIFO 2 Chr special 3 MPX chr + * 4 Directory 5 NAM special 6 BLK special 7 MPX blk + * 8 Regular File 9 Contig File 10 Symlink 11 Sol Shadow ino + * 12 Socket 13 DOOR special 14 Whiteout 15 UNOS event count + * + * No bound checking in hope that S_IFMT will never hold more than 4 bits. */ -char iftoxt_tab[] = { - XT_NONE, XT_FIFO, XT_CHR, XT_BAD, - XT_DIR, XT_NAM, XT_BLK, XT_BAD, - XT_FILE, XT_CONT, XT_SLINK, XT_BAD, - XT_SOCK, XT_BAD, XT_BAD, XT_BAD, +char iftoxt_tab[] = { + /* 0 */ XT_NONE, XT_FIFO, XT_CHR, XT_MPC, + /* 4 */ XT_DIR, XT_NAM, XT_BLK, XT_MPB, + /* 8 */ XT_FILE, XT_CONT, XT_SLINK, XT_BAD, + /*12 */ XT_SOCK, XT_DOOR, XT_WHT, XT_BAD, }; /* * Ustar File type to XT_ table + * + * Maps the ustar 0..7 filetypes to star's internal XT_ types. + * Bound checking is done via ustoxt(). */ char ustoxt_tab[] = { - XT_FILE, XT_LINK, XT_SLINK, XT_CHR, - XT_BLK, XT_DIR, XT_FIFO, XT_CONT, + /* 0 */ XT_FILE, XT_LINK, XT_SLINK, XT_CHR, + /* 4 */ XT_BLK, XT_DIR, XT_FIFO, XT_CONT, + /* 8 */ XT_BAD, XT_BAD, }; /* - * Gnutar File type to XT_ table + * Vendor unique File type to XT_ table + * + * Maps the filetypes 'A'..'Z' to star's internal XT_ types. + * Fortunately, the different vendor unique extensions are disjunct. + * External code does bound checking. */ -char gttoxt_tab[] = { +char vttoxt_tab[] = { /* A */ XT_NONE, XT_NONE, XT_NONE, XT_DUMPDIR, /* E */ XT_NONE, XT_NONE, XT_NONE, XT_NONE, - /* I */ XT_NONE, XT_NONE, XT_LONGLINK, XT_LONGNAME, + /* I */ XT_META, XT_NONE, XT_LONGLINK, XT_LONGNAME, /* M */ XT_MULTIVOL, XT_NAMES, XT_NONE, XT_NONE, /* Q */ XT_NONE, XT_NONE, XT_SPARSE, XT_NONE, /* U */ XT_NONE, XT_VOLHDR, XT_NONE, XT_NONE, - /* Y */ XT_NONE, XT_NONE, + /* Y */ XT_NONE, XT_NONE, }; + +/* + * XT_* codes used (see table.h): + * 0..16 Real file types and hard links + * 20..26 Speudo file types (POSIX 'A' .. 'Z' + * 31 XT_BAD (illegal file type) + */ + /* * XT_ to UNIX File type table + * + * XT_SPARSE and XT_META are just other (tar specific) views of regular files. */ int xttoif_tab[] = { - 0, S_IFREG, S_IFCNT, S_IFREG, - S_IFLNK, S_IFDIR, S_IFCHR, S_IFBLK, - S_IFIFO, S_IFSOCK, S_IFBAD, S_IFBAD, - S_IFBAD, S_IFBAD, S_IFBAD, S_IFBAD, - S_IFBAD, S_IFBAD, S_IFBAD, S_IFBAD, - S_IFDIR, S_IFBAD, S_IFBAD, S_IFBAD, - S_IFBAD, S_IFBAD, S_IFBAD, S_IFBAD, - S_IFBAD, S_IFBAD, S_IFBAD, S_IFBAD, + /* 0 */ 0, S_IFREG, S_IFCNT, S_IFREG, + /* 4 */ S_IFLNK, S_IFDIR, S_IFCHR, S_IFBLK, + /* 8 */ S_IFIFO, S_IFSOCK, S_IFMPC, S_IFMPB, + /*12 */ S_IFNAM, S_IFNAM, S_IFDOOR, S_IFEVC, + /*16 */ S_IFWHT, S_IFBAD, S_IFBAD, S_IFBAD, + /*20 */ S_IFDIR, S_IFBAD, S_IFBAD, S_IFBAD, + /*24 */ S_IFBAD, S_IFREG, S_IFBAD, S_IFREG, + /*28 */ S_IFBAD, S_IFBAD, S_IFBAD, S_IFBAD, }; /* - * XT_ to Star File type table + * XT_ to Star-1985 File type table */ char xttost_tab[] = { /* 0 */ 0, F_FILE, F_FILE, F_FILE, @@ -106,24 +163,80 @@ /*12 */ F_SPEC, F_SPEC, F_SPEC, F_SPEC, /*16 */ F_SPEC, F_SPEC, F_SPEC, F_SPEC, /*20 */ F_DIR, F_FILE, F_FILE, F_FILE, - /*24 */ F_FILE, F_FILE, F_SPEC, F_SPEC, + /*24 */ F_FILE, F_FILE, F_SPEC, F_FILE, /*28 */ F_SPEC, F_SPEC, F_SPEC, F_SPEC, }; /* - * XT_ to Ustar File type table + * XT_ Old tar supported File type table + */ +char xttar_tab[] = { + /* 0 */ 0, 1, 1, 1, + /* 4 */ 1, 1, 0, 0, + /* 8 */ 0, 0, 0, 0, + /*12 */ 0, 0, 0, 0, + /*16 */ 0, 0, 0, 0, + /*20 */ 0, 0, 0, 0, + /*24 */ 0, 0, 0, 0, + /*28 */ 0, 0, 0, 0, + }; +/* + * XT_ Star-1985 supported File type table + */ +char xtstar_tab[] = { + /* 0 */ 0, 1, 1, 1, + /* 4 */ 1, 1, 1, 1, + /* 8 */ 1, 1, 1, 1, + /*12 */ 1, 1, 1, 0, + /*16 */ 0, 0, 0, 0, + /*20 */ 0, 0, 0, 0, + /*24 */ 0, 1, 0, 1, + /*28 */ 0, 0, 0, 0, + }; +/* + * XT_ Ustar-1988 supported File type table + */ +char xtustar_tab[] = { + /* 0 */ 0, 1, 1, 1, + /* 4 */ 1, 1, 1, 1, + /* 8 */ 1, 0, 0, 0, + /*12 */ 0, 0, 0, 0, + /*16 */ 0, 0, 0, 0, + /*20 */ 0, 0, 0, 0, + /*24 */ 0, 0, 0, 0, + /*28 */ 0, 0, 0, 0, + }; + + +/* + * XT_ Extended PAX-2001 'exustar' supported File type table + */ +char xtexustar_tab[] = { + /* 0 */ 0, 1, 1, 1, + /* 4 */ 1, 1, 1, 1, + /* 8 */ 1, 1, 0, 0, + /*12 */ 0, 0, 1, 0, + /*16 */ 0, 0, 0, 0, + /*20 */ 0, 0, 0, 0, + /*24 */ 0, 1, 0, 1, + /*28 */ 0, 0, 0, 0, + }; + + +/* + * XT_ to Ustar (including Vendor Unique extensions) File type table * * sockets cannot be handled in ansi tar, they are handled as regular files :-( */ char xttous_tab[] = { - 0, REGTYPE, CONTTYPE, LNKTYPE, - SYMTYPE, DIRTYPE, CHRTYPE, BLKTYPE, - FIFOTYPE,REGTYPE/* socket */, 0/* bad */, 0/* bad */, - 0, 0, 0, 0, - 0, 0, 0, 0, - LF_DUMPDIR, LF_LONGLINK, LF_LONGNAME, LF_MULTIVOL, - LF_NAMES, LF_SPARSE, LF_VOLHDR, 0, - 0, 0, 0, 0, + /* 0 */ 0, REGTYPE, CONTTYPE, LNKTYPE, + /* 4 */ SYMTYPE, DIRTYPE, CHRTYPE, BLKTYPE, + /* 8 */ FIFOTYPE,REGTYPE/* socket */, 0/* bad */, 0/* bad */, + /*12 */ 0, 0, 0, 0, + /*16 */ 0, 0, 0, 0, + /*20 */ LF_DUMPDIR, LF_LONGLINK, LF_LONGNAME, LF_MULTIVOL, + /*24 */ LF_NAMES, LF_SPARSE, LF_VOLHDR, LF_META, + /*28 */ 0, 0, 0, 0, }; /* @@ -132,21 +245,36 @@ char *xttostr_tab[] = { #define XT_DEBUG #ifdef XT_DEBUG - "U", "-", "C", "H", + /* 0 */ "U", "-", "C", "H", #else - "-", "-", "-", "-", + /* 0 */ "-", "-", "-", "-", #endif - "l", "d", "c", "b", - "p", "s", "~", "~", - "~", "~", "~", "~", - "~", "~", "~", "~", + /* 4 */ "l", "d", "c", "b", + /* 8 */ "p", "s", "~", "~", + /*12 */ "~", "~", "D", "~", + /*16 */ "%", "~", "~", "~", - "D", "K", "L", "M", + /*20 */ "D", "K", "L", "M", #ifdef XT_DEBUG - "N", "S", "V", "~", + /*24 */ "N", "S", "V", "m", #else - "N", "-", "V", "~", + /*24 */ "N", "-", "V", "-", #endif - "~", "~", "~", "~", + /*28 */ "~", "~", "~", "~", }; + +/* + * XT_ to named file type text + */ +char *xttoname_tab[] = { + /* 0 */ "unallocated", "regular", "contiguous", "hardlink", + /* 4 */ "symlink", "directory", "character special", "block special", + /* 8 */ "fifo", "socket", "mpx character special","mpx block special", + /*12 */ "XENIX nsem", "XENIX nshd", "door", "eventcount", + /*16 */ "whiteout", "reserved", "reserved", "reserved", + /*20 */ "dumpdir", "longlink", "longname", "multivol continuation", + /*24 */ "names", "sparse", "volheader", "meta", + /*28 */ "reserved", "reserved", "reserved", "unknown/bad", + }; + diff -ruN star-1.3.1/star/table.h star-1.4/star/table.h --- star-1.3.1/star/table.h Wed Jun 26 09:05:51 1996 +++ star-1.4/star/table.h Thu May 9 15:25:26 2002 @@ -1,4 +1,4 @@ -/* @(#)table.h 1.4 96/06/26 Copyright 1994 J. Schilling */ +/* @(#)table.h 1.8 02/05/09 Copyright 1994 J. Schilling */ /* * Conversion table definitions for efficient conversion * of different file type representations @@ -39,8 +39,11 @@ S_IFSHAD 0130000 /* Solaris shadow inode */ S_IFSOCK 0140000 SOCK /* UNIX domain socket */ S_IFDOOR 0150000 /* Solaris DOOR */ - 0160000 /* UNUSED cpio acl */ - 0170000 /* UNUSED */ +S_IFWHT 0160000 /* BSD whiteout */ + 0160200 /* Solaris cpio acl */ + 0170000 /* UNUSED on UNIX */ +S_IFEVC 0170000 /* UNOS event count */ + /* UNOS/UNIX compat only*/ #endif /* @@ -60,6 +63,13 @@ #define XT_BLK 7 /* block special */ #define XT_FIFO 8 /* fifo (named pipe) */ #define XT_SOCK 9 /* unix domain socket */ +#define XT_MPC 10 /* multiplexed character special */ +#define XT_MPB 11 /* multiplexed block special */ +#define XT_NSEM 12 /* XENIX named semaphore */ +#define XT_NSHD 13 /* XENIX named shared data */ +#define XT_DOOR 14 /* Solaris DOOR */ +#define XT_EVENT 15 /* UNOS Event Count */ +#define XT_WHT 16 /* BSD whiteout */ /* ... Reserved ... */ #define XT_DUMPDIR 20 /* Dir entry containing filenames */ #define XT_LONGLINK 21 /* Next file on tape has a long link */ @@ -68,23 +78,32 @@ #define XT_NAMES 24 /* OLD */ #define XT_SPARSE 25 /* for files with holes in it */ #define XT_VOLHDR 26 /* Tape Volume header */ +#define XT_META 27 /* Inode meta data only */ #define XT_BAD 31 /* illegal file type */ extern char iftoxt_tab[]; extern char ustoxt_tab[]; -extern char gttoxt_tab[]; +extern char vttoxt_tab[]; extern int xttoif_tab[]; extern char xttost_tab[]; extern char xttous_tab[]; + +extern char xttar_tab[]; +extern char xtstar_tab[]; +extern char xtustar_tab[]; +extern char xtexustar_tab[]; + extern char *xttostr_tab[]; +extern char *xttoname_tab[]; #define IFTOXT(t) (iftoxt_tab[((t)&S_IFMT) >> 12])/* UNIX to XT */ #define USTOXT(t) (ustoxt(t)) /* ustar to XT */ #define _USTOXT(t) (ustoxt_tab[(t)-REGTYPE]) /* ustar to XT */ -#define _GTTOXT(t) (gttoxt_tab[(t)-'A']) /* gnutar to XT */ +#define _VTTOXT(t) (vttoxt_tab[(t)-'A']) /* vendor to XT */ #define XTTOIF(t) (xttoif_tab[(t)]) /* XT to UNIX */ #define XTTOST(t) (xttost_tab[(t)]) /* XT to star */ #define XTTOUS(t) (xttous_tab[(t)]) /* XT to ustar */ -#define XTTOSTR(t) (xttostr_tab[(t)]) /* XT to string */ +#define XTTOSTR(t) (xttostr_tab[(t)]) /* XT to string */ +#define XTTONAME(t) (xttoname_tab[(t)]) /* XT to name */ diff -ruN star-1.3.1/star/unicode.c star-1.4/star/unicode.c --- star-1.3.1/star/unicode.c Thu Jan 1 01:00:00 1970 +++ star-1.4/star/unicode.c Fri Aug 17 22:54:29 2001 @@ -0,0 +1,108 @@ +/* @(#)unicode.c 1.2 01/08/17 Copyright 2001 J. Schilling */ +#ifndef lint +static char sccsid[] = + "@(#)unicode.c 1.2 01/08/17 Copyright 2001 J. Schilling"; +#endif +/* + * Routines to convert from/to UNICODE + * + * This is currently a very simple implementation that only + * handles ISO-8859-1 coding. There should be a better solution + * in the future. + * + * Copyright (c) 2001 J. Schilling + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "star.h" +#include +#include +#include "starsubs.h" + +EXPORT void to_utf8 __PR((Uchar *to, Uchar *from)); +EXPORT BOOL from_utf8 __PR((Uchar *to, Uchar *from)); + +EXPORT void +to_utf8(to, from) + register Uchar *to; + register Uchar *from; +{ + register Uchar c; + + while ((c = *from++) != '\0') { + if (c <= 0x7F) { + *to++ = c; + } else if (c <= 0xBF) { + *to++ = 0xC2; + *to++ = c; + } else { /*c <= 0xFF */ + *to++ = 0xC3; + *to++ = c & 0xBF; + } + } + *to = '\0'; +} + +EXPORT BOOL +from_utf8(to, from) + register Uchar *to; + register Uchar *from; +{ + register Uchar c; + register BOOL ret = TRUE; + + while ((c = *from++) != '\0') { + if (c <= 0x7F) { + *to++ = c; + } else if (c == 0xC0) { + *to++ = *from++ & 0x7F; + } else if (c == 0xC1) { + *to++ = (*from++ | 0x40) & 0x7F; + } else if (c == 0xC2) { + *to++ = *from++; + } else if (c == 0xC3) { + *to++ = *from++ | 0x40; + } else { + ret = FALSE; /* unknown/illegal UTF-8 char*/ + *to++ = '_'; /* use default character */ + if (c < 0xE0) { + from++; /* 2 bytes in total */ + } else if (c < 0xF0) { + from += 2; /* 3 bytes in total */ + } else if (c < 0xF8) { + from += 3; /* 4 bytes in total */ + } else if (c < 0xFC) { + from += 4; /* 5 bytes in total */ + } else if (c < 0xFE) { + from += 5; /* 6 bytes in total */ + } else { + while ((c = *from) != '\0') { + /* + * Test for 7 bit ASCII + non prefix + */ + if (c <= 0xBF) + break; + from++; + } + } + } + } + *to = '\0'; + return (ret); +} diff -ruN star-1.3.1/star/xheader.c star-1.4/star/xheader.c --- star-1.3.1/star/xheader.c Thu Jan 1 01:00:00 1970 +++ star-1.4/star/xheader.c Fri May 17 11:26:32 2002 @@ -0,0 +1,923 @@ +/* @(#)xheader.c 1.12 02/05/17 Copyright 2001 J. Schilling */ +#ifndef lint +static char sccsid[] = + "@(#)xheader.c 1.12 02/05/17 Copyright 2001 J. Schilling"; +#endif +/* + * Handling routines to read/write, parse/create + * POSIX.1-2001 extended archive headers + * + * Copyright (c) 2001 J. Schilling + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include "star.h" +#include "props.h" +#include "table.h" +#include +#include +#include +#define __XDEV__ /* Needed to activate _dev_major()/_dev_minor() */ +#include +#include +#include "starsubs.h" +#include "movearch.h" + +#define MAX_UNAME 64 /* The maximum length of a user/group name */ + +typedef void (*function) __PR((FINFO *, char *, char *)); + +typedef struct { + char *x_name; + function x_func; + int x_flag; +} xtab_t; + +EXPORT void xbinit __PR((void)); +LOCAL void xbgrow __PR((int newsize)); +EXPORT void info_to_xhdr __PR((FINFO * info, TCB * ptb)); +LOCAL void gen_xtime __PR((char *keyword, time_t sec, Ulong nsec)); +LOCAL void gen_number __PR((char *keyword, Llong arg)); +LOCAL void gen_text __PR((char *keyword, char *arg, BOOL addslash)); +LOCAL xtab_t *lookup __PR((char *cmd, xtab_t *cp)); +EXPORT int tcb_to_xhdr __PR((TCB * ptb, FINFO * info)); +LOCAL BOOL get_xtime __PR((char *keyword, char *arg, time_t *secp, + Ulong *nsecp)); +LOCAL void get_atime __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_ctime __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_mtime __PR((FINFO *info, char *keyword, char *arg)); +LOCAL BOOL get_number __PR((char *keyword, char *arg, Llong *llp)); +LOCAL void get_uid __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_gid __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_uname __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_gname __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_path __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_lpath __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_size __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_major __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_minor __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_dev __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_ino __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_nlink __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_filetype __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_acl_access __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_acl_default __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_xfflags __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void get_dummy __PR((FINFO *info, char *keyword, char *arg)); +LOCAL void bad_utf8 __PR((char *keyword, char *arg)); + +LOCAL char *xbuf; /* Space used to prepare I/O from/to extended headers */ +LOCAL int xblen; /* the length of the buffer for the extended headers */ +LOCAL int xbidx; /* The index where we start to prepare next entry */ + +LOCAL xtab_t xtab[] = { + { "atime", get_atime, 0 }, + { "ctime", get_ctime, 0 }, + { "mtime", get_mtime, 0 }, + + { "uid", get_uid, 0 }, + { "uname", get_uname, 0 }, + { "gid", get_gid, 0 }, + { "gname", get_gname, 0 }, + + { "path", get_path, 0 }, + { "linkpath", get_lpath, 0 }, + + { "size", get_size, 0 }, + + { "charset", get_dummy, 0 }, + { "comment", get_dummy, 0 }, + + { "SCHILY.devmajor", get_major, 0 }, + { "SCHILY.devminor", get_minor, 0 }, + +#ifdef USE_ACL + { "SCHILY.acl.access", get_acl_access, 0 }, + { "SCHILY.acl.default", get_acl_default,0 }, +#else +/* + * We don't want star to complain about unknown extended headers when it + * has been compiled without ACL support. + */ + { "SCHILY.acl.access", get_dummy, 0 }, + { "SCHILY.acl.default", get_dummy, 0 }, +#endif + +#ifdef USE_FFLAGS + { "SCHILY.fflags", get_xfflags, 0 }, +#else +/* + * We don't want star to complain about unknown extended headers when it + * has been compiled without extended file flag support. + */ + { "SCHILY.fflags", get_dummy, 0 }, +#endif + { "SCHILY.dev", get_dev, 0 }, + { "SCHILY.ino", get_ino, 0 }, + { "SCHILY.nlink", get_nlink, 0 }, + { "SCHILY.filetype", get_filetype, 0 }, + { "SCHILY.tarfiletype", get_filetype, 0 }, + + { "SUN.devmajor", get_major, 0 }, + { "SUN.devminor", get_minor, 0 }, + + { NULL, NULL, 0 }}; + +/* + * Initialize the growable buffer used for reading the extended headers + */ +EXPORT void +xbinit() +{ + xbuf = __malloc(1, "growable xheader"); + xblen = 1; +} + +/* + * Grow the growable buffer used for reading the extended headers + */ +LOCAL void +xbgrow(newsize) + int newsize; +{ + char *newbuf; + int i; + + /* + * grow in 1k units + */ + for (i = 0; i < newsize; i += 1024) + ; + newsize = i + xblen; + newbuf = __realloc(xbuf, newsize, "growable xheader"); + xbuf = newbuf; + xblen = newsize; +} + +/* + * Prepare and write out the extended header + */ +EXPORT void +info_to_xhdr(info, ptb) + register FINFO *info; + register TCB *ptb; +{ + FINFO finfo; + TCB *xptb; + move_t move; + char name[MAX_UNAME+1]; +extern long hdrtype; +extern BOOL dodump; + + fillbytes((char *)&finfo, sizeof(finfo), '\0'); + + /* + * Unless we really don't want extended sub-second resolution + * timestamps or a specific selection of timestams has been set up, + * include all times (atime/ctime/mtime) if we need to include extended + * headers at all. + */ + if ((info->f_xflags & (XF_ATIME|XF_CTIME|XF_MTIME|XF_NOTIME)) == 0) + info->f_xflags |= (XF_ATIME|XF_CTIME|XF_MTIME); + +/*#define DEBUG_XHDR*/ +#ifdef DEBUG_XHDR + info->f_xflags = 0xffffffff; +#endif + + xbidx = 0; /* Reset xbuffer index to start of buffer. */ + + if (info->f_xflags & XF_ATIME) + gen_xtime("atime", info->f_atime, info->f_ansec); + if (info->f_xflags & XF_CTIME) + gen_xtime("ctime", info->f_ctime, info->f_cnsec); + if (info->f_xflags & XF_MTIME) + gen_xtime("mtime", info->f_mtime, info->f_mnsec); + + if (info->f_xflags & XF_UID) + gen_number("uid", (Llong)info->f_uid); + if (info->f_xflags & XF_GID) + gen_number("gid", (Llong)info->f_gid); + + if (info->f_xflags & XF_UNAME) { + nameuid(name, sizeof(name)-1, info->f_uid); + gen_text("uname", name, FALSE); + } + if (info->f_xflags & XF_GNAME) { + namegid(name, sizeof(name)-1, info->f_gid); + gen_text("gname", name, FALSE); + } + + if (info->f_xflags & XF_PATH) + gen_text("path", info->f_name, + (info->f_flags & F_ADDSLASH) != 0); + if (info->f_xflags & XF_LINKPATH && info->f_lnamelen) + gen_text("linkpath", info->f_lname, FALSE); + + if (info->f_xflags & XF_SIZE) + gen_number("size", (Llong)info->f_size); + + if (H_TYPE(hdrtype) == H_SUNTAR) { + if (info->f_xflags & XF_DEVMAJOR) + gen_number("SUN.devmajor", (Llong)info->f_rdevmaj); + if (info->f_xflags & XF_DEVMINOR) + gen_number("SUN.devminor", (Llong)info->f_rdevmin); + } else { + if (info->f_xflags & XF_DEVMAJOR) + gen_number("SCHILY.devmajor", (Llong)info->f_rdevmaj); + if (info->f_xflags & XF_DEVMINOR) + gen_number("SCHILY.devminor", (Llong)info->f_rdevmin); + } + +#ifdef USE_ACL + /* + * POSIX Access Control Lists, currently supported e.g. by Linux. + * Solaris ACLs have been converted to POSIX before. + */ + if (info->f_xflags & XF_ACL_ACCESS) { + gen_text("SCHILY.acl.access", info->f_acl_access, FALSE); + } + + if (info->f_xflags & XF_ACL_DEFAULT) { + gen_text("SCHILY.acl.default", info->f_acl_default, FALSE); + } +#endif /* USE_ACL */ + +#ifdef USE_FFLAGS + if (info->f_xflags & XF_FFLAGS) { +extern char *textfromflags __PR((FINFO *, char *)); + + char fbuf[512]; + gen_text("SCHILY.fflags", textfromflags(info, fbuf), FALSE); + } +#endif + + if (dodump) { + gen_number("SCHILY.dev", (Llong)info->f_dev); + gen_number("SCHILY.ino", (Llong)info->f_ino); + gen_number("SCHILY.nlink", (Llong)info->f_nlink); + gen_text("SCHILY.filetype", XTTONAME(info->f_rxftype), FALSE); +#ifdef __needed__ + if (info->f_rxftype != info->f_xftype) + gen_text("SCHILY.tarfiletype", XTTONAME(info->f_xftype), FALSE); +#endif + } + + xptb = (TCB *)get_block(); + finfo.f_flags |= F_TCB_BUF; + filltcb(xptb); +/* strcpy(xptb->dbuf.t_name, ptb->dbuf.t_name);*/ + strcpy(xptb->dbuf.t_name, "././@PaxHeader"); + finfo.f_rsize = finfo.f_size = xbidx; + finfo.f_xftype = props.pr_xc; + info_to_tcb(&finfo, xptb); + xptb->dbuf.t_linkflag = props.pr_xc; + write_tcb(xptb, &finfo); + + move.m_data = xbuf; + move.m_size = finfo.f_size; + move.m_flags = 0; + cr_file(&finfo, vp_move_to_arch, &move, 0, "moving extended header"); +} + +/* + * Create a time string with sub-second granularity. + * + * =.\n + * + * As we always emmit 9 digits for the sub-second part, the + * length of this entry is always more then 10 and less than 100. + * We may safely fill in the two digit later when we know the value. + */ +LOCAL void +gen_xtime(keyword, sec, nsec) + char *keyword; + time_t sec; + Ulong nsec; +{ + char *p; + int len; + + if ((xbidx + 100) > xblen) + xbgrow(100); + + p = &xbuf[xbidx+3]; + len = js_sprintf(p, "%s=%lld.%9.9ld\n", keyword, (Llong)sec, nsec); + len += 3; + js_sprintf(&xbuf[xbidx], "%d", len); + xbuf[xbidx+2] = ' '; + xbidx += len; +} + +/* + * Create a generic number string. + * + * =\n + * + * The length of this entry is always less than 100 chars if the length of the + * 'name-spec' is less than 75 chars (the maximum length of a 64 bit number in + * decimal is 20 digits). In the rare case when the number is short and + * 'name-spec' only uses a few characters (e.g. number == 0 and + * strlen(name-spec) < 4) the length of the entry will be less than 10 and + * we have to correct the string by moving it backwards later. + */ +LOCAL void +gen_number(keyword, arg) + char *keyword; + Llong arg; +{ + char *p; + int len; + + if ((xbidx + 100) > xblen) + xbgrow(100); + + p = &xbuf[xbidx+3]; + len = js_sprintf(p, "%s=%lld\n", keyword, arg); + len += 3; + js_sprintf(&xbuf[xbidx], "%d", len); + xbuf[xbidx+2] = ' '; + if (len < 10) { + /* + * Rare case: the total length is less than 10 and we have to + * move the remainder of the string backwards by one. + */ + len -= 1; + xbuf[xbidx] = len + '0'; + strcpy(&xbuf[xbidx+1], &xbuf[xbidx+2]); + } + xbidx += len; +} + +/* + * Create a generic text string in UTF-8 coding. + * + * =\n + * + * This function will have to carefully check for the resultant length + * and thus compute the total length in advance. + */ +LOCAL void +gen_text(keyword, arg, addslash) + char *keyword; + char *arg; + BOOL addslash; +{ + Uchar uuu[10000]; + int len; + + to_utf8(uuu, (Uchar *)arg); + + len = strlen((char *)uuu); + if (addslash) { /* only used if 'path' is a dir */ + uuu[len++] = '/'; + uuu[len] = '\0'; + } + len += strlen(keyword) + 4; /* one digit + ' ' + '=' + '\n' */ + + if (len > 9996) { + comerrno(EX_BAD, + "Fatal: extended header for keyword '%s' too long.\n", + keyword); + } + if (len > 997) + len += 3; + else if (len > 98) + len += 2; + else if (len > 9) + len += 1; + + if ((xbidx + len) > xblen) + xbgrow(len); + + js_sprintf(&xbuf[xbidx], "%d %s=%s\n", len, keyword, uuu); + xbidx += len; +} + +/* + * Lookup command in command tab + */ +LOCAL xtab_t * +lookup(cmd, cp) + register char *cmd; + register xtab_t *cp; +{ + for (; cp->x_name; cp++) { + if ((*cmd == *cp->x_name) && + strcmp(cmd, cp->x_name) == 0) { + return (cp); + } + } + return ((xtab_t *)NULL); +} + +/* + * Read extended POSIX.1-2001 header and parse the content. + */ +EXPORT int +tcb_to_xhdr(ptb, info) + register TCB *ptb; + register FINFO *info; +{ + register xtab_t *cp; + register char *keyword; + register char *arg; + register char *p; + register char *ep; + move_t move; + Ullong ull; + long length; + +#ifdef XH_DEBUG +error("Block: %lld\n", tblocks()); +#endif + /* + * File size is strlen of extended header + */ + stolli(ptb->dbuf.t_size, &ull); + info->f_size = ull; + info->f_rsize = (off_t)info->f_size; + /* + * Reset xbidx to make xbgrow() work correctly for our case. + */ + xbidx = 0; + if ((info->f_size+1) > xblen) + xbgrow(info->f_size+1); + + move.m_data = xbuf; + move.m_flags = 0; + if (xt_file(info, vp_move_from_arch, &move, 0, + "moving extended header") < 0) { + die(EX_BAD); + } + +#ifdef XH_DEBUG +error("Block: %lld\n", tblocks()); +error("xbuf: '%s'\n", xbuf); +#endif + + p = xbuf; + ep = p + ull; + while (p < ep) { + keyword = astolb(p, &length, 10); + if (*keyword != ' ') { + errmsgno(EX_BAD, "Syntax error in extended header.\n"); + break; + } + keyword++; + arg = strchr(keyword, '='); + *arg++ = '\0'; + *(p + length -1) = '\0'; /* Kill new-line character */ + + if ((cp = lookup(keyword, xtab)) != NULL) { + (*cp->x_func)(info, keyword, arg); + } else { + errmsgno(EX_BAD, + "Unknown extended header keyword '%s' ignored.\n", + keyword); + } + p += length; + } + return (get_tcb(ptb)); +} + +/* + * generic function to read args that hold times + * + * The time may either be in second resolution or in sub-second resolution. + * In the latter case the second fraction and the sub second fraction + * is separated by a dot ('.'). + */ +LOCAL BOOL +get_xtime(keyword, arg, secp, nsecp) + char *keyword; + char *arg; + time_t *secp; + Ulong *nsecp; +{ + Llong ll; + long l; + char *p; + + p = astollb(arg, &ll, 10); + if (*p == '\0') { /* time has second resolution only */ + *secp = ll; + *nsecp = 0; + return (TRUE); + } else if (*p == '.') { /* time has sub-second resolution */ + *secp = ll; + if (strlen(++p) > 9) /* if resolution is better then nano- */ + p[9] = '\0'; /* seconds kill rest of line as we */ + p = astolb(p, &l, 10); /* don't understand more. */ + if (*p == '\0') { /* number read correctly */ + if (l >= 0) { + *nsecp = l; + return (TRUE); + } + } + } + errmsgno(EX_BAD, "Bad timespec '%s' for '%s' in extended header.\n", + arg, keyword); + return (FALSE); +} + +/* + * get read access time from extended header + */ +LOCAL void +get_atime(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + if (get_xtime(keyword, arg, &info->f_atime, &info->f_ansec)) + info->f_xflags |= XF_ATIME; +} + +/* + * get inode status change time from extended header + */ +LOCAL void +get_ctime(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + if (get_xtime(keyword, arg, &info->f_ctime, &info->f_cnsec)) + info->f_xflags |= XF_CTIME; +} + +/* + * get modification time from extended header + */ +LOCAL void +get_mtime(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + if (get_xtime(keyword, arg, &info->f_mtime, &info->f_mnsec)) + info->f_xflags |= XF_MTIME; +} + +/* + * generic function to read args that hold decimal numbers + */ +LOCAL BOOL +get_number(keyword, arg, llp) + char *keyword; + char *arg; + Llong *llp; +{ + Llong ll; + char *p; + + p = astollb(arg, &ll, 10); + if (*p == '\0') { /* number read correctly */ + *llp = ll; + return (TRUE); + } + errmsgno(EX_BAD, "Bad number '%s' for '%s' in extended header.\n", + arg, keyword); + return (FALSE); +} + +/* + * get user id (if > 2097151) + */ +LOCAL void +get_uid(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + Llong ll; + + if (get_number(keyword, arg, &ll)) { + info->f_xflags |= XF_UID; + info->f_uid = ll; + } +} + +/* + * get group id (if > 2097151) + */ +LOCAL void +get_gid(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + Llong ll; + + if (get_number(keyword, arg, &ll)) { + info->f_xflags |= XF_GID; + info->f_gid = ll; + } +} + +/* + * Space for returning user/group names. + */ +LOCAL Uchar _uname[MAX_UNAME+1]; +LOCAL Uchar _gname[MAX_UNAME+1]; + +/* + * get user name (if name length is > 32 chars or if contains non ASCII chars) + */ +LOCAL void +get_uname(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + if (strlen(arg) > MAX_UNAME) + return; + if (from_utf8(_uname, (Uchar *)arg)) { + info->f_xflags |= XF_UNAME; + info->f_uname = (char *)_uname; + info->f_umaxlen = strlen((char *)_uname); + } else { + bad_utf8(keyword, arg); + } +} + +/* + * get group name (if name length is > 32 chars or if contains non ASCII chars) + */ +LOCAL void +get_gname(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + if (strlen(arg) > MAX_UNAME) + return; + if (from_utf8(_gname, (Uchar *)arg)) { + info->f_xflags |= XF_GNAME; + info->f_gname = (char *)_gname; + info->f_gmaxlen = strlen((char *)_gname); + } else { + bad_utf8(keyword, arg); + } +} + +/* + * get path (if name length is > 100-255 chars or if contains non ASCII chars) + */ +LOCAL void +get_path(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + if (strlen(arg) > PATH_MAX) + return; + if (from_utf8((Uchar *)info->f_name, (Uchar *)arg)) { + info->f_xflags |= XF_PATH; + } else { + bad_utf8(keyword, arg); + } +} + +/* + * get link path (if name length is > 100 chars or if contains non ASCII chars) + */ +LOCAL void +get_lpath(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ +extern char longlinkname[]; + + if (strlen(arg) > PATH_MAX) + return; + if (from_utf8((Uchar *)longlinkname, (Uchar *)arg)) { + info->f_xflags |= XF_LINKPATH; + info->f_lname = longlinkname; + } else { + bad_utf8(keyword, arg); + } +} + +/* + * get size (usually when size is > 8 GB) + */ +LOCAL void +get_size(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + Llong ll; + + if (get_number(keyword, arg, &ll)) { + info->f_xflags |= XF_SIZE; + info->f_size = (off_t)ll; + } +} + +/* + * get major device number (always vendor unique) + */ +LOCAL void +get_major(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + Llong ll; + + if (get_number(keyword, arg, &ll)) { + info->f_xflags |= XF_DEVMAJOR; + info->f_rdevmaj = ll; + } +} + +/* + * get minor device number (always vendor unique) + */ +LOCAL void +get_minor(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + Llong ll; + + if (get_number(keyword, arg, &ll)) { + info->f_xflags |= XF_DEVMINOR; + info->f_rdevmin = ll; + } +} + +/* + * get device number of device containing FS (vendor unique) + */ +LOCAL void +get_dev(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + Llong ll; + + if (get_number(keyword, arg, &ll)) { + info->f_dev = ll; + } +} + +/* + * get inode number for this file (vendor unique) + */ +LOCAL void +get_ino(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + Llong ll; + + if (get_number(keyword, arg, &ll)) { + info->f_ino = ll; + } +} + +/* + * get link count for this file (vendor unique) + */ +LOCAL void +get_nlink(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + Llong ll; + + if (get_number(keyword, arg, &ll)) { + info->f_nlink = ll; + } +} + +/* + * get tar file type or real file type for this file (vendor unique) + */ +LOCAL void +get_filetype(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + int i; + + for (i=0; i < XT_BAD; i++) { + if (streql(xttoname_tab[i], arg)) + break; + } + if (i >= XT_BAD) + return; + + if (keyword[7] == 'f') { /* "SCHILY.filetype" */ + info->f_rxftype = i; + info->f_filetype = XTTOST(info->f_rxftype); + info->f_type = XTTOIF(info->f_rxftype); + } else { /* "SCHILY.tarfiletype" */ + info->f_xftype = i; + } +} + +#ifdef USE_ACL + +/* + * XXX acl_access_text/acl_default_text are a bad idea. (see acl_unix.c) + */ +LOCAL char acl_access_text[PATH_MAX+1]; +LOCAL char acl_default_text[PATH_MAX+1]; + +LOCAL void +get_acl_access(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + if (strlen(arg) > PATH_MAX) /* XXX We should use dynamic strings */ + return; + if (from_utf8((Uchar *)acl_access_text, (Uchar *)arg)) { + info->f_xflags |= XF_ACL_ACCESS; + info->f_acl_access = acl_access_text; + } else { + bad_utf8(keyword, arg); + } +} + +LOCAL void +get_acl_default(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + if (strlen(arg) > PATH_MAX) /* XXX We should use dynamic strings */ + return; + if (from_utf8((Uchar *)acl_default_text, (Uchar *)arg)) { + info->f_xflags |= XF_ACL_DEFAULT; + info->f_acl_default = acl_default_text; + } else { + bad_utf8(keyword, arg); + } +} + +#endif /* USE_ACL */ + +#ifdef USE_FFLAGS + +LOCAL void +get_xfflags(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ + texttoflags(info, arg); + info->f_xflags |= XF_FFLAGS; +} + +#endif /* USE_FFLAGS */ + + +/* + * Dummy 'get' function used for all fields that we don't yet understand or + * fields that we indent to ignore. + */ +LOCAL void +get_dummy(info, keyword, arg) + FINFO *info; + char *keyword; + char *arg; +{ +} + +LOCAL void +bad_utf8(keyword, arg) + char *keyword; + char *arg; +{ + errmsgno(EX_BAD, "Bad UTF-8 arg '%s' for '%s' in extended header.\n", + arg, keyword); +}