2285 lines
56 KiB
C
2285 lines
56 KiB
C
/* @(#)isoinfo.c 1.108 16/08/10 joerg */
|
|
#include <schily/mconfig.h>
|
|
#ifndef lint
|
|
static UConst char sccsid[] =
|
|
"@(#)isoinfo.c 1.108 16/08/10 joerg";
|
|
#endif
|
|
/*
|
|
* File isodump.c - dump iso9660 directory information.
|
|
*
|
|
*
|
|
* Written by Eric Youngdale (1993).
|
|
*
|
|
* Copyright 1993 Yggdrasil Computing, Incorporated
|
|
* Copyright (c) 1999-2016 J. Schilling
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/*
|
|
* Simple program to dump contents of iso9660 image in more usable format.
|
|
*
|
|
* Usage:
|
|
* To list contents of image (with or without RR):
|
|
* isoinfo -l [-R] -i imagefile
|
|
* To extract file from image:
|
|
* isoinfo -i imagefile -x xtractfile > outfile
|
|
* To generate a "find" like list of files:
|
|
* isoinfo -f -i imagefile
|
|
*/
|
|
|
|
#include <schily/stdlib.h>
|
|
#include <schily/unistd.h>
|
|
#include <schily/string.h>
|
|
|
|
#include <schily/stdio.h>
|
|
#include <schily/utypes.h>
|
|
#include <schily/standard.h>
|
|
#include <schily/signal.h>
|
|
#include <schily/stat.h>
|
|
#include <schily/device.h>
|
|
#include <schily/time.h>
|
|
#include <schily/fcntl.h>
|
|
#include <schily/intcvt.h>
|
|
#include <schily/nlsdefs.h>
|
|
#include <schily/getargs.h>
|
|
#include <schily/nlsdefs.h>
|
|
#include <schily/ctype.h>
|
|
#include <schily/errno.h>
|
|
#include <schily/schily.h>
|
|
|
|
#include "../iso9660.h"
|
|
#include "../rock.h"
|
|
#include "../scsi.h"
|
|
#include "cdrdeflt.h"
|
|
#include "../../cdrecord/version.h"
|
|
|
|
#include <schily/siconv.h>
|
|
#include <schily/io.h> /* for setmode() prototype */
|
|
#ifdef USE_FIND
|
|
#include <schily/walk.h>
|
|
#include <schily/find.h>
|
|
#endif
|
|
|
|
/*
|
|
* Make sure we have a definition for this. If not, take a very conservative
|
|
* guess.
|
|
* POSIX requires the max pathname component lenght to be defined in limits.h
|
|
* If variable, it may be undefined. If undefined, there should be
|
|
* a definition for _POSIX_NAME_MAX in limits.h or in unistd.h
|
|
* As _POSIX_NAME_MAX is defined to 14, we cannot use it.
|
|
* XXX Eric's wrong comment:
|
|
* XXX From what I can tell SunOS is the only one with this trouble.
|
|
*/
|
|
#include <schily/limits.h>
|
|
|
|
#ifndef NAME_MAX
|
|
#ifdef FILENAME_MAX
|
|
#define NAME_MAX FILENAME_MAX
|
|
#else
|
|
#define NAME_MAX 256
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef PATH_MAX
|
|
#ifdef FILENAME_MAX
|
|
#define PATH_MAX FILENAME_MAX
|
|
#else
|
|
#define PATH_MAX 1024
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
* XXX JS: Some structures have odd lengths!
|
|
* Some compilers (e.g. on Sun3/mc68020) padd the structures to even length.
|
|
* For this reason, we cannot use sizeof (struct iso_path_table) or
|
|
* sizeof (struct iso_directory_record) to compute on disk sizes.
|
|
* Instead, we use offsetof(..., name) and add the name size.
|
|
* See iso9660.h
|
|
*/
|
|
#ifndef offsetof
|
|
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
|
#endif
|
|
|
|
/*
|
|
* Note: always use these macros to avoid problems.
|
|
*
|
|
* ISO_ROUND_UP(X) may cause an integer overflow and thus give
|
|
* incorrect results. So avoid it if possible.
|
|
*
|
|
* ISO_BLOCKS(X) is overflow safe. Prefer this when ever it is possible.
|
|
*/
|
|
#define SECTOR_SIZE (2048)
|
|
#define ISO_ROUND_UP(X) (((X) + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))
|
|
#define ISO_BLOCKS(X) (((X) / SECTOR_SIZE) + (((X)%SECTOR_SIZE)?1:0))
|
|
|
|
#define GET_UBYTE(a) a_to_u_byte(a)
|
|
|
|
#define infile in_image
|
|
EXPORT FILE *infile = NULL;
|
|
EXPORT BOOL ignerr = FALSE;
|
|
LOCAL int use_rock = 0;
|
|
LOCAL int use_joliet = 0;
|
|
LOCAL int do_listing = 0;
|
|
LOCAL int do_f = 0;
|
|
LOCAL int do_find = 0;
|
|
LOCAL int find_ac = 0; /* ac past -find option */
|
|
LOCAL char *const *find_av = NULL; /* av past -find option */
|
|
LOCAL int find_pac = 0; /* ac for first find primary */
|
|
LOCAL char *const *find_pav = NULL; /* av for first find primary */
|
|
LOCAL int do_sectors = 0;
|
|
LOCAL int do_pathtab = 0;
|
|
LOCAL int do_pvd = 0;
|
|
LOCAL BOOL debug = FALSE;
|
|
LOCAL char *xtract = 0;
|
|
LOCAL BOOL Xtract = FALSE;
|
|
LOCAL char er_id[256];
|
|
LOCAL int su_version = 0;
|
|
LOCAL int rr_version = 0;
|
|
LOCAL int aa_version = 0;
|
|
LOCAL int cl_extent = 0;
|
|
LOCAL int ucs_level = 0;
|
|
LOCAL BOOL iso9660_inodes = FALSE;
|
|
LOCAL uid_t myuid;
|
|
|
|
#ifdef USE_FIND
|
|
LOCAL findn_t *find_node; /* syntaxtree from find_parse() */
|
|
LOCAL void *plusp; /* residual for -exec ...{} + */
|
|
LOCAL int find_patlen; /* len for -find pattern state */
|
|
LOCAL BOOL find_print = FALSE; /* -print or -ls primary found */
|
|
|
|
LOCAL int walkflags = WALK_CHDIR | WALK_PHYS | WALK_NOEXIT;
|
|
LOCAL int maxdepth = -1;
|
|
LOCAL int mindepth = -1;
|
|
LOCAL struct WALK walkstate;
|
|
#endif
|
|
|
|
LOCAL struct stat fstat_buf;
|
|
LOCAL int found_rr;
|
|
LOCAL char name_buf[256*3];
|
|
LOCAL char xname[8192];
|
|
LOCAL unsigned char date_buf[9]; /* iso_directory_record.date[7] */
|
|
/*
|
|
* Use sector_offset != 0 (-N #) if we have an image file
|
|
* of a single session and we need to list the directory contents.
|
|
* This is the session block (sector) number of the start
|
|
* of the session when it would be on disk.
|
|
*/
|
|
LOCAL unsigned int sector_offset = 0;
|
|
|
|
LOCAL unsigned char buffer[2048];
|
|
|
|
LOCAL siconvt_t *unls;
|
|
|
|
#define PAGE sizeof (buffer)
|
|
|
|
#define ISODCL(from, to) (to - from + 1)
|
|
|
|
struct todo
|
|
{
|
|
struct todo *next;
|
|
struct todo *prev;
|
|
char *name;
|
|
int extent;
|
|
int length;
|
|
};
|
|
|
|
LOCAL struct todo *todo_idr = NULL;
|
|
LOCAL struct todo **todo_pp = &todo_idr;
|
|
|
|
|
|
LOCAL int isonum_721 __PR((char * p));
|
|
LOCAL int isonum_723 __PR((char * p));
|
|
LOCAL int isonum_731 __PR((char * p));
|
|
LOCAL int isonum_732 __PR((char * p));
|
|
LOCAL int isonum_733 __PR((unsigned char * p));
|
|
LOCAL void printchars __PR((char *s, int n, BOOL ucs));
|
|
LOCAL char *sdate __PR((char *dp));
|
|
LOCAL void dump_pathtab __PR((int block, int size));
|
|
LOCAL int parse_rr __PR((unsigned char * pnt, int len,
|
|
int cont_flag));
|
|
LOCAL void find_rr __PR((struct iso_directory_record * idr,
|
|
Uchar **pntp, int *lenp));
|
|
LOCAL int dump_rr __PR((struct iso_directory_record * idr));
|
|
LOCAL BOOL dump_stat __PR((char *rootname,
|
|
struct iso_directory_record * idr,
|
|
char *fname,
|
|
int extent));
|
|
LOCAL void extract __PR((char *rootname,
|
|
struct iso_directory_record * idr,
|
|
char *fname));
|
|
LOCAL void extract_file __PR((int f,
|
|
struct iso_directory_record * idr,
|
|
char *fname));
|
|
LOCAL void parse_cl_dir __PR((struct iso_directory_record *idr,
|
|
int extent));
|
|
LOCAL BOOL parse_de __PR((struct iso_directory_record *idr));
|
|
LOCAL void parse_dir __PR((struct todo *dp,
|
|
char * rootname, int extent, int len));
|
|
LOCAL void usage __PR((int excode));
|
|
EXPORT int main __PR((int argc, char *argv[]));
|
|
LOCAL void list_vd __PR((struct iso_primary_descriptor *vp, BOOL ucs));
|
|
LOCAL void list_locales __PR((void));
|
|
LOCAL void printf_bootinfo __PR((FILE *f, int bootcat_offset));
|
|
LOCAL char *arch_name __PR((int val));
|
|
LOCAL char *boot_name __PR((int val));
|
|
LOCAL char *bootmedia_name __PR((int val));
|
|
LOCAL int time_cvt __PR((unsigned char *dp, int len));
|
|
LOCAL time_t iso9660_time __PR((unsigned char *date, int *hsecp,
|
|
BOOL longfmt));
|
|
#ifdef USE_FIND
|
|
LOCAL int getfind __PR((char *arg, long *valp,
|
|
int *pac, char *const **pav));
|
|
LOCAL BOOL find_stat __PR((char *rootname,
|
|
struct iso_directory_record * idr,
|
|
char *fname,
|
|
int extent));
|
|
#endif
|
|
|
|
|
|
|
|
LOCAL int
|
|
isonum_721(p)
|
|
char *p;
|
|
{
|
|
return ((p[0] & 0xff)
|
|
| ((p[1] & 0xff) << 8));
|
|
}
|
|
|
|
LOCAL int
|
|
isonum_723(p)
|
|
char * p;
|
|
{
|
|
#if 0
|
|
if (p[0] != p[3] || p[1] != p[2]) {
|
|
fprintf(stderr, "invalid format 7.2.3 number\n");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
return (isonum_721(p));
|
|
}
|
|
|
|
LOCAL int
|
|
isonum_731(p)
|
|
char *p;
|
|
{
|
|
return ((p[0] & 0xff)
|
|
| ((p[1] & 0xff) << 8)
|
|
| ((p[2] & 0xff) << 16)
|
|
| ((p[3] & 0xff) << 24));
|
|
}
|
|
|
|
LOCAL int
|
|
isonum_732(p)
|
|
char *p;
|
|
{
|
|
return ((p[3] & 0xff)
|
|
| ((p[2] & 0xff) << 8)
|
|
| ((p[1] & 0xff) << 16)
|
|
| ((p[0] & 0xff) << 24));
|
|
}
|
|
|
|
LOCAL int
|
|
isonum_733(p)
|
|
unsigned char *p;
|
|
{
|
|
return (isonum_731((char *)p));
|
|
}
|
|
|
|
LOCAL void
|
|
printchars(s, n, ucs)
|
|
char *s;
|
|
int n;
|
|
BOOL ucs;
|
|
{
|
|
int i;
|
|
char *p;
|
|
int c;
|
|
|
|
for (; n > 0 && (*s || (ucs && s[1])); n--) {
|
|
if (ucs) {
|
|
c = *s++ & 0xFF;
|
|
c *= 256;
|
|
c += *s++ & 0xFF;
|
|
n--;
|
|
} else {
|
|
c = *s++;
|
|
}
|
|
if (c == ' ') {
|
|
int c2;
|
|
p = s;
|
|
i = n;
|
|
while (--i >= 0) {
|
|
if (ucs) {
|
|
c2 = *p++ & 0xFF;
|
|
c2 *= 256;
|
|
c2 += *p++ & 0xFF;
|
|
i--;
|
|
} else {
|
|
c2 = *p++;
|
|
}
|
|
if (c2 != ' ')
|
|
break;
|
|
}
|
|
if (i <= 0)
|
|
break;
|
|
}
|
|
putchar(c);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Print date info from PVD
|
|
*/
|
|
LOCAL char *
|
|
sdate(dp)
|
|
char *dp;
|
|
{
|
|
static char d[30];
|
|
|
|
js_sprintf(d, "%4.4s %2.2s %2.2s %2.2s:%2.2s:%2.2s.%2.2s",
|
|
&dp[0], /* Year */
|
|
&dp[4], /* Month */
|
|
&dp[6], /* Monthday */
|
|
&dp[8], /* Hour */
|
|
&dp[10], /* Minute */
|
|
&dp[12], /* Seconds */
|
|
&dp[14]); /* Hunreds of a Seconds */
|
|
|
|
/*
|
|
* dp[16] contains minute offset from Greenwich
|
|
* Positive values are to the east of Greenwich.
|
|
*/
|
|
return (d);
|
|
}
|
|
|
|
LOCAL void
|
|
dump_pathtab(block, size)
|
|
int block;
|
|
int size;
|
|
{
|
|
unsigned char *buf;
|
|
int offset;
|
|
int idx;
|
|
int extent;
|
|
int pindex;
|
|
int j;
|
|
int len;
|
|
int jlen;
|
|
char namebuf[256*3];
|
|
unsigned char uc;
|
|
|
|
|
|
printf(_("Path table starts at block %d, size %d\n"), block, size);
|
|
|
|
buf = (unsigned char *) malloc(ISO_ROUND_UP(size));
|
|
|
|
#ifdef USE_SCG
|
|
readsecs(block - sector_offset, buf, ISO_BLOCKS(size));
|
|
#else
|
|
lseek(fileno(infile), ((off_t)(block - sector_offset)) << 11, SEEK_SET);
|
|
read(fileno(infile), buf, size);
|
|
#endif
|
|
|
|
offset = 0;
|
|
idx = 1;
|
|
while (offset < size) {
|
|
len = buf[offset];
|
|
extent = isonum_731((char *)buf + offset + 2);
|
|
pindex = isonum_721((char *)buf + offset + 6);
|
|
switch (ucs_level) {
|
|
case 3:
|
|
case 2:
|
|
case 1:
|
|
jlen = len/2;
|
|
namebuf[0] = '\0';
|
|
#ifdef USE_ICONV
|
|
#ifdef HAVE_ICONV_CONST
|
|
#define __IC_CONST const
|
|
#else
|
|
#define __IC_CONST
|
|
#endif
|
|
if (use_iconv(unls)) {
|
|
int u;
|
|
char *to = namebuf;
|
|
|
|
for (j = 0, u = 0; j < jlen; j++) {
|
|
char *ibuf = (char *)&buf[offset + 8 + j*2];
|
|
size_t isize = 2; /* UCS-2 character size */
|
|
size_t osize = 4;
|
|
|
|
if (iconv(unls->sic_uni2cd, (__IC_CONST char **)&ibuf, &isize,
|
|
(char **)&to, &osize) == -1) {
|
|
int err = geterrno();
|
|
|
|
if ((err == EINVAL || err == EILSEQ) &&
|
|
osize == 4) {
|
|
*to = '_';
|
|
u += 1;
|
|
to++;
|
|
}
|
|
} else {
|
|
u += 4 - osize;
|
|
to = &namebuf[u];
|
|
}
|
|
}
|
|
j = u;
|
|
} else
|
|
#endif
|
|
for (j = 0; j < jlen; j++) {
|
|
UInt16_t unichar;
|
|
|
|
unichar = (buf[offset + 8 + j*2] & 0xFF) * 256 +
|
|
(buf[offset + 8 + j*2+1] & 0xFF);
|
|
|
|
if (unls)
|
|
uc = sic_uni2c(unls, unichar); /* Get the backconverted char */
|
|
else
|
|
uc = unichar > 255 ? '_' : unichar;
|
|
|
|
namebuf[j] = uc ? uc : '_';
|
|
}
|
|
namebuf[j] = '\0';
|
|
printf("%4d: %4d %x %s\n",
|
|
idx, pindex, extent, namebuf);
|
|
break;
|
|
case 0:
|
|
printf("%4d: %4d %x %.*s\n",
|
|
idx, pindex, extent, len, buf + offset + 8);
|
|
}
|
|
|
|
idx++;
|
|
offset += 8 + len;
|
|
if (offset & 1)
|
|
offset++;
|
|
}
|
|
|
|
free(buf);
|
|
}
|
|
|
|
LOCAL int
|
|
parse_rr(pnt, len, cont_flag)
|
|
unsigned char *pnt;
|
|
int len;
|
|
int cont_flag;
|
|
{
|
|
int slen;
|
|
int xlen;
|
|
int ncount;
|
|
int pl_extent;
|
|
int cont_extent, cont_offset, cont_size;
|
|
int flag1, flag2;
|
|
unsigned char *pnts;
|
|
char symlinkname[1024];
|
|
int goof = 0;
|
|
|
|
symlinkname[0] = 0;
|
|
|
|
cl_extent = cont_extent = cont_offset = cont_size = 0;
|
|
|
|
ncount = 0;
|
|
flag1 = -1;
|
|
flag2 = 0;
|
|
while (len >= 4) {
|
|
if (pnt[3] != 1 && pnt[3] != 2) {
|
|
printf(_("**BAD RRVERSION (%d) in '%2.2s' field %2.2X %2.2X.\n"), pnt[3], pnt, pnt[0], pnt[1]);
|
|
return (0); /* JS ??? Is this right ??? */
|
|
}
|
|
if (pnt[2] < 4) {
|
|
printf(_("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"), pnt[2], pnt, pnt[0], pnt[1]);
|
|
return (0); /* JS ??? Is this right ??? */
|
|
}
|
|
|
|
ncount++;
|
|
if (pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
|
|
if (strncmp((char *)pnt, "PX", 2) == 0) flag2 |= RR_FLAG_PX; /* POSIX attributes */
|
|
if (strncmp((char *)pnt, "PN", 2) == 0) flag2 |= RR_FLAG_PN; /* POSIX device number */
|
|
if (strncmp((char *)pnt, "SL", 2) == 0) flag2 |= RR_FLAG_SL; /* Symlink */
|
|
if (strncmp((char *)pnt, "NM", 2) == 0) flag2 |= RR_FLAG_NM; /* Alternate Name */
|
|
if (strncmp((char *)pnt, "CL", 2) == 0) flag2 |= RR_FLAG_CL; /* Child link */
|
|
if (strncmp((char *)pnt, "PL", 2) == 0) flag2 |= RR_FLAG_PL; /* Parent link */
|
|
if (strncmp((char *)pnt, "RE", 2) == 0) flag2 |= RR_FLAG_RE; /* Relocated Direcotry */
|
|
if (strncmp((char *)pnt, "TF", 2) == 0) {
|
|
BOOL longfmt;
|
|
int size = 7;
|
|
int hsec;
|
|
unsigned char *p = &pnt[5];
|
|
|
|
flag2 |= RR_FLAG_TF; /* Time stamp */
|
|
longfmt = (pnt[4] & 0x80) != 0;
|
|
if (longfmt)
|
|
size = 17;
|
|
if (pnt[4] & 0x01) {
|
|
p += size;
|
|
}
|
|
if (pnt[4] & 0x02) {
|
|
fstat_buf.st_mtime = iso9660_time(p,
|
|
&hsec, longfmt);
|
|
hsec *= 10000000;
|
|
stat_set_mnsecs(&fstat_buf, hsec);
|
|
p += size;
|
|
}
|
|
if (pnt[4] & 0x04) {
|
|
fstat_buf.st_atime = iso9660_time(p,
|
|
&hsec, longfmt);
|
|
hsec *= 10000000;
|
|
stat_set_ansecs(&fstat_buf, hsec);
|
|
p += size;
|
|
}
|
|
if (pnt[4] & 0x08) {
|
|
fstat_buf.st_ctime = iso9660_time(p,
|
|
&hsec, longfmt);
|
|
hsec *= 10000000;
|
|
stat_set_cnsecs(&fstat_buf, hsec);
|
|
p += size;
|
|
}
|
|
}
|
|
if (strncmp((char *)pnt, "SF", 2) == 0) flag2 |= RR_FLAG_SF; /* Sparse File */
|
|
|
|
if (strncmp((char *)pnt, "SP", 2) == 0) {
|
|
flag2 |= RR_FLAG_SP; /* SUSP record */
|
|
su_version = pnt[3] & 0xff;
|
|
}
|
|
if (strncmp((char *)pnt, "AA", 2) == 0) { /* Neither SUSP nor RR */
|
|
flag2 |= RR_FLAG_AA; /* Apple Signature record */
|
|
aa_version = pnt[3] & 0xff;
|
|
}
|
|
if (strncmp((char *)pnt, "ER", 2) == 0) {
|
|
flag2 |= RR_FLAG_ER; /* ER record */
|
|
rr_version = pnt[7] & 0xff; /* Ext Version */
|
|
strlcpy(er_id, (char *)&pnt[8], (pnt[4] & 0xFF) + 1);
|
|
}
|
|
|
|
if (strncmp((char *)pnt, "PX", 2) == 0) { /* POSIX attributes */
|
|
fstat_buf.st_mode = isonum_733(pnt+4);
|
|
fstat_buf.st_nlink = isonum_733(pnt+12);
|
|
fstat_buf.st_uid = isonum_733(pnt+20);
|
|
fstat_buf.st_gid = isonum_733(pnt+28);
|
|
if ((pnt[2] & 0xFF) >= 44) /* Check for RR 1.12 */
|
|
fstat_buf.st_ino = (UInt32_t)isonum_733(pnt+36);
|
|
}
|
|
|
|
if (strncmp((char *)pnt, "PN", 2) == 0) { /* POSIX device number */
|
|
dev_t devmajor = isonum_733(pnt+4);
|
|
dev_t devminor = isonum_733(pnt+12);
|
|
|
|
fstat_buf.st_rdev = makedev(devmajor, devminor);
|
|
}
|
|
|
|
if (strncmp((char *)pnt, "NM", 2) == 0) { /* Alternate Name */
|
|
int l = strlen(name_buf);
|
|
|
|
if (!found_rr)
|
|
l = 0;
|
|
strncpy(&name_buf[l], (char *)(pnt+5), pnt[2] - 5);
|
|
name_buf[l + pnt[2] - 5] = 0;
|
|
found_rr = 1;
|
|
}
|
|
|
|
if (strncmp((char *)pnt, "CE", 2) == 0) { /* Continuation Area */
|
|
cont_extent = isonum_733(pnt+4);
|
|
cont_offset = isonum_733(pnt+12);
|
|
cont_size = isonum_733(pnt+20);
|
|
}
|
|
|
|
if (strncmp((char *)pnt, "ST", 2) == 0) { /* Terminate SUSP */
|
|
break;
|
|
}
|
|
|
|
if (strncmp((char *)pnt, "CL", 2) == 0) {
|
|
cl_extent = isonum_733(pnt+4); /* Child link location */
|
|
}
|
|
if (strncmp((char *)pnt, "PL", 2) == 0) {
|
|
pl_extent = isonum_733(pnt+4); /* Parent link location */
|
|
}
|
|
|
|
if (strncmp((char *)pnt, "SL", 2) == 0) { /* Symlink */
|
|
int cflag;
|
|
|
|
cflag = pnt[4];
|
|
pnts = pnt+5;
|
|
slen = pnt[2] - 5;
|
|
while (slen >= 1) {
|
|
switch (pnts[0] & 0xfe) {
|
|
case 0:
|
|
strncat(symlinkname, (char *)(pnts+2), pnts[1]);
|
|
symlinkname[pnts[1]] = 0;
|
|
break;
|
|
case 2:
|
|
strcat(symlinkname, ".");
|
|
break;
|
|
case 4:
|
|
strcat(symlinkname, "..");
|
|
break;
|
|
case 8:
|
|
symlinkname[0] = '\0';
|
|
break;
|
|
case 16:
|
|
strcat(symlinkname, "/mnt");
|
|
printf(_("Warning - mount point requested"));
|
|
break;
|
|
case 32:
|
|
strcat(symlinkname, "kafka");
|
|
printf(_("Warning - host_name requested"));
|
|
break;
|
|
default:
|
|
printf(_("Reserved bit setting in symlink"));
|
|
goof++;
|
|
break;
|
|
}
|
|
if ((pnts[0] & 0xfe) && pnts[1] != 0) {
|
|
printf(_("Incorrect length in symlink component"));
|
|
}
|
|
if (pnts[0] == 8)
|
|
xname[0] = '\0';
|
|
if (xname[0] == 0)
|
|
strcpy(xname, "-> ");
|
|
strcat(xname, symlinkname);
|
|
symlinkname[0] = 0;
|
|
xlen = strlen(xname);
|
|
if ((pnts[0] & 1) == 0)
|
|
strcat(xname, "/");
|
|
|
|
slen -= (pnts[1] + 2);
|
|
pnts += (pnts[1] + 2);
|
|
}
|
|
symlinkname[0] = 0;
|
|
}
|
|
|
|
len -= pnt[2];
|
|
pnt += pnt[2];
|
|
}
|
|
if (cont_extent) {
|
|
unsigned char sector[2048];
|
|
|
|
#ifdef USE_SCG
|
|
readsecs(cont_extent - sector_offset, sector, ISO_BLOCKS(sizeof (sector)));
|
|
#else
|
|
lseek(fileno(infile), ((off_t)(cont_extent - sector_offset)) << 11, SEEK_SET);
|
|
read(fileno(infile), sector, sizeof (sector));
|
|
#endif
|
|
flag2 |= parse_rr(§or[cont_offset], cont_size, 1);
|
|
}
|
|
/*
|
|
* for symbolic links, strip out the last '/'
|
|
*/
|
|
if (xname[0] != 0 && xname[strlen(xname)-1] == '/') {
|
|
if (strlen(xname) > 4)
|
|
xname[strlen(xname)-1] = '\0';
|
|
}
|
|
return (flag2);
|
|
}
|
|
|
|
LOCAL void
|
|
find_rr(idr, pntp, lenp)
|
|
struct iso_directory_record *idr;
|
|
Uchar **pntp;
|
|
int *lenp;
|
|
{
|
|
struct iso_xa_dir_record *xadp;
|
|
int len;
|
|
unsigned char * pnt;
|
|
|
|
len = idr->length[0] & 0xff;
|
|
len -= offsetof(struct iso_directory_record, name[0]);
|
|
len -= idr->name_len[0];
|
|
|
|
pnt = (unsigned char *) idr;
|
|
pnt += offsetof(struct iso_directory_record, name[0]);
|
|
pnt += idr->name_len[0];
|
|
if ((idr->name_len[0] & 1) == 0) {
|
|
pnt++;
|
|
len--;
|
|
}
|
|
if (len >= 14) {
|
|
xadp = (struct iso_xa_dir_record *)pnt;
|
|
|
|
if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
|
|
xadp->reserved[0] == '\0') {
|
|
len -= 14;
|
|
pnt += 14;
|
|
}
|
|
}
|
|
*pntp = pnt;
|
|
*lenp = len;
|
|
}
|
|
|
|
LOCAL int
|
|
dump_rr(idr)
|
|
struct iso_directory_record *idr;
|
|
{
|
|
int len;
|
|
unsigned char * pnt;
|
|
|
|
find_rr(idr, &pnt, &len);
|
|
return (parse_rr(pnt, len, 0));
|
|
}
|
|
|
|
LOCAL char *months[12] = {"Jan", "Feb", "Mar", "Apr",
|
|
"May", "Jun", "Jul",
|
|
"Aug", "Sep", "Oct", "Nov", "Dec"};
|
|
|
|
/*
|
|
* Return TRUE if this file was "selected" either based on find rules
|
|
* or for all files if there was no find rule.
|
|
*/
|
|
LOCAL BOOL
|
|
dump_stat(rootname, idr, fname, extent)
|
|
char *rootname;
|
|
struct iso_directory_record *idr;
|
|
char *fname;
|
|
int extent;
|
|
{
|
|
int i;
|
|
int off = 0;
|
|
char outline[100];
|
|
|
|
if (do_find) {
|
|
if (!find_stat(rootname, idr, fname, extent))
|
|
return (FALSE);
|
|
if (!do_listing || find_print)
|
|
return (TRUE);
|
|
} else if (!do_listing)
|
|
return (TRUE);
|
|
|
|
memset(outline, ' ', sizeof (outline));
|
|
|
|
if (fstat_buf.st_ino != 0)
|
|
off = js_sprintf(outline, "%10llu ", (ULlong)fstat_buf.st_ino);
|
|
if (off < 0)
|
|
off = 0;
|
|
|
|
if (S_ISREG(fstat_buf.st_mode))
|
|
outline[off] = '-';
|
|
else if (S_ISDIR(fstat_buf.st_mode))
|
|
outline[off] = 'd';
|
|
else if (S_ISLNK(fstat_buf.st_mode))
|
|
outline[off] = 'l';
|
|
else if (S_ISCHR(fstat_buf.st_mode))
|
|
outline[off] = 'c';
|
|
else if (S_ISBLK(fstat_buf.st_mode))
|
|
outline[off] = 'b';
|
|
else if (S_ISFIFO(fstat_buf.st_mode))
|
|
outline[off] = 'f';
|
|
else if (S_ISSOCK(fstat_buf.st_mode))
|
|
outline[off] = 's';
|
|
else
|
|
outline[off] = '?';
|
|
|
|
memset(outline+off+1, '-', 9);
|
|
if (fstat_buf.st_mode & S_IRUSR)
|
|
outline[off+1] = 'r';
|
|
if (fstat_buf.st_mode & S_IWUSR)
|
|
outline[off+2] = 'w';
|
|
if (fstat_buf.st_mode & S_IXUSR)
|
|
outline[off+3] = 'x';
|
|
|
|
if (fstat_buf.st_mode & S_IRGRP)
|
|
outline[off+4] = 'r';
|
|
if (fstat_buf.st_mode & S_IWGRP)
|
|
outline[off+5] = 'w';
|
|
if (fstat_buf.st_mode & S_IXGRP)
|
|
outline[off+6] = 'x';
|
|
|
|
if (fstat_buf.st_mode & S_IROTH)
|
|
outline[off+7] = 'r';
|
|
if (fstat_buf.st_mode & S_IWOTH)
|
|
outline[off+8] = 'w';
|
|
if (fstat_buf.st_mode & S_IXOTH)
|
|
outline[off+9] = 'x';
|
|
|
|
off += 10;
|
|
off += js_sprintf(outline+off, " %3ld", (long)fstat_buf.st_nlink);
|
|
off += js_sprintf(outline+off, " %4ld", (unsigned long)fstat_buf.st_uid);
|
|
off += js_sprintf(outline+off, " %4ld", (unsigned long)fstat_buf.st_gid);
|
|
|
|
if (do_sectors == 0) {
|
|
off += js_sprintf(outline+off, " %10lld", (Llong)fstat_buf.st_size);
|
|
} else {
|
|
off += js_sprintf(outline+off, " %10lld", (Llong)((fstat_buf.st_size+PAGE-1)/PAGE));
|
|
}
|
|
|
|
if (date_buf[1] >= 1 && date_buf[1] <= 12) {
|
|
memcpy(outline+off+1, months[date_buf[1]-1], 3);
|
|
off += 4;
|
|
} else {
|
|
/*
|
|
* Some broken ISO-9660 formatters write illegal month numbers.
|
|
*/
|
|
off += 1 + js_sprintf(outline+off+1, "???");
|
|
}
|
|
|
|
off += js_sprintf(outline+off, " %2d", date_buf[2]);
|
|
off += js_sprintf(outline+off, " %4d", date_buf[0]+1900);
|
|
|
|
off += js_sprintf(outline+off, " [%7d", extent); /* XXX up to 20 GB */
|
|
off += js_sprintf(outline+off, " %02X]", idr->flags[0] & 0xFF);
|
|
|
|
for (i = 0; i < off; i++) {
|
|
if (outline[i] == 0) outline[i] = ' ';
|
|
}
|
|
outline[off] = 0;
|
|
printf("%s %s %s\n", outline, name_buf, xname);
|
|
return (TRUE);
|
|
}
|
|
|
|
LOCAL void
|
|
extract(rootname, idr, fname)
|
|
char *rootname;
|
|
struct iso_directory_record *idr;
|
|
char *fname;
|
|
{
|
|
int f;
|
|
struct timespec times[2];
|
|
static BOOL isfirst = TRUE;
|
|
|
|
if ((idr->flags[0] & 2) != 0 &&
|
|
(idr->name_len[0] == 1 &&
|
|
(idr->name[0] == 0 || idr->name[0] == 1))) {
|
|
/*
|
|
* Catch all "." and ".." entries here.
|
|
*/
|
|
if (idr->name[0] == 1) /* Skip "/.." */
|
|
return;
|
|
if (rootname[0] == '/' && rootname[1] == '\0')
|
|
fname = "/.";
|
|
}
|
|
if (*fname == '/')
|
|
fname++;
|
|
makedirs(fname, S_IRUSR|S_IWUSR|S_IXUSR|
|
|
S_IRGRP|S_IWGRP|S_IXGRP|
|
|
S_IROTH|S_IWOTH|S_IXOTH, TRUE);
|
|
|
|
switch (fstat_buf.st_mode & S_IFMT) {
|
|
|
|
#ifndef HAVE_MKNOD
|
|
err:
|
|
#endif
|
|
default:
|
|
errmsgno(EX_BAD,
|
|
"Unsupported file type %0lo for '%s'.\n",
|
|
(unsigned long)fstat_buf.st_mode & S_IFMT,
|
|
fname);
|
|
return;
|
|
|
|
|
|
case S_IFDIR:
|
|
#ifdef __MINGW32__
|
|
#define mkdir(n, m) mkdir(n)
|
|
#endif
|
|
if (mkdir(fname, fstat_buf.st_mode) < 0 &&
|
|
geterrno() != EEXIST)
|
|
errmsg("Cannot make directory '%s'.\n", fname);
|
|
goto setmode;
|
|
|
|
#ifdef S_IFBLK
|
|
case S_IFBLK:
|
|
#ifdef HAVE_MKNOD
|
|
if (mknod(fname, fstat_buf.st_mode, fstat_buf.st_rdev) < 0)
|
|
errmsg("Cannot make block device '%s'.\n", fname);
|
|
goto setmode;
|
|
#else
|
|
goto err;
|
|
#endif
|
|
#endif
|
|
#ifdef S_IFCHR
|
|
case S_IFCHR:
|
|
#ifdef HAVE_MKNOD
|
|
if (mknod(fname, fstat_buf.st_mode, fstat_buf.st_rdev) < 0)
|
|
errmsg("Cannot make character device '%s'.\n", fname);
|
|
goto setmode;
|
|
#else
|
|
goto err;
|
|
#endif
|
|
#endif
|
|
#ifdef S_IFIFO
|
|
case S_IFIFO:
|
|
#ifdef HAVE_MKFIFO
|
|
if (mkfifo(fname, fstat_buf.st_mode) < 0)
|
|
errmsg("Cannot make fifo '%s'.\n", fname);
|
|
goto setmode;
|
|
#else
|
|
goto err;
|
|
#endif
|
|
#endif
|
|
#ifdef S_IFSOCK
|
|
case S_IFSOCK:
|
|
#ifdef HAVE_MKNOD
|
|
if (mknod(fname, fstat_buf.st_mode, 0) < 0)
|
|
errmsg("Cannot make socket '%s'.\n", fname);
|
|
goto setmode;
|
|
#else
|
|
goto err;
|
|
#endif
|
|
#endif
|
|
#ifdef S_IFLNK
|
|
case S_IFLNK:
|
|
if (symlink(&xname[3], fname) < 0)
|
|
errmsg("Cannot make symlink '%s'.\n", fname);
|
|
goto setmode;
|
|
#endif
|
|
|
|
case S_IFREG: break;
|
|
}
|
|
|
|
makedirs(fname, S_IRUSR|S_IWUSR|S_IXUSR|
|
|
S_IRGRP|S_IWGRP|S_IXGRP|
|
|
S_IROTH|S_IWOTH|S_IXOTH, TRUE);
|
|
if (isfirst)
|
|
f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0600);
|
|
else
|
|
f = open(fname, O_WRONLY|O_CREAT, 0600);
|
|
if (f < 0) {
|
|
errmsg("Cannot create '%s'.\n", fname);
|
|
return;
|
|
}
|
|
lseek(f, 0, SEEK_END);
|
|
extract_file(f, idr, fname);
|
|
if ((idr->flags[0] & ISO_MULTIEXTENT) == 0) {
|
|
#ifdef HAVE_FCHOWN
|
|
fchown(f, fstat_buf.st_uid, fstat_buf.st_gid);
|
|
#else
|
|
fchownat(AT_FDCWD, fname, fstat_buf.st_uid, fstat_buf.st_gid, 0);
|
|
#endif
|
|
#ifdef HAVE_FCHMOD
|
|
fchmod(f, fstat_buf.st_mode);
|
|
#else
|
|
fchmodat(AT_FDCWD, fname, fstat_buf.st_mode, 0);
|
|
#endif
|
|
times[0].tv_sec = fstat_buf.st_atime;
|
|
times[0].tv_nsec = stat_ansecs(&fstat_buf);
|
|
times[1].tv_sec = fstat_buf.st_mtime;
|
|
times[1].tv_nsec = stat_mnsecs(&fstat_buf);
|
|
#if defined(HAVE_FUTIMESAT) || defined(HAVE_FUTIMES) || defined(HAVE_FUTIMENS)
|
|
futimens(f, times);
|
|
#else
|
|
utimensat(AT_FDCWD, fname, times, 0);
|
|
#endif
|
|
isfirst = TRUE; /* Next call is for a new file */
|
|
} else {
|
|
isfirst = FALSE; /* Next call is a continuation */
|
|
}
|
|
close(f);
|
|
return;
|
|
setmode:
|
|
fchownat(AT_FDCWD, fname, fstat_buf.st_uid, fstat_buf.st_gid, AT_SYMLINK_NOFOLLOW);
|
|
fchmodat(AT_FDCWD, fname, fstat_buf.st_mode, AT_SYMLINK_NOFOLLOW);
|
|
times[0].tv_sec = fstat_buf.st_atime;
|
|
times[0].tv_nsec = stat_ansecs(&fstat_buf);
|
|
times[1].tv_sec = fstat_buf.st_mtime;
|
|
times[1].tv_nsec = stat_mnsecs(&fstat_buf);
|
|
utimensat(AT_FDCWD, fname, times, AT_SYMLINK_NOFOLLOW);
|
|
}
|
|
|
|
LOCAL void
|
|
extract_file(f, idr, fname)
|
|
int f;
|
|
struct iso_directory_record *idr;
|
|
char *fname;
|
|
{
|
|
int extent, len, tlen;
|
|
unsigned char buff[20480];
|
|
|
|
if (f == STDOUT_FILENO)
|
|
setmode(fileno(stdout), O_BINARY);
|
|
|
|
extent = isonum_733((unsigned char *)idr->extent);
|
|
len = isonum_733((unsigned char *)idr->size);
|
|
|
|
while (len > 0) {
|
|
tlen = (len > sizeof (buff) ? sizeof (buff) : len);
|
|
#ifdef USE_SCG
|
|
readsecs(extent - sector_offset, buff, ISO_BLOCKS(tlen));
|
|
#else
|
|
lseek(fileno(infile), ((off_t)(extent - sector_offset)) << 11, SEEK_SET);
|
|
read(fileno(infile), buff, tlen);
|
|
#endif
|
|
len -= tlen;
|
|
extent += ISO_BLOCKS(tlen);
|
|
if (write(f, buff, tlen) != tlen)
|
|
errmsg("Write error on '%s'.\n", fname);
|
|
}
|
|
}
|
|
|
|
|
|
LOCAL void
|
|
parse_cl_dir(idr, extent)
|
|
struct iso_directory_record *idr;
|
|
int extent;
|
|
{
|
|
char cl_name_buf[256*3];
|
|
|
|
strlcpy(cl_name_buf, name_buf, sizeof (cl_name_buf));
|
|
#ifdef USE_SCG
|
|
readsecs(extent - sector_offset, idr, 1);
|
|
#else
|
|
lseek(fileno(infile), ((off_t)(extent - sector_offset)) << 11, SEEK_SET);
|
|
read(fileno(infile), idr, 2048);
|
|
#endif
|
|
|
|
if (parse_de(idr) && use_rock)
|
|
dump_rr(idr);
|
|
strlcpy(name_buf, cl_name_buf, sizeof (name_buf));
|
|
}
|
|
|
|
LOCAL BOOL
|
|
parse_de(idr)
|
|
struct iso_directory_record *idr;
|
|
{
|
|
unsigned char uc;
|
|
|
|
if (idr->length[0] == 0)
|
|
return (FALSE);
|
|
memset(&fstat_buf, 0, sizeof (fstat_buf));
|
|
found_rr = 0;
|
|
name_buf[0] = xname[0] = 0;
|
|
fstat_buf.st_size = (off_t)(unsigned)isonum_733((unsigned char *)idr->size);
|
|
if (idr->flags[0] & 2)
|
|
fstat_buf.st_mode |= S_IFDIR;
|
|
else
|
|
fstat_buf.st_mode |= S_IFREG;
|
|
if (idr->name_len[0] == 1 && idr->name[0] == 0)
|
|
strcpy(name_buf, ".");
|
|
else if (idr->name_len[0] == 1 && idr->name[0] == 1)
|
|
strcpy(name_buf, "..");
|
|
else {
|
|
switch (ucs_level) {
|
|
case 3:
|
|
case 2:
|
|
case 1:
|
|
/*
|
|
* Unicode name. Convert as best we can.
|
|
*/
|
|
{
|
|
int j;
|
|
name_buf[0] = '\0';
|
|
#ifdef USE_ICONV
|
|
if (use_iconv(unls)) {
|
|
int u;
|
|
char *to = name_buf;
|
|
|
|
for (j = 0, u = 0; j < (int)idr->name_len[0] / 2; j++) {
|
|
char *ibuf = (char *)&idr->name[j*2];
|
|
size_t isize = 2; /* UCS-2 character size */
|
|
size_t osize = 4;
|
|
|
|
if (iconv(unls->sic_uni2cd, (__IC_CONST char **)&ibuf, &isize,
|
|
(char **)&to, &osize) == -1) {
|
|
int err = geterrno();
|
|
|
|
if ((err == EINVAL || err == EILSEQ) &&
|
|
osize == 4) {
|
|
*to = '_';
|
|
u += 1;
|
|
to++;
|
|
}
|
|
} else {
|
|
u += 4 - osize;
|
|
to = &name_buf[u];
|
|
}
|
|
}
|
|
j = u;
|
|
} else
|
|
#endif
|
|
for (j = 0; j < (int)idr->name_len[0] / 2; j++) {
|
|
UInt16_t unichar;
|
|
|
|
unichar = (idr->name[j*2] & 0xFF) * 256 +
|
|
(idr->name[j*2+1] & 0xFF);
|
|
|
|
/*
|
|
* Get the backconverted char
|
|
*/
|
|
if (unls)
|
|
uc = sic_uni2c(unls, unichar);
|
|
else
|
|
uc = unichar > 255 ? '_' : unichar;
|
|
|
|
name_buf[j] = uc ? uc : '_';
|
|
}
|
|
name_buf[j] = '\0';
|
|
}
|
|
break;
|
|
case 0:
|
|
/*
|
|
* Normal non-Unicode name.
|
|
*/
|
|
strncpy(name_buf, idr->name, idr->name_len[0]);
|
|
name_buf[idr->name_len[0]] = 0;
|
|
break;
|
|
default:
|
|
/*
|
|
* Don't know how to do these yet. Maybe they are the same
|
|
* as one of the above.
|
|
*/
|
|
exit(1);
|
|
}
|
|
}
|
|
memcpy(date_buf, idr->date, sizeof (idr->date));
|
|
/*
|
|
* Always first set up time stamps and file modes from
|
|
* ISO-9660. This is used as a fallback in case that
|
|
* there is no related Rock Ridge based data.
|
|
*/
|
|
fstat_buf.st_atime =
|
|
fstat_buf.st_mtime =
|
|
fstat_buf.st_ctime = iso9660_time(date_buf, NULL, FALSE);
|
|
fstat_buf.st_mode |= S_IRUSR|S_IXUSR |
|
|
S_IRGRP|S_IXGRP |
|
|
S_IROTH|S_IXOTH;
|
|
fstat_buf.st_nlink = 1;
|
|
fstat_buf.st_ino = 0;
|
|
fstat_buf.st_uid = 0;
|
|
fstat_buf.st_gid = 0;
|
|
if (iso9660_inodes) {
|
|
fstat_buf.st_ino = (unsigned long)
|
|
isonum_733((unsigned char *)idr->extent);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
LOCAL void
|
|
parse_dir(dp, rootname, extent, len)
|
|
struct todo *dp;
|
|
char *rootname;
|
|
int extent; /* Directory extent */
|
|
int len; /* Directory size */
|
|
{
|
|
struct todo *td;
|
|
int i;
|
|
struct iso_directory_record * idr;
|
|
struct iso_directory_record didr;
|
|
struct stat dstat;
|
|
unsigned char cl_buffer[2048];
|
|
unsigned char flags = 0;
|
|
Llong size = 0;
|
|
int sextent = 0;
|
|
int rlen;
|
|
int blen;
|
|
int rr_flags = 0;
|
|
static char *n = 0;
|
|
static int nlen = 0;
|
|
|
|
|
|
if (do_listing && (!do_find || !find_print))
|
|
printf(_("\nDirectory listing of %s\n"), rootname);
|
|
|
|
rlen = strlen(rootname);
|
|
|
|
while (len > 0) {
|
|
#ifdef USE_SCG
|
|
readsecs(extent - sector_offset, buffer, ISO_BLOCKS(sizeof (buffer)));
|
|
#else
|
|
lseek(fileno(infile), ((off_t)(extent - sector_offset)) << 11, SEEK_SET);
|
|
read(fileno(infile), buffer, sizeof (buffer));
|
|
#endif
|
|
len -= sizeof (buffer);
|
|
extent++;
|
|
i = 0;
|
|
while (1 == 1) {
|
|
idr = (struct iso_directory_record *) &buffer[i];
|
|
if (idr->length[0] == 0)
|
|
break;
|
|
parse_de(idr);
|
|
if (use_rock) {
|
|
rr_flags = dump_rr(idr);
|
|
|
|
if (rr_flags & RR_FLAG_CL) {
|
|
/*
|
|
* Need to reparse the child link
|
|
* but note that we parse "CL/."
|
|
* so we get no usable file name.
|
|
*/
|
|
idr = (struct iso_directory_record *) cl_buffer;
|
|
parse_cl_dir(idr, cl_extent);
|
|
} else if (rr_flags & RR_FLAG_RE)
|
|
goto cont; /* skip rr_moved */
|
|
}
|
|
if (Xtract &&
|
|
(idr->flags[0] & 2) != 0 &&
|
|
idr->name_len[0] == 1 &&
|
|
idr->name[0] == 0) {
|
|
/*
|
|
* The '.' entry.
|
|
*/
|
|
didr = *idr;
|
|
dstat = fstat_buf;
|
|
}
|
|
blen = strlen(name_buf);
|
|
|
|
blen = rlen + blen + 1;
|
|
if (nlen < blen) {
|
|
n = ___realloc(n, blen, _("find_stat name"));
|
|
nlen = blen;
|
|
}
|
|
strcatl(n, rootname, name_buf, (char *)0);
|
|
if (name_buf[0] == '.' && name_buf[1] == '\0')
|
|
n[rlen] = '\0';
|
|
|
|
if ((idr->flags[0] & 2) != 0 &&
|
|
((rr_flags & RR_FLAG_CL) ||
|
|
(idr->name_len[0] != 1 ||
|
|
(idr->name[0] != 0 && idr->name[0] != 1)))) {
|
|
/*
|
|
* This is a plain directory (neither "xxx/."
|
|
* nor "xxx/..").
|
|
* Add this directory to the todo list.
|
|
*/
|
|
int dir_loop = 0;
|
|
int nextent;
|
|
struct todo *tp = dp;
|
|
|
|
nextent = isonum_733((unsigned char *)idr->extent);
|
|
while (tp) {
|
|
if (tp->extent == nextent) {
|
|
dir_loop = 1;
|
|
break;
|
|
}
|
|
tp = tp->prev;
|
|
}
|
|
if (dir_loop == 0) {
|
|
td = (struct todo *) malloc(sizeof (*td));
|
|
if (td == NULL)
|
|
comerr(_("No memory.\n"));
|
|
td->next = NULL;
|
|
td->prev = dp;
|
|
td->extent = isonum_733((unsigned char *)idr->extent);
|
|
td->length = isonum_733((unsigned char *)idr->size);
|
|
td->name = (char *) malloc(strlen(rootname)
|
|
+ strlen(name_buf) + 2);
|
|
if (td->name == NULL)
|
|
comerr(_("No memory.\n"));
|
|
strcpy(td->name, rootname);
|
|
strcat(td->name, name_buf);
|
|
strcat(td->name, "/");
|
|
|
|
*todo_pp = td;
|
|
todo_pp = &td->next;
|
|
}
|
|
} else {
|
|
if (xtract && strcmp(xtract, n) == 0) {
|
|
extract_file(STDOUT_FILENO, idr, "stdout");
|
|
}
|
|
}
|
|
if (do_f &&
|
|
(idr->name_len[0] != 1 ||
|
|
(idr->name[0] != 0 && idr->name[0] != 1))) {
|
|
printf("%s\n", n);
|
|
}
|
|
if (do_listing || Xtract || do_find) {
|
|
/*
|
|
* In case if a multi-extent file, remember the
|
|
* start extent number.
|
|
*/
|
|
if ((idr->flags[0] & ISO_MULTIEXTENT) && size == 0)
|
|
sextent = isonum_733((unsigned char *)idr->extent);
|
|
|
|
if (debug ||
|
|
((idr->flags[0] & ISO_MULTIEXTENT) == 0 && size == 0)) {
|
|
if (dump_stat(rootname, idr, n,
|
|
isonum_733((unsigned char *)idr->extent))) {
|
|
if (Xtract) {
|
|
if ((idr->flags[0] & 2) != 0 &&
|
|
idr->name_len[0] != 1 &&
|
|
idr->name[0] != 1) {
|
|
char *p = n;
|
|
if (*p == '/')
|
|
p++;
|
|
makedirs(p,
|
|
S_IRUSR|S_IWUSR|S_IXUSR|
|
|
S_IRGRP|S_IWGRP|S_IXGRP|
|
|
S_IROTH|S_IWOTH|S_IXOTH,
|
|
FALSE);
|
|
} else {
|
|
if (myuid != 0 &&
|
|
S_ISDIR(fstat_buf.st_mode)) {
|
|
fstat_buf.st_mode |= S_IWUSR;
|
|
}
|
|
extract(rootname, idr, n);
|
|
}
|
|
}
|
|
}
|
|
} else if (Xtract && find_stat(rootname, idr, n, sextent)) {
|
|
/*
|
|
* Extract all multi extent files here...
|
|
*/
|
|
extract(rootname, idr, n);
|
|
}
|
|
size += fstat_buf.st_size;
|
|
if ((flags & ISO_MULTIEXTENT) &&
|
|
(idr->flags[0] & ISO_MULTIEXTENT) == 0) {
|
|
fstat_buf.st_size = size;
|
|
if (!debug)
|
|
idr->flags[0] |= ISO_MULTIEXTENT;
|
|
dump_stat(rootname, idr, n, sextent);
|
|
if (!debug)
|
|
idr->flags[0] &= ~ISO_MULTIEXTENT;
|
|
}
|
|
flags = idr->flags[0];
|
|
if ((idr->flags[0] & ISO_MULTIEXTENT) == 0)
|
|
size = 0;
|
|
}
|
|
cont:
|
|
i += buffer[i];
|
|
if (i > 2048 - offsetof(struct iso_directory_record, name[0])) break;
|
|
}
|
|
}
|
|
if (Xtract) {
|
|
char *nm = strrchr(rootname, '/');
|
|
|
|
if (nm != rootname)
|
|
nm++;
|
|
if (find_stat(rootname, &didr, nm, 0)) {
|
|
fstat_buf = dstat;
|
|
extract(rootname, &didr, rootname);
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCAL void
|
|
usage(excode)
|
|
int excode;
|
|
{
|
|
#ifdef USE_FIND
|
|
errmsgno(EX_BAD, _("Usage: %s [options] -i filename [-find [[find expr.]]\n"), get_progname());
|
|
#else
|
|
errmsgno(EX_BAD, _("Usage: %s [options] -i filename\n"), get_progname());
|
|
#endif
|
|
|
|
error(_("Options:\n"));
|
|
error(_("\t-help,-h Print this help\n"));
|
|
error(_("\t-version Print version info and exit\n"));
|
|
error(_("\t-debug Print additional debug info\n"));
|
|
error(_("\t-ignore-error Ignore errors\n"));
|
|
error(_("\t-d Print information from the primary volume descriptor\n"));
|
|
error(_("\t-f Generate output similar to 'find . -print'\n"));
|
|
#ifdef USE_FIND
|
|
error(_("\t-find [find expr.] Option separator: Use find command line to the right\n"));
|
|
#endif
|
|
error(_("\t-J Print information from Joliet extensions\n"));
|
|
error(_("\t-j charset Use charset to display Joliet file names\n"));
|
|
error(_("\t-l Generate output similar to 'ls -lR'\n"));
|
|
error(_("\t-p Print Path Table\n"));
|
|
error(_("\t-R Print information from Rock Ridge extensions\n"));
|
|
error(_("\t-s Print file size infos in multiples of sector size (%ld bytes).\n"), (long)PAGE);
|
|
error(_("\t-N sector Sector number where ISO image should start on CD\n"));
|
|
error(_("\t-T sector Sector number where actual session starts on CD\n"));
|
|
error(_("\t-i filename Filename to read ISO-9660 image from\n"));
|
|
error(_("\tdev=target SCSI target to use as CD/DVD-Recorder\n"));
|
|
error(_("\t-X Extract all matching files to the filesystem\n"));
|
|
error(_("\t-x pathname Extract specified file to stdout\n"));
|
|
exit(excode);
|
|
}
|
|
|
|
EXPORT int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int cac;
|
|
char * const *cav;
|
|
int c;
|
|
int ret = 0;
|
|
char *filename = NULL;
|
|
char *sdevname = NULL;
|
|
#if defined(USE_NLS)
|
|
char *dir;
|
|
#endif
|
|
/*
|
|
* Use toc_offset != 0 (-T #) if we have a complete multi-session
|
|
* disc that we want/need to play with.
|
|
* Here we specify the offset where we want to
|
|
* start searching for the TOC.
|
|
*/
|
|
int toc_offset = 0;
|
|
int extent;
|
|
struct todo * td;
|
|
struct iso_primary_descriptor ipd;
|
|
struct iso_primary_descriptor jpd;
|
|
struct eltorito_boot_descriptor bpd;
|
|
struct iso_directory_record * idr;
|
|
char *charset = NULL;
|
|
char *opts = "help,h,version,debug,ignore-error,d,p,i*,dev*,J,R,l,x*,X,find~,f,s,N#l,T#l,j*";
|
|
BOOL help = FALSE;
|
|
BOOL prvers = FALSE;
|
|
BOOL found_eltorito = FALSE;
|
|
int bootcat_offset = 0;
|
|
int voldesc_sum = 0;
|
|
char *cp;
|
|
|
|
|
|
save_args(argc, argv);
|
|
|
|
#if defined(USE_NLS)
|
|
setlocale(LC_ALL, "");
|
|
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
|
|
#define TEXT_DOMAIN "isoinfo" /* Use this only if it weren't */
|
|
#endif
|
|
dir = searchfileinpath("share/locale", F_OK,
|
|
SIP_ANY_FILE|SIP_NO_PATH, NULL);
|
|
if (dir)
|
|
(void) bindtextdomain(TEXT_DOMAIN, dir);
|
|
else
|
|
#if defined(PROTOTYPES) && defined(INS_BASE)
|
|
(void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
|
|
#else
|
|
(void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
|
|
#endif
|
|
(void) textdomain(TEXT_DOMAIN);
|
|
#endif
|
|
|
|
cac = argc - 1;
|
|
cav = argv + 1;
|
|
if (getallargs(&cac, &cav, opts,
|
|
&help, &help, &prvers, &debug, &ignerr,
|
|
&do_pvd, &do_pathtab,
|
|
&filename, &sdevname,
|
|
&use_joliet, &use_rock,
|
|
&do_listing,
|
|
&xtract, &Xtract,
|
|
getfind, NULL,
|
|
&do_f, &do_sectors,
|
|
§or_offset, &toc_offset,
|
|
&charset) < 0) {
|
|
errmsgno(EX_BAD, _("Bad Option: '%s'\n"), cav[0]);
|
|
usage(EX_BAD);
|
|
}
|
|
if (help)
|
|
usage(0);
|
|
if (prvers) {
|
|
printf(_("isoinfo %s (%s-%s-%s) Copyright (C) 1993-1999 %s (C) 1999-2016 %s\n"),
|
|
VERSION,
|
|
HOST_CPU, HOST_VENDOR, HOST_OS,
|
|
_("Eric Youngdale"),
|
|
_("Joerg Schilling"));
|
|
exit(0);
|
|
}
|
|
myuid = getuid();
|
|
#ifdef USE_FIND
|
|
if (do_find) {
|
|
finda_t fa;
|
|
|
|
cac = find_ac;
|
|
cav = find_av;
|
|
find_firstprim(&cac, &cav);
|
|
find_pac = cac;
|
|
find_pav = cav;
|
|
|
|
if (cac > 0) {
|
|
find_argsinit(&fa);
|
|
fa.walkflags = walkflags;
|
|
fa.Argc = cac;
|
|
fa.Argv = (char **)cav;
|
|
find_node = find_parse(&fa);
|
|
if (fa.primtype == FIND_ERRARG)
|
|
comexit(fa.error);
|
|
if (fa.primtype != FIND_ENDARGS)
|
|
comerrno(EX_BAD, _("Incomplete expression.\n"));
|
|
plusp = fa.plusp;
|
|
find_patlen = fa.patlen;
|
|
walkflags = fa.walkflags;
|
|
maxdepth = fa.maxdepth;
|
|
mindepth = fa.mindepth;
|
|
|
|
if (find_node && xtract) {
|
|
if (find_pname(find_node, "-exec") ||
|
|
find_pname(find_node, "-exec+") ||
|
|
find_pname(find_node, "-ok"))
|
|
comerrno(EX_BAD,
|
|
"Cannot -exec with '-o -'.\n");
|
|
}
|
|
if (find_node && find_hasprint(find_node))
|
|
find_print = TRUE;
|
|
}
|
|
if (find_ac > find_pac) {
|
|
errmsgno(EX_BAD, _("Unsupported pathspec for -find.\n"));
|
|
usage(EX_BAD);
|
|
}
|
|
#ifdef __not_yet__
|
|
if (find_ac <= 0 || find_ac == find_pac) {
|
|
errmsgno(EX_BAD, _("Missing pathspec for -find.\n"));
|
|
usage(EX_BAD);
|
|
}
|
|
#endif
|
|
|
|
walkinitstate(&walkstate);
|
|
if (find_patlen > 0) {
|
|
walkstate.patstate = ___malloc(sizeof (int) * find_patlen,
|
|
_("space for pattern state"));
|
|
}
|
|
|
|
find_timeinit(time(0));
|
|
walkstate.walkflags = walkflags;
|
|
walkstate.maxdepth = maxdepth;
|
|
walkstate.mindepth = mindepth;
|
|
walkstate.lname = NULL;
|
|
walkstate.tree = find_node;
|
|
walkstate.err = 0;
|
|
walkstate.pflags = 0;
|
|
}
|
|
#endif
|
|
cac = argc - 1;
|
|
cav = argv + 1;
|
|
if (!do_find && getfiles(&cac, &cav, opts) != 0) {
|
|
errmsgno(EX_BAD, _("Bad Argument: '%s'\n"), cav[0]);
|
|
usage(EX_BAD);
|
|
}
|
|
|
|
#if defined(USE_NLS) && defined(HAVE_NL_LANGINFO) && defined(CODESET)
|
|
/*
|
|
* If the locale has not been set up, nl_langinfo() returns the
|
|
* name of the default codeset. This should be either "646",
|
|
* "ISO-646", "ASCII", or something similar. Unfortunately, the
|
|
* POSIX standard does not include a list of valid locale names,
|
|
* so ne need to find all values in use.
|
|
*
|
|
* Observed:
|
|
* Solaris "646"
|
|
* Linux "ANSI_X3.4-1968" strange value from Linux...
|
|
*/
|
|
if (charset == NULL) {
|
|
char *codeset = nl_langinfo(CODESET);
|
|
Uchar *p;
|
|
|
|
if (codeset != NULL)
|
|
codeset = strdup(codeset);
|
|
if (codeset == NULL) /* Should not happen */
|
|
goto setcharset;
|
|
if (*codeset == '\0') /* Invalid locale */
|
|
goto setcharset;
|
|
|
|
for (p = (Uchar *)codeset; *p != '\0'; p++) {
|
|
if (islower(*p))
|
|
*p = toupper(*p);
|
|
}
|
|
p = (Uchar *)strstr(codeset, "ISO");
|
|
if (p != NULL) {
|
|
if (*p == '_' || *p == '-')
|
|
p++;
|
|
codeset = (char *)p;
|
|
}
|
|
if (strcmp("646", codeset) != 0 &&
|
|
strcmp("ASCII", codeset) != 0 &&
|
|
strcmp("US-ASCII", codeset) != 0 &&
|
|
strcmp("US_ASCII", codeset) != 0 &&
|
|
strcmp("USASCII", codeset) != 0 &&
|
|
strcmp("ANSI_X3.4-1968", codeset) != 0)
|
|
charset = nl_langinfo(CODESET);
|
|
|
|
if (codeset != NULL)
|
|
free(codeset);
|
|
|
|
#define verbose 1
|
|
if (verbose > 0 && charset != NULL) {
|
|
error(_("Setting input-charset to '%s' from locale.\n"),
|
|
charset);
|
|
}
|
|
}
|
|
setcharset:
|
|
/*
|
|
* Allow to switch off locale with -input-charset "".
|
|
*/
|
|
if (charset != NULL && *charset == '\0')
|
|
charset = NULL;
|
|
#endif
|
|
|
|
if (charset == NULL) {
|
|
#if (defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__DJGPP__) || defined(__MINGW32__)) && !defined(IS_CYGWIN_1)
|
|
unls = sic_open("cp437");
|
|
#else
|
|
unls = sic_open("default");
|
|
#endif
|
|
} else {
|
|
unls = sic_open(charset);
|
|
}
|
|
if (unls == NULL) { /* Unknown charset specified */
|
|
fprintf(stderr, _("Unknown charset: %s\nKnown charsets are:\n"),
|
|
charset);
|
|
sic_list(stdout); /* List all known charset names */
|
|
|
|
list_locales();
|
|
exit(EX_BAD);
|
|
exit(1);
|
|
}
|
|
|
|
if (filename != NULL && sdevname != NULL) {
|
|
errmsgno(EX_BAD, _("Only one of -i or dev= allowed\n"));
|
|
usage(EX_BAD);
|
|
}
|
|
#ifdef USE_SCG
|
|
if (filename == NULL && sdevname == NULL)
|
|
cdr_defaults(&sdevname, NULL, NULL, NULL, NULL);
|
|
#endif
|
|
if (filename == NULL && sdevname == NULL) {
|
|
fprintf(stderr, _("ISO-9660 image not specified\n"));
|
|
usage(EX_BAD);
|
|
}
|
|
|
|
if (filename != NULL)
|
|
infile = fopen(filename, "rb");
|
|
else
|
|
filename = sdevname;
|
|
|
|
if (infile != NULL) {
|
|
/* EMPTY */;
|
|
#ifdef USE_SCG
|
|
} else if (scsidev_open(filename) < 0) {
|
|
#else
|
|
} else {
|
|
#endif
|
|
fprintf(stderr, _("Unable to open %s\n"), filename);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Absolute sector offset, so don't subtract sector_offset here.
|
|
*/
|
|
#ifdef USE_SCG
|
|
readsecs(16 + toc_offset, &ipd, ISO_BLOCKS(sizeof (ipd)));
|
|
#else
|
|
lseek(fileno(infile), ((off_t)(16 + toc_offset)) <<11, SEEK_SET);
|
|
read(fileno(infile), &ipd, sizeof (ipd));
|
|
#endif
|
|
idr = (struct iso_directory_record *)ipd.root_directory_record;
|
|
for (c = 0, cp = (char *)&ipd; c < 2048; c++)
|
|
voldesc_sum += *cp++ & 0xFF;
|
|
if (GET_UBYTE(ipd.type) == ISO_VD_PRIMARY) {
|
|
c = 17;
|
|
do {
|
|
#ifdef USE_SCG
|
|
readsecs(c + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd)));
|
|
#else
|
|
lseek(fileno(infile), ((off_t)(c + toc_offset)) <<11, SEEK_SET);
|
|
read(fileno(infile), &jpd, sizeof (jpd));
|
|
#endif
|
|
} while (++c < 32 && GET_UBYTE(jpd.type) != ISO_VD_END);
|
|
if (GET_UBYTE(jpd.type) == ISO_VD_END) do {
|
|
#ifdef USE_SCG
|
|
readsecs(c + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd)));
|
|
#else
|
|
lseek(fileno(infile), ((off_t)(c + toc_offset)) <<11, SEEK_SET);
|
|
read(fileno(infile), &jpd, sizeof (jpd));
|
|
#endif
|
|
cp = (char *)&jpd;
|
|
if (strncmp(cp, "MKI ", 4) == 0) {
|
|
int sum;
|
|
|
|
sum = cp[2045] & 0xFF;
|
|
sum *= 256;
|
|
sum += cp[2046] & 0xFF;
|
|
sum *= 256;
|
|
sum += cp[2047] & 0xFF;
|
|
if (sum == voldesc_sum)
|
|
iso9660_inodes = TRUE;
|
|
break;
|
|
}
|
|
} while (++c < 48);
|
|
}
|
|
|
|
/*
|
|
* Read '.' entry for the root directory.
|
|
*/
|
|
extent = isonum_733((unsigned char *)idr->extent);
|
|
#ifdef USE_SCG
|
|
readsecs(extent - sector_offset, buffer, ISO_BLOCKS(sizeof (buffer)));
|
|
#else
|
|
lseek(fileno(infile), ((off_t)(extent - sector_offset)) <<11, SEEK_SET);
|
|
read(fileno(infile), buffer, sizeof (buffer));
|
|
#endif
|
|
c = dump_rr((struct iso_directory_record *) buffer);
|
|
if (c == 0 ||
|
|
(c & (RR_FLAG_SP | RR_FLAG_ER)) == 0 || su_version < 1 || rr_version < 1) {
|
|
if (!debug)
|
|
use_rock = FALSE;
|
|
}
|
|
if (do_pvd) {
|
|
/*
|
|
* High sierra:
|
|
*
|
|
* DESC TYPE == 1 (VD_SFS) offset 8 len 1
|
|
* STR ID == "CDROM" offset 9 len 5
|
|
* STD_VER == 1 offset 14 len 1
|
|
*/
|
|
if ((((char *)&ipd)[8] == 1) &&
|
|
(strncmp(&((char *)&ipd)[9], "CDROM", 5) == 0) &&
|
|
(((char *)&ipd)[14] == 1)) {
|
|
printf(_("CD-ROM is in High Sierra format\n"));
|
|
exit(0);
|
|
}
|
|
/*
|
|
* ISO 9660:
|
|
*
|
|
* DESC TYPE == 1 (VD_PVD) offset 0 len 1
|
|
* STR ID == "CD001" offset 1 len 5
|
|
* STD_VER == 1 offset 6 len 1
|
|
*/
|
|
if ((ipd.type[0] != ISO_VD_PRIMARY) ||
|
|
(strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) ||
|
|
(ipd.version[0] != 1)) {
|
|
printf(_("CD-ROM is NOT in ISO 9660 format\n"));
|
|
exit(1);
|
|
}
|
|
|
|
printf(_("CD-ROM is in ISO 9660 format\n"));
|
|
if (!use_joliet)
|
|
list_vd(&ipd, FALSE);
|
|
{
|
|
int block = 16;
|
|
movebytes(&ipd, &jpd, sizeof (ipd));
|
|
while ((Uchar)jpd.type[0] != ISO_VD_END) {
|
|
|
|
if (debug && (Uchar) jpd.type[0] == ISO_VD_SUPPLEMENTARY)
|
|
error(_("Joliet escape sequence 0: '%c' 1: '%c' 2: '%c' 3: '%c'\n"),
|
|
jpd.escape_sequences[0],
|
|
jpd.escape_sequences[1],
|
|
jpd.escape_sequences[2],
|
|
jpd.escape_sequences[3]);
|
|
/*
|
|
* If Joliet UCS escape sequence found, we may be wrong
|
|
*/
|
|
if (jpd.escape_sequences[0] == '%' &&
|
|
jpd.escape_sequences[1] == '/' &&
|
|
(jpd.escape_sequences[3] == '\0' ||
|
|
jpd.escape_sequences[3] == ' ') &&
|
|
(jpd.escape_sequences[2] == '@' ||
|
|
jpd.escape_sequences[2] == 'C' ||
|
|
jpd.escape_sequences[2] == 'E')) {
|
|
|
|
if (jpd.version[0] == 1)
|
|
goto nextblock;
|
|
}
|
|
if (jpd.type[0] == 0) {
|
|
movebytes(&jpd, &bpd, sizeof (bpd));
|
|
if (strncmp(bpd.system_id, EL_TORITO_ID, sizeof (EL_TORITO_ID)) == 0) {
|
|
bootcat_offset = (Uchar)bpd.bootcat_ptr[0] +
|
|
(Uchar)bpd.bootcat_ptr[1] * 256 +
|
|
(Uchar)bpd.bootcat_ptr[2] * 65536 +
|
|
(Uchar)bpd.bootcat_ptr[3] * 16777216;
|
|
found_eltorito = TRUE;
|
|
printf(_("El Torito VD version %d found, boot catalog is in sector %d\n"),
|
|
bpd.version[0],
|
|
bootcat_offset);
|
|
}
|
|
}
|
|
if (jpd.version[0] == 2) {
|
|
printf(_("CD-ROM uses ISO 9660:1999 relaxed format\n"));
|
|
break;
|
|
}
|
|
|
|
nextblock:
|
|
block++;
|
|
#ifdef USE_SCG
|
|
readsecs(block + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd)));
|
|
#else
|
|
lseek(fileno(infile), ((off_t)(block + toc_offset)) <<11, SEEK_SET);
|
|
read(fileno(infile), &jpd, sizeof (jpd));
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* ISO 9660:
|
|
*
|
|
* DESC TYPE == 1 (VD_PVD) offset 0 len 1
|
|
* STR ID == "CD001" offset 1 len 5
|
|
* STD_VER == 1 offset 6 len 1
|
|
*/
|
|
if ((ipd.type[0] != ISO_VD_PRIMARY) ||
|
|
(strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) ||
|
|
(ipd.version[0] != 1)) {
|
|
printf(_("CD-ROM is NOT in ISO 9660 format\n"));
|
|
exit(1);
|
|
}
|
|
|
|
if (use_joliet || do_pvd) {
|
|
int block = 16;
|
|
movebytes(&ipd, &jpd, sizeof (ipd));
|
|
while ((unsigned char) jpd.type[0] != ISO_VD_END) {
|
|
if (debug && (unsigned char) jpd.type[0] == ISO_VD_SUPPLEMENTARY)
|
|
error(_("Joliet escape sequence 0: '%c' 1: '%c' 2: '%c' 3: '%c'\n"),
|
|
jpd.escape_sequences[0],
|
|
jpd.escape_sequences[1],
|
|
jpd.escape_sequences[2],
|
|
jpd.escape_sequences[3]);
|
|
/*
|
|
* Find the UCS escape sequence.
|
|
*/
|
|
if (jpd.escape_sequences[0] == '%' &&
|
|
jpd.escape_sequences[1] == '/' &&
|
|
(jpd.escape_sequences[3] == '\0' ||
|
|
jpd.escape_sequences[3] == ' ') &&
|
|
(jpd.escape_sequences[2] == '@' ||
|
|
jpd.escape_sequences[2] == 'C' ||
|
|
jpd.escape_sequences[2] == 'E')) {
|
|
break;
|
|
}
|
|
|
|
block++;
|
|
#ifdef USE_SCG
|
|
readsecs(block + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd)));
|
|
#else
|
|
lseek(fileno(infile),
|
|
((off_t)(block + toc_offset)) <<11, SEEK_SET);
|
|
read(fileno(infile), &jpd, sizeof (jpd));
|
|
#endif
|
|
}
|
|
|
|
if (use_joliet && ((unsigned char) jpd.type[0] == ISO_VD_END)) {
|
|
fprintf(stderr, _("Unable to find Joliet SVD\n"));
|
|
exit(1);
|
|
}
|
|
|
|
switch (jpd.escape_sequences[2]) {
|
|
case '@':
|
|
ucs_level = 1;
|
|
break;
|
|
case 'C':
|
|
ucs_level = 2;
|
|
break;
|
|
case 'E':
|
|
ucs_level = 3;
|
|
break;
|
|
}
|
|
|
|
if (ucs_level > 3) {
|
|
fprintf(stderr,
|
|
_("Don't know what ucs_level == %d means\n"),
|
|
ucs_level);
|
|
exit(1);
|
|
}
|
|
if (jpd.escape_sequences[3] == ' ')
|
|
errmsgno(EX_BAD,
|
|
_("Warning: Joliet escape sequence uses illegal space at offset 3\n"));
|
|
}
|
|
|
|
if (do_pvd) {
|
|
if (ucs_level > 0) {
|
|
if (use_joliet) {
|
|
printf(_("\nJoliet with UCS level %d found,"), ucs_level);
|
|
printf(_(" Joliet volume descriptor:\n"));
|
|
list_vd(&jpd, TRUE);
|
|
} else {
|
|
printf(_("\nJoliet with UCS level %d found."), ucs_level);
|
|
}
|
|
} else {
|
|
printf(_("NO Joliet present\n"));
|
|
}
|
|
|
|
if (c != 0) {
|
|
#ifdef RR_DEBUG
|
|
printf("RR %X %d\n", c, c);
|
|
#endif
|
|
if (c & RR_FLAG_SP) {
|
|
printf(
|
|
_("\nSUSP signatures version %d found\n"),
|
|
su_version);
|
|
if (c & RR_FLAG_ER) {
|
|
if (rr_version < 1) {
|
|
printf(
|
|
_("No valid Rock Ridge signature found\n"));
|
|
} else {
|
|
printf(
|
|
_("Rock Ridge signatures version %d found\n"),
|
|
rr_version);
|
|
printf(
|
|
_("Rock Ridge id '%s'\n"),
|
|
er_id);
|
|
}
|
|
}
|
|
} else {
|
|
printf(
|
|
_("\nBad Rock Ridge signatures found (SU record missing)\n"));
|
|
}
|
|
/*
|
|
* This is currently a no op!
|
|
* We need to check the first plain file instead of
|
|
* the '.' entry in the root directory.
|
|
*/
|
|
if (c & RR_FLAG_AA) {
|
|
printf(_("\nApple signatures version %d found\n"),
|
|
aa_version);
|
|
}
|
|
} else {
|
|
printf(_("\nNo SUSP/Rock Ridge present\n"));
|
|
}
|
|
if (found_eltorito)
|
|
printf_bootinfo(infile, bootcat_offset);
|
|
exit(0);
|
|
}
|
|
|
|
if (use_joliet)
|
|
idr = (struct iso_directory_record *)jpd.root_directory_record;
|
|
|
|
if (do_pathtab) {
|
|
if (use_joliet) {
|
|
dump_pathtab(isonum_731(jpd.type_l_path_table),
|
|
isonum_733((unsigned char *)jpd.path_table_size));
|
|
} else {
|
|
dump_pathtab(isonum_731(ipd.type_l_path_table),
|
|
isonum_733((unsigned char *)ipd.path_table_size));
|
|
}
|
|
}
|
|
|
|
parse_dir(todo_idr, "/", isonum_733((unsigned char *)idr->extent),
|
|
isonum_733((unsigned char *)idr->size));
|
|
td = todo_idr;
|
|
while (td) {
|
|
parse_dir(td, td->name, td->extent, td->length);
|
|
free(td->name);
|
|
td = td->next;
|
|
}
|
|
|
|
/*
|
|
* Execute all unflushed '-exec .... {} +' expressions.
|
|
*/
|
|
if (do_find) {
|
|
find_plusflush(plusp, &walkstate);
|
|
#ifdef __use_find_free__
|
|
find_free(Tree, &fa);
|
|
#endif
|
|
if (walkstate.patstate != NULL)
|
|
free(walkstate.patstate);
|
|
ret = walkstate.err;
|
|
}
|
|
|
|
if (infile != NULL)
|
|
fclose(infile);
|
|
return (ret);
|
|
}
|
|
|
|
LOCAL void
|
|
list_vd(vp, ucs)
|
|
struct iso_primary_descriptor *vp;
|
|
BOOL ucs;
|
|
{
|
|
struct iso_directory_record *idr = (struct iso_directory_record *)
|
|
vp->root_directory_record;
|
|
|
|
printf(_("System id: "));
|
|
printchars(vp->system_id, 32, ucs);
|
|
putchar('\n');
|
|
printf(_("Volume id: "));
|
|
printchars(vp->volume_id, 32, ucs);
|
|
putchar('\n');
|
|
|
|
printf(_("Volume set id: "));
|
|
printchars(vp->volume_set_id, 128, ucs);
|
|
putchar('\n');
|
|
printf(_("Publisher id: "));
|
|
printchars(vp->publisher_id, 128, ucs);
|
|
putchar('\n');
|
|
printf(_("Data preparer id: "));
|
|
printchars(vp->preparer_id, 128, ucs);
|
|
putchar('\n');
|
|
printf(_("Application id: "));
|
|
printchars(vp->application_id, 128, ucs);
|
|
putchar('\n');
|
|
|
|
printf(_("Copyright File id: "));
|
|
printchars(vp->copyright_file_id, 37, ucs);
|
|
putchar('\n');
|
|
printf(_("Abstract File id: "));
|
|
printchars(vp->abstract_file_id, 37, ucs);
|
|
putchar('\n');
|
|
printf(_("Bibliographic File id: "));
|
|
printchars(vp->bibliographic_file_id, 37, ucs);
|
|
putchar('\n');
|
|
|
|
printf(_("Volume set size is: %d\n"), isonum_723(vp->volume_set_size));
|
|
printf(_("Volume set sequence number is: %d\n"), isonum_723(vp->volume_sequence_number));
|
|
printf(_("Logical block size is: %d\n"), isonum_723(vp->logical_block_size));
|
|
printf(_("Volume size is: %d\n"), isonum_733((unsigned char *)vp->volume_space_size));
|
|
if (debug) {
|
|
int dextent;
|
|
int dlen;
|
|
|
|
dextent = isonum_733((unsigned char *)idr->extent);
|
|
dlen = isonum_733((unsigned char *)idr->size);
|
|
printf(_("Root directory extent: %d size: %d\n"),
|
|
dextent, dlen);
|
|
printf(_("Path table size is: %d\n"),
|
|
isonum_733((unsigned char *)vp->path_table_size));
|
|
printf(_("L Path table start: %d\n"),
|
|
isonum_731(vp->type_l_path_table));
|
|
printf(_("L Path opt table start: %d\n"),
|
|
isonum_731(vp->opt_type_l_path_table));
|
|
printf(_("M Path table start: %d\n"),
|
|
isonum_732(vp->type_m_path_table));
|
|
printf(_("M Path opt table start: %d\n"),
|
|
isonum_732(vp->opt_type_m_path_table));
|
|
printf(_("Creation Date: %s\n"),
|
|
sdate(vp->creation_date));
|
|
printf(_("Modification Date: %s\n"),
|
|
sdate(vp->modification_date));
|
|
printf(_("Expiration Date: %s\n"),
|
|
sdate(vp->expiration_date));
|
|
printf(_("Effective Date: %s\n"),
|
|
sdate(vp->effective_date));
|
|
printf(_("File structure version: %d\n"),
|
|
vp->file_structure_version[0]);
|
|
}
|
|
}
|
|
|
|
LOCAL void
|
|
list_locales()
|
|
{
|
|
int n;
|
|
|
|
n = sic_list(stdout);
|
|
if (n <= 0) {
|
|
errmsgno(EX_BAD, "'%s/lib/siconv/' %s.\n",
|
|
INS_BASE, n < 0 ? _("missing"):_("incomplete"));
|
|
if (n == 0) {
|
|
errmsgno(EX_BAD,
|
|
_("Check '%s/lib/siconv/' for missing translation tables.\n"),
|
|
INS_BASE);
|
|
}
|
|
}
|
|
#ifdef USE_ICONV
|
|
if (n > 0) {
|
|
errmsgno(EX_BAD,
|
|
_("'iconv -l' lists more available names.\n"));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#include <schily/intcvt.h>
|
|
|
|
LOCAL void
|
|
printf_bootinfo(f, bootcat_offset)
|
|
FILE *f;
|
|
int bootcat_offset;
|
|
{
|
|
int s = 0;
|
|
int i;
|
|
Uchar *p;
|
|
struct eltorito_validation_entry *evp;
|
|
struct eltorito_defaultboot_entry *ebe;
|
|
|
|
#ifdef USE_SCG
|
|
readsecs(bootcat_offset, buffer, ISO_BLOCKS(sizeof (buffer)));
|
|
#else
|
|
lseek(fileno(f), ((off_t)bootcat_offset) <<11, SEEK_SET);
|
|
read(fileno(f), buffer, sizeof (buffer));
|
|
#endif
|
|
|
|
evp = (struct eltorito_validation_entry *)buffer;
|
|
ebe = (struct eltorito_defaultboot_entry *)&buffer[32];
|
|
|
|
|
|
p = (Uchar *)evp;
|
|
for (i = 0; i < 32; i += 2) {
|
|
s += p[i] & 0xFF;
|
|
s += (p[i+1] & 0xFF) * 256;
|
|
}
|
|
s = s % 65536;
|
|
|
|
printf(_("Eltorito validation header:\n"));
|
|
printf(_(" Hid %d\n"), (Uchar)evp->headerid[0]);
|
|
printf(_(" Arch %d (%s)\n"), (Uchar)evp->arch[0], arch_name((Uchar)evp->arch[0]));
|
|
printf(_(" ID '%.23s'\n"), evp->id);
|
|
printf(_(" Cksum %2.2X %2.2X %s\n"), (Uchar)evp->cksum[0], (Uchar)evp->cksum[1],
|
|
s == 0 ? _("OK"):_("BAD"));
|
|
printf(_(" Key %X %X\n"), (Uchar)evp->key1[0], (Uchar)evp->key2[0]);
|
|
|
|
printf(_(" Eltorito defaultboot header:\n"));
|
|
printf(_(" Bootid %X (%s)\n"), (Uchar)ebe->boot_id[0], boot_name((Uchar)ebe->boot_id[0]));
|
|
printf(_(" Boot media %X (%s)\n"), (Uchar)ebe->boot_media[0], bootmedia_name((Uchar)ebe->boot_media[0]));
|
|
printf(_(" Load segment %X\n"), la_to_2_byte(ebe->loadseg));
|
|
printf(_(" Sys type %X\n"), (Uchar)ebe->sys_type[0]);
|
|
printf(_(" Nsect %X\n"), la_to_2_byte(ebe->nsect));
|
|
printf(_(" Bootoff %lX %ld\n"), la_to_4_byte(ebe->bootoff), la_to_4_byte(ebe->bootoff));
|
|
|
|
}
|
|
|
|
LOCAL char *
|
|
arch_name(val)
|
|
int val;
|
|
{
|
|
switch (val) {
|
|
|
|
case EL_TORITO_ARCH_x86:
|
|
return ("x86");
|
|
case EL_TORITO_ARCH_PPC:
|
|
return ("PPC");
|
|
case EL_TORITO_ARCH_MAC:
|
|
return ("MAC");
|
|
default:
|
|
return ("Unknown Arch");
|
|
}
|
|
}
|
|
|
|
LOCAL char *
|
|
boot_name(val)
|
|
int val;
|
|
{
|
|
switch (val) {
|
|
|
|
case EL_TORITO_BOOTABLE:
|
|
return ("bootable");
|
|
case EL_TORITO_NOT_BOOTABLE:
|
|
return ("not bootable");
|
|
default:
|
|
return ("Illegal");
|
|
}
|
|
}
|
|
|
|
LOCAL char *
|
|
bootmedia_name(val)
|
|
int val;
|
|
{
|
|
switch (val) {
|
|
|
|
case EL_TORITO_MEDIA_NOEMUL:
|
|
return ("No Emulation Boot");
|
|
case EL_TORITO_MEDIA_12FLOP:
|
|
return ("1200 Floppy");
|
|
case EL_TORITO_MEDIA_144FLOP:
|
|
return ("1.44MB Floppy");
|
|
case EL_TORITO_MEDIA_288FLOP:
|
|
return ("2.88MB Floppy");
|
|
case EL_TORITO_MEDIA_HD:
|
|
return ("Hard Disk Emulation");
|
|
default:
|
|
return ("Illegal Bootmedia");
|
|
}
|
|
}
|
|
|
|
LOCAL int
|
|
time_cvt(dp, len)
|
|
unsigned char *dp;
|
|
int len;
|
|
{
|
|
int ret;
|
|
|
|
for (ret = 0; --len >= 0; ) {
|
|
ret *= 10;
|
|
ret += *dp++ - '0';
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
LOCAL time_t
|
|
iso9660_time(date, hsecp, longfmt)
|
|
unsigned char *date;
|
|
int *hsecp;
|
|
BOOL longfmt;
|
|
{
|
|
time_t t;
|
|
int y;
|
|
int m;
|
|
int d;
|
|
int days;
|
|
int hour;
|
|
int min;
|
|
int sec;
|
|
int hsec;
|
|
int gmtoff;
|
|
|
|
if (longfmt) {
|
|
y = time_cvt(&date[0], 4); /* Year 0..9999 */
|
|
m = time_cvt(&date[4], 2);
|
|
d = time_cvt(&date[6], 2);
|
|
hour = time_cvt(&date[8], 2);
|
|
min = time_cvt(&date[10], 2);
|
|
sec = time_cvt(&date[12], 2);
|
|
hsec = time_cvt(&date[14], 2);
|
|
gmtoff = ((char *)date)[16];
|
|
} else {
|
|
y = date[0] + 1900; /* Year 1900..2155 */
|
|
m = date[1];
|
|
d = date[2];
|
|
hour = date[3];
|
|
min = date[4];
|
|
sec = date[5];
|
|
hsec = 0;
|
|
gmtoff = ((char *)date)[6];
|
|
}
|
|
if (hsecp)
|
|
*hsecp = hsec;
|
|
/*
|
|
* The original algorithm did win a Fortan contest in early times.
|
|
* It computes days relative to September 19th 1989.
|
|
* days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100;
|
|
* The updated algorithm was modified to use Jan 1st 1970 as base
|
|
* and was taken from FreeBSD.
|
|
*/
|
|
days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239;
|
|
t = days;
|
|
t = ((((t * 24) + hour) * 60 + min) * 60) + sec;
|
|
if (-48 <= gmtoff && gmtoff <= 52)
|
|
t -= gmtoff * 15 * 60;
|
|
return (t);
|
|
}
|
|
|
|
#ifdef USE_FIND
|
|
/* ARGSUSED */
|
|
LOCAL int
|
|
getfind(arg, valp, pac, pav)
|
|
char *arg;
|
|
long *valp; /* Not used until we introduce a ptr to opt struct */
|
|
int *pac;
|
|
char *const **pav;
|
|
{
|
|
do_find = TRUE;
|
|
find_ac = *pac;
|
|
find_av = *pav;
|
|
find_ac--, find_av++;
|
|
return (NOARGS);
|
|
}
|
|
|
|
/*
|
|
* Called from dump_stat()
|
|
*/
|
|
LOCAL BOOL
|
|
find_stat(rootname, idr, fname, extent)
|
|
char *rootname;
|
|
struct iso_directory_record *idr;
|
|
char *fname;
|
|
int extent;
|
|
{
|
|
BOOL ret;
|
|
int rlen;
|
|
|
|
if (name_buf[0] == '.' && name_buf[1] == '.' && name_buf[2] == '\0')
|
|
if (find_node)
|
|
return (FALSE);
|
|
|
|
if (find_node == NULL) /* No find(1) rules */
|
|
return (TRUE); /* so pass everything */
|
|
|
|
rlen = strlen(rootname);
|
|
|
|
#ifdef HAVE_ST_BLKSIZE
|
|
fstat_buf.st_blksize = 0;
|
|
#endif
|
|
#ifdef HAVE_ST_BLOCKS
|
|
fstat_buf.st_blocks = (fstat_buf.st_size+1023) / DEV_BSIZE;
|
|
#endif
|
|
walkstate.lname = &xname[3];
|
|
walkstate.pflags = PF_ACL|PF_XATTR;
|
|
#ifdef XXX
|
|
if (info->f_xflags & (XF_ACL_ACCESS|XF_ACL_DEFAULT))
|
|
walkstate.pflags |= PF_HAS_ACL;
|
|
if (info->f_xflags & XF_XATTR)
|
|
walkstate.pflags |= PF_HAS_XATTR;
|
|
#endif
|
|
|
|
ret = find_expr(fname, &fname[rlen], &fstat_buf, &walkstate, find_node);
|
|
if (!ret)
|
|
return (ret);
|
|
return (ret);
|
|
}
|
|
#endif /* USE_FIND */
|