Rizin
unix-like reverse engineering framework and cli tools
cabextract.c File Reference
#include <sys/types.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
#include <limits.h>
#include <locale.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include "getopt.h"
#include <mspack.h>
#include <md5.h>

Go to the source code of this file.

Classes

struct  file_mem
 
struct  filter
 
struct  cabextract_args
 
struct  mspack_file_p
 

Macros

#define _GNU_SOURCE   1
 
#define FNM_CASEFOLD   (0)
 

Functions

static int process_cabinet (char *cabname)
 
static void load_spanning_cabinets (struct mscabd_cabinet *basecab, char *basename)
 
static char * find_cabinet_file (char *origcab, char *cabname)
 
static int unix_path_seperators (struct mscabd_file *files)
 
static char * create_output_name (const char *fname, const char *dir, int lower, int isunix, int unicode)
 
static void set_date_and_perm (struct mscabd_file *file, char *filename)
 
static void memorise_file (struct file_mem **fml, char *name, char *from)
 
static int recall_file (struct file_mem *fml, char *name, char **from)
 
static void forget_files (struct file_mem **fml)
 
static void add_filter (char *arg)
 
static void free_filters ()
 
static int ensure_filepath (char *path)
 
static char * cab_error (struct mscab_decompressor *cd)
 
static struct mspack_filecabx_open (struct mspack_system *this, const char *filename, int mode)
 
static void cabx_close (struct mspack_file *file)
 
static int cabx_read (struct mspack_file *file, void *buffer, int bytes)
 
static int cabx_write (struct mspack_file *file, void *buffer, int bytes)
 
static int cabx_seek (struct mspack_file *file, off_t offset, int mode)
 
static off_t cabx_tell (struct mspack_file *file)
 
static void cabx_msg (struct mspack_file *file, const char *format,...)
 
static void * cabx_alloc (struct mspack_system *this, size_t bytes)
 
static void cabx_free (void *buffer)
 
static void cabx_copy (void *src, void *dest, size_t bytes)
 
int main (int argc, char *argv[])
 

Variables

struct option optlist []
 
const char * OPTSTRING = "d:fF:hlLpqstv"
 
struct mscab_decompressorcabd = NULL
 
struct file_memcab_args = NULL
 
struct file_memcab_exts = NULL
 
struct file_memcab_seen = NULL
 
mode_t user_umask = 0
 
struct cabextract_args args
 
const char * STDOUT_FNAME = "stdout"
 
const char * TEST_FNAME = "test"
 
struct md5_ctx md5_context
 
unsigned char md5_result [16]
 
static struct mspack_system cabextract_system
 

Macro Definition Documentation

◆ _GNU_SOURCE

#define _GNU_SOURCE   1

Definition at line 23 of file cabextract.c.

◆ FNM_CASEFOLD

#define FNM_CASEFOLD   (0)

Definition at line 74 of file cabextract.c.

Function Documentation

◆ add_filter()

static void add_filter ( char *  arg)
static

Adds a filter to args.filters. On first call, sets up free_filters() to run at exit.

Parameters
argfilter to add

Definition at line 1094 of file cabextract.c.

1094  {
1095  struct filter *f = malloc(sizeof(struct filter));
1096  if (f) {
1097  if (!args.filters) {
1098  atexit(free_filters);
1099  }
1100  f->next = args.filters;
1101  f->filter = arg;
1102  args.filters = f;
1103  }
1104 }
static const char * arg(RzAnalysis *a, csh *handle, cs_insn *insn, char *buf, int n)
Definition: arm_esil32.c:136
struct cabextract_args args
Definition: cabextract.c:134
static void free_filters()
Definition: cabextract.c:1107
void * malloc(size_t size)
Definition: malloc.c:123
#define f(i)
Definition: sha256.c:46
struct filter * filters
Definition: cabextract.c:122

References arg(), args, f, cabextract_args::filters, free_filters(), and malloc().

Referenced by main().

◆ cab_error()

static char * cab_error ( struct mscab_decompressor cd)
static

Returns a string with an error message appropriate for the last error of the CAB decompressor.

Parameters
cdthe CAB decompressor.
Returns
a constant string with an appropriate error message.

Definition at line 1146 of file cabextract.c.

1146  {
1147  switch (cd->last_error(cd)) {
1148  case MSPACK_ERR_OPEN:
1149  return errno ? strerror(errno) : "file open error";
1150  case MSPACK_ERR_READ:
1151  return errno ? strerror(errno) : "file read error";
1152  case MSPACK_ERR_WRITE:
1153  return errno ? strerror(errno) : "file write error";
1154  case MSPACK_ERR_SEEK:
1155  return errno ? strerror(errno) : "file seek error";
1156  case MSPACK_ERR_NOMEMORY:
1157  return "out of memory";
1158  case MSPACK_ERR_SIGNATURE:
1159  return "bad CAB signature";
1160  case MSPACK_ERR_DATAFORMAT:
1161  return "error in CAB data format";
1162  case MSPACK_ERR_CHECKSUM:
1163  return "checksum error";
1164  case MSPACK_ERR_DECRUNCH:
1165  return "decompression error";
1166  }
1167  return "unknown error";
1168 }
static csh cd
Definition: asm_mips_cs.c:10
#define MSPACK_ERR_SEEK
Definition: mspack.h:495
#define MSPACK_ERR_OPEN
Definition: mspack.h:489
#define MSPACK_ERR_WRITE
Definition: mspack.h:493
#define MSPACK_ERR_CHECKSUM
Definition: mspack.h:503
#define MSPACK_ERR_SIGNATURE
Definition: mspack.h:499
#define MSPACK_ERR_DATAFORMAT
Definition: mspack.h:501
#define MSPACK_ERR_DECRUNCH
Definition: mspack.h:507
#define MSPACK_ERR_READ
Definition: mspack.h:491
#define MSPACK_ERR_NOMEMORY
Definition: mspack.h:497

References cd, MSPACK_ERR_CHECKSUM, MSPACK_ERR_DATAFORMAT, MSPACK_ERR_DECRUNCH, MSPACK_ERR_NOMEMORY, MSPACK_ERR_OPEN, MSPACK_ERR_READ, MSPACK_ERR_SEEK, MSPACK_ERR_SIGNATURE, and MSPACK_ERR_WRITE.

Referenced by load_spanning_cabinets(), and process_cabinet().

◆ cabx_alloc()

static void * cabx_alloc ( struct mspack_system this,
size_t  bytes 
)
static

Definition at line 1305 of file cabextract.c.

1305  {
1306  return malloc(bytes);
1307 }
static ut8 bytes[32]
Definition: asm_arc.c:23

References bytes, and malloc().

◆ cabx_close()

static void cabx_close ( struct mspack_file file)
static

Definition at line 1229 of file cabextract.c.

1229  {
1230  struct mspack_file_p *this = (struct mspack_file_p *) file;
1231  if (this) {
1232  if (this->name == TEST_FNAME) {
1233  md5_finish_ctx(&md5_context, (void *) &md5_result);
1234  }
1235  else if (this->regular_file) {
1236  fclose(this->fh);
1237  }
1238  free(this);
1239  }
1240 }
unsigned char md5_result[16]
Definition: cabextract.c:161
struct md5_ctx md5_context
Definition: cabextract.c:158
const char * TEST_FNAME
Definition: cabextract.c:155
FILE * fh
Definition: cabinfo.c:52
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
Definition: gzappend.c:170
Definition: z80asm.h:102
void * md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
Definition: md5.c:104

References fh, free(), md5_context, md5_finish_ctx(), md5_result, mspack_file_p::regular_file, and TEST_FNAME.

◆ cabx_copy()

static void cabx_copy ( void *  src,
void *  dest,
size_t  bytes 
)
static

Definition at line 1311 of file cabextract.c.

1311  {
1312  memcpy(dest, src, bytes);
1313 }
lzma_index * src
Definition: index.h:567
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
char * dest
Definition: lz4.h:697

References bytes, dest, memcpy(), and src.

◆ cabx_free()

static void cabx_free ( void *  buffer)
static

Definition at line 1308 of file cabextract.c.

1308  {
1309  free(buffer);
1310 }
Definition: buffer.h:15

References free().

◆ cabx_msg()

static void cabx_msg ( struct mspack_file file,
const char *  format,
  ... 
)
static

Definition at line 1294 of file cabextract.c.

1294  {
1295  va_list ap;
1296  if (file) {
1297  fprintf(stderr, "%s: ", ((struct mspack_file_p *) file)->name);
1298  }
1299  va_start(ap, format);
1300  vfprintf(stderr, format, ap);
1301  va_end(ap);
1302  fputc((int) '\n', stderr);
1303  fflush(stderr);
1304 }

◆ cabx_open()

static struct mspack_file * cabx_open ( struct mspack_system this,
const char *  filename,
int  mode 
)
static

Definition at line 1176 of file cabextract.c.

1178 {
1179  struct mspack_file_p *fh;
1180  const char *fmode;
1181 
1182  /* Use of the STDOUT_FNAME pointer for a filename means the file should
1183  * actually be extracted to stdout. Use of the TEST_FNAME pointer for a
1184  * filename means the file should only be MD5-summed.
1185  */
1186  if (filename == STDOUT_FNAME || filename == TEST_FNAME) {
1187  /* only WRITE mode is valid for these special files */
1188  if (mode != MSPACK_SYS_OPEN_WRITE) {
1189  return NULL;
1190  }
1191  }
1192 
1193  /* ensure that mode is one of READ, WRITE, UPDATE or APPEND */
1194  switch (mode) {
1195  case MSPACK_SYS_OPEN_READ: fmode = "rb"; break;
1196  case MSPACK_SYS_OPEN_WRITE: fmode = "wb"; break;
1197  case MSPACK_SYS_OPEN_UPDATE: fmode = "r+b"; break;
1198  case MSPACK_SYS_OPEN_APPEND: fmode = "ab"; break;
1199  default: return NULL;
1200  }
1201 
1202  if ((fh = malloc(sizeof(struct mspack_file_p)))) {
1203  fh->name = filename;
1204 
1205  if (filename == STDOUT_FNAME) {
1206  fh->regular_file = 0;
1207  fh->fh = stdout;
1208  return (struct mspack_file *) fh;
1209  }
1210  else if (filename == TEST_FNAME) {
1211  fh->regular_file = 0;
1212  fh->fh = NULL;
1214  return (struct mspack_file *) fh;
1215  }
1216  else {
1217  /* regular file - simply attempt to open it */
1218  fh->regular_file = 1;
1219  if ((fh->fh = fopen(filename, fmode))) {
1220  return (struct mspack_file *) fh;
1221  }
1222  }
1223  /* error - free file handle and return NULL */
1224  free(fh);
1225  }
1226  return NULL;
1227 }
#define MSPACK_SYS_OPEN_APPEND
Definition: mspack.h:464
#define MSPACK_SYS_OPEN_WRITE
Definition: mspack.h:460
#define MSPACK_SYS_OPEN_READ
Definition: mspack.h:458
#define MSPACK_SYS_OPEN_UPDATE
Definition: mspack.h:462
const char * STDOUT_FNAME
Definition: cabextract.c:148
#define NULL
Definition: cris-opc.c:27
const char * filename
Definition: ioapi.h:137
const char int mode
Definition: ioapi.h:137
void md5_init_ctx(struct md5_ctx *ctx)
Definition: md5.c:71

References fh, free(), malloc(), md5_context, md5_init_ctx(), MSPACK_SYS_OPEN_APPEND, MSPACK_SYS_OPEN_READ, MSPACK_SYS_OPEN_UPDATE, MSPACK_SYS_OPEN_WRITE, NULL, STDOUT_FNAME, and TEST_FNAME.

◆ cabx_read()

static int cabx_read ( struct mspack_file file,
void *  buffer,
int  bytes 
)
static

Definition at line 1242 of file cabextract.c.

1242  {
1243  struct mspack_file_p *this = (struct mspack_file_p *) file;
1244  if (this && this->regular_file && buffer && bytes >= 0) {
1245  size_t count = fread(buffer, 1, (size_t) bytes, this->fh);
1246  if (!ferror(this->fh)) return (int) count;
1247  }
1248  return -1;
1249 }
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98

References bytes, count, fh, and mspack_file_p::regular_file.

◆ cabx_seek()

static int cabx_seek ( struct mspack_file file,
off_t  offset,
int  mode 
)
static

Definition at line 1267 of file cabextract.c.

1267  {
1268  struct mspack_file_p *this = (struct mspack_file_p *) file;
1269  if (this && this->regular_file) {
1270  switch (mode) {
1271  case MSPACK_SYS_SEEK_START: mode = SEEK_SET; break;
1272  case MSPACK_SYS_SEEK_CUR: mode = SEEK_CUR; break;
1273  case MSPACK_SYS_SEEK_END: mode = SEEK_END; break;
1274  default: return -1;
1275  }
1276 #if HAVE_FSEEKO
1277  return fseeko(this->fh, offset, mode);
1278 #else
1279  return fseek(this->fh, offset, mode);
1280 #endif
1281  }
1282  return -1;
1283 }
#define MSPACK_SYS_SEEK_END
Definition: mspack.h:471
#define MSPACK_SYS_SEEK_START
Definition: mspack.h:467
#define MSPACK_SYS_SEEK_CUR
Definition: mspack.h:469
#define fseeko(s, o, w)
Definition: compat.h:121
voidpf uLong offset
Definition: ioapi.h:144
#define SEEK_SET
Definition: zip.c:88
#define SEEK_CUR
Definition: zip.c:80
#define SEEK_END
Definition: zip.c:84

References fh, fseeko, MSPACK_SYS_SEEK_CUR, MSPACK_SYS_SEEK_END, MSPACK_SYS_SEEK_START, mspack_file_p::regular_file, SEEK_CUR, SEEK_END, and SEEK_SET.

◆ cabx_tell()

static off_t cabx_tell ( struct mspack_file file)
static

Definition at line 1285 of file cabextract.c.

1285  {
1286  struct mspack_file_p *this = (struct mspack_file_p *) file;
1287 #if HAVE_FSEEKO
1288  return (this && this->regular_file) ? (off_t) ftello(this->fh) : 0;
1289 #else
1290  return (this && this->regular_file) ? (off_t) ftell(this->fh) : 0;
1291 #endif
1292 }
#define ftello(s)
Definition: compat.h:125
int off_t
Definition: sftypes.h:41

References fh, ftello, and mspack_file_p::regular_file.

◆ cabx_write()

static int cabx_write ( struct mspack_file file,
void *  buffer,
int  bytes 
)
static

Definition at line 1251 of file cabextract.c.

1251  {
1252  struct mspack_file_p *this = (struct mspack_file_p *) file;
1253  if (this && buffer && bytes >= 0) {
1254  if (this->name == TEST_FNAME) {
1256  return bytes;
1257  }
1258  else {
1259  /* regular files and the stdout writer */
1260  size_t count = fwrite(buffer, 1, (size_t) bytes, this->fh);
1261  if (!ferror(this->fh)) return (int) count;
1262  }
1263  }
1264  return -1;
1265 }
void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx)
Definition: md5.c:216

References bytes, count, fh, md5_context, md5_process_bytes(), and TEST_FNAME.

◆ create_output_name()

static char * create_output_name ( const char *  fname,
const char *  dir,
int  lower,
int  isunix,
int  utf8 
)
static

Creates a UNIX filename from the internal CAB filename and the given parameters.

Parameters
fnamethe internal CAB filename.
dira directory path to prepend to the output filename.
lowerif non-zero, filename should be made lower-case.
isunixif zero, MS-DOS path seperators are used in the internal CAB filename. If non-zero, UNIX path seperators are used.
utf8if non-zero, the internal CAB filename is encoded in UTF-8.
Returns
a freshly allocated and created filename, or NULL if there was not enough memory.
See also
unix_path_seperators()

Definition at line 761 of file cabextract.c.

763 {
764  char sep = (isunix) ? '/' : '\\'; /* the path-seperator */
765  char slash = (isunix) ? '\\' : '/'; /* the other slash */
766 
767  size_t dirlen = dir ? strlen(dir) + 1 : 0; /* length of dir + '/' */
768  size_t filelen = strlen(fname);
769 
770  /* worst case, UTF-8 processing expands all chars to 4 bytes */
771  char *name = malloc(dirlen + (filelen * 4) + 2);
772 
773  unsigned char *i = (unsigned char *) &fname[0];
774  unsigned char *iend = (unsigned char *) &fname[filelen];
775  unsigned char *o = (unsigned char *) &name[dirlen], c;
776 
777  if (!name) {
778  fprintf(stderr, "Can't allocate output filename\n");
779  return NULL;
780  }
781 
782  /* copy directory prefix if needed */
783  if (dir) {
784  strcpy(name, dir);
785  name[dirlen - 1] = '/';
786  }
787 
788  /* copy cab filename to output name, converting MS-DOS slashes to UNIX
789  * slashes as we go. Also lowercases characters if needed. */
790  if (utf8) {
791  /* handle UTF-8 encoded filenames (see RFC 3629). This doesn't reject bad
792  * UTF-8 with overlong encodings, but does re-encode it as valid UTF-8. */
793  while (i < iend) {
794  /* get next UTF-8 character */
795  int x;
796  if ((c = *i++) < 0x80) {
797  x = c;
798  }
799  else if (c >= 0xC2 && c < 0xE0 && i <= iend && (i[0] & 0xC0) == 0x80) {
800  x = (c & 0x1F) << 6;
801  x |= *i++ & 0x3F;
802  }
803  else if (c >= 0xE0 && c < 0xF0 && i+1 <= iend && (i[0] & 0xC0) == 0x80 &&
804  (i[1] & 0xC0) == 0x80)
805  {
806  x = (c & 0x0F) << 12;
807  x |= (*i++ & 0x3F) << 6;
808  x |= *i++ & 0x3F;
809  }
810  else if (c >= 0xF0 && c < 0xF5 && i+2 <= iend && (i[0] & 0xC0) == 0x80 &&
811  (i[1] & 0xC0) == 0x80 && (i[2] & 0xC0) == 0x80)
812  {
813  x = (c & 0x07) << 18;
814  x |= (*i++ & 0x3F) << 12;
815  x |= (*i++ & 0x3F) << 6;
816  x |= *i++ & 0x3F;
817  }
818  else {
819  x = 0xFFFD; /* bad first byte */
820  }
821 
822  if (x <= 0 || x > 0x10FFFF || (x >= 0xD800 && x <= 0xDFFF) ||
823  x == 0xFFFE || x == 0xFFFF)
824  {
825  x = 0xFFFD; /* invalid code point or cheeky null byte */
826  }
827 
828 #if HAVE_TOWLOWER
829  if (lower) x = towlower(x);
830 #else
831  if (lower && x < 256) x = tolower(x);
832 #endif
833 
834  /* whatever is the path separator -> '/'
835  * whatever is the other slash -> '\' */
836  if (x == sep) x = '/'; else if (x == slash) x = '\\';
837 
838  /* convert unicode character back to UTF-8 */
839  if (x < 0x80) {
840  *o++ = (unsigned char) x;
841  }
842  else if (x < 0x800) {
843  *o++ = 0xC0 | (x >> 6);
844  *o++ = 0x80 | (x & 0x3F);
845  }
846  else if (x < 0x10000) {
847  *o++ = 0xE0 | (x >> 12);
848  *o++ = 0x80 | ((x >> 6) & 0x3F);
849  *o++ = 0x80 | (x & 0x3F);
850  }
851  else if (x <= 0x10FFFF) {
852  *o++ = 0xF0 | (x >> 18);
853  *o++ = 0x80 | ((x >> 12) & 0x3F);
854  *o++ = 0x80 | ((x >> 6) & 0x3F);
855  *o++ = 0x80 | (x & 0x3F);
856  }
857  else {
858  *o++ = 0xEF; /* unicode replacement character in UTF-8 */
859  *o++ = 0xBF;
860  *o++ = 0xBD;
861  }
862  }
863  *o++ = '\0';
864 #if LATIN1_FILENAMES
865  convert_utf8_to_latin1(&name[dirlen]);
866 #endif
867  }
868  else {
869  /* non UTF-8 version */
870  while (i < iend) {
871  c = *i++;
872  if (lower) c = (unsigned char) tolower((int) c);
873  if (c == sep) c = '/'; else if (c == slash) c = '\\';
874  *o++ = c;
875  }
876  *o++ = '\0';
877  }
878 
879  /* remove any leading slashes in the cab filename part.
880  * This prevents unintended absolute file path access. */
881  o = (unsigned char *) &name[dirlen];
882  for (i = o; *i == '/' || *i == '\\'; i++);
883  if (i != o) {
884  size_t len = strlen((char *) i);
885  if (len > 0) {
886  memmove(o, i, len + 1);
887  }
888  else {
889  /* change filename composed entirely of leading slashes to "x" */
890  strcpy((char *) o, "x");
891  }
892  }
893 
894  /* search for "../" or "..\" in cab filename part and change to "xx"
895  * This prevents unintended directory traversal. */
896  for (; *o; o++) {
897  if ((o[0] == '.') && (o[1] == '.') && (o[2] == '/' || o[2] == '\\')) {
898  o[0] = o[1] = 'x';
899  o += 2;
900  }
901  }
902 
903  return name;
904 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
FILELEN filelen
Definition: cabinfo.c:54
int x
Definition: mipsasm.c:20
const char * name
Definition: op.c:541
#define tolower(c)
Definition: safe-ctype.h:149
#define c(i)
Definition: sha256.c:43

References c, filelen, create_tags_rz::fname, i, len, malloc(), name, NULL, tolower, and x.

Referenced by process_cabinet().

◆ ensure_filepath()

static int ensure_filepath ( char *  path)
static

Ensures that all directory components in a filepath exist. New directory components are created, if necessary.

Parameters
paththe filepath to check
Returns
non-zero if all directory components in a filepath exist, zero if components do not exist and cannot be created

Definition at line 1123 of file cabextract.c.

1123  {
1124  struct stat st_buf;
1125  char *p;
1126  int ok;
1127 
1128  for (p = &path[1]; *p; p++) {
1129  if (*p != '/') continue;
1130  *p = '\0';
1131  ok = (stat(path, &st_buf) == 0) && S_ISDIR(st_buf.st_mode);
1132  if (!ok) ok = (mkdir(path, 0777 & ~user_umask) == 0);
1133  *p = '/';
1134  if (!ok) return 0;
1135  }
1136  return 1;
1137 }
mode_t user_umask
Definition: cabextract.c:132
#define S_ISDIR(mode)
Definition: compat.h:187
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
void * p
Definition: libc.cpp:67
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig mkdir
Definition: sflib.h:66
static stat
Definition: sflib.h:131
@ ok
Definition: lz4.c:1706
Definition: sftypes.h:80

References mkdir, ok, p, path, S_ISDIR, stat, and user_umask.

Referenced by process_cabinet().

◆ find_cabinet_file()

static char * find_cabinet_file ( char *  origcab,
char *  cabname 
)
static

Matches a cabinet's filename case-insensitively in the filesystem and returns the case-correct form.

Parameters
origcabif this is non-NULL, the pathname part of this filename will be extracted, and the search will be conducted in that directory.
cabnamethe internal CAB filename to search for.
Returns
a copy of the full, case-correct filename of the given cabinet filename, or NULL if the specified filename does not exist on disk.

Definition at line 622 of file cabextract.c.

622  {
623  struct dirent *entry;
624  struct stat st_buf;
625  int found = 0, len;
626  char *tail, *cab;
627  DIR *dir;
628 
629  /* ensure we have a cabinet name at all */
630  if (!cabname || !cabname[0]) return NULL;
631 
632  /* find if there's a directory path in the origcab */
633  tail = origcab ? strrchr(origcab, '/') : NULL;
634  len = (tail - origcab) + 1;
635 
636  /* allocate memory for our copy */
637  if (!(cab = malloc((tail ? len : 2) + strlen(cabname) + 1))) return NULL;
638 
639  /* add the directory path from the original cabinet name, or "." */
640  if (tail) memcpy(cab, origcab, (size_t) len);
641  else cab[0]='.', cab[1]='/', len=2;
642  cab[len] = '\0';
643 
644  /* try accessing the cabinet with its current name (case-sensitive) */
645  strcpy(&cab[len], cabname);
646  if (stat(cab, &st_buf) == 0) {
647  found = 1;
648  }
649  else {
650  /* cabinet was not found, look for it in the current dir */
651  cab[len] = '\0';
652  if ((dir = opendir(cab))) {
653  while ((entry = readdir(dir))) {
654  if (strcasecmp(cabname, entry->d_name) == 0) {
655  strcat(cab, entry->d_name);
656  found = (stat(cab, &st_buf) == 0);
657  break;
658  }
659  }
660  closedir(dir);
661  }
662  }
663 
664  if (!found || !S_ISREG(st_buf.st_mode)) {
665  /* cabinet not found, or not a regular file */
666  free(cab);
667  cab = NULL;
668  }
669 
670  return cab;
671 }
#define S_ISREG(mode)
Definition: compat.h:191
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
static static fork const void static count static fd const char static mode const char static pathname const char static path const char static dev const char static group static getpid static getuid void void static data static pause const char static mode static sync const char const char static newpath const char static pathname unsigned long static filedes void static end_data_segment static handler static getegid char static len static pgid const char static path static newfd static getpgrp static euid const sigset_t static mask const char static len const gid_t static list const char const char static newpath const char static library readdir
Definition: sflib.h:120
Definition: sftypes.h:48
Definition: zipcmp.c:77

References found, free(), len, malloc(), memcpy(), NULL, readdir, S_ISREG, and stat.

Referenced by load_spanning_cabinets().

◆ forget_files()

static void forget_files ( struct file_mem **  fml)
static

Frees all memory used by a file_mem list.

Parameters
fmladdress of the list to free
See also
memorise_file()

Definition at line 1078 of file cabextract.c.

1078  {
1079  struct file_mem *fm, *next;
1080  for (fm = *fml; fm; fm = next) {
1081  next = fm->next;
1082  free(fm->from);
1083  free(fm);
1084  }
1085  *fml = NULL;
1086 }
char * from
Definition: cabextract.c:111
struct file_mem * next
Definition: cabextract.c:108

References free(), file_mem::from, file_mem::next, and NULL.

Referenced by main().

◆ free_filters()

static void free_filters ( )
static

Frees all memory used by args.filters

Definition at line 1107 of file cabextract.c.

1107  {
1108  struct filter *f, *next;
1109  for (f = args.filters; f; f = next) {
1110  next = f->next;
1111  free(f);
1112  }
1113 }
struct filter * next
Definition: cabextract.c:115

References args, f, cabextract_args::filters, free(), and filter::next.

Referenced by add_filter().

◆ load_spanning_cabinets()

static void load_spanning_cabinets ( struct mscabd_cabinet basecab,
char *  basename 
)
static

Follows the spanning cabinet chain specified in a cabinet, loading and attaching the spanning cabinets as it goes.

Parameters
basecabthe base cabinet to start the chain from.
basenamethe full pathname of the base cabinet, so spanning cabinets can be found in the same path as the base cabinet.
See also
find_cabinet_file()

Definition at line 564 of file cabextract.c.

566 {
567  struct mscabd_cabinet *cab, *cab2;
568  char *name;
569 
570  /* load any spanning cabinets -- backwards */
571  for (cab = basecab; cab->flags & MSCAB_HDR_PREVCAB; cab = cab->prevcab) {
572  if (!(name = find_cabinet_file(basename, cab->prevname))) {
573  fprintf(stderr, "%s: can't find %s\n", basename, cab->prevname);
574  break;
575  }
576  if (args.single && !recall_file(cab_args, name, NULL)) break;
577  if (!args.quiet) {
578  printf("%s: extends backwards to %s (%s)\n", basename,
579  cab->prevname, cab->previnfo);
580  }
581  if (!(cab2 = cabd->open(cabd,name)) || cabd->prepend(cabd, cab, cab2)) {
582  fprintf(stderr, "%s: can't prepend %s: %s\n", basename,
583  cab->prevname, cab_error(cabd));
584  if (cab2) cabd->close(cabd, cab2);
585  break;
586  }
588  }
589 
590  /* load any spanning cabinets -- forwards */
591  for (cab = basecab; cab->flags & MSCAB_HDR_NEXTCAB; cab = cab->nextcab) {
592  if (!(name = find_cabinet_file(basename, cab->nextname))) {
593  fprintf(stderr, "%s: can't find %s\n", basename, cab->nextname);
594  break;
595  }
596  if (args.single && !recall_file(cab_args, name, NULL)) break;
597  if (!args.quiet) {
598  printf("%s: extends to %s (%s)\n", basename,
599  cab->nextname, cab->nextinfo);
600  }
601  if (!(cab2 = cabd->open(cabd,name)) || cabd->append(cabd, cab, cab2)) {
602  fprintf(stderr, "%s: can't append %s: %s\n", basename,
603  cab->nextname, cab_error(cabd));
604  if (cab2) cabd->close(cabd, cab2);
605  break;
606  }
608  }
609 }
#define MSCAB_HDR_NEXTCAB
Definition: mspack.h:793
#define MSCAB_HDR_PREVCAB
Definition: mspack.h:791
struct mscab_decompressor * cabd
Definition: cabextract.c:126
static void memorise_file(struct file_mem **fml, char *name, char *from)
Definition: cabextract.c:1034
struct file_mem * cab_exts
Definition: cabextract.c:129
static int recall_file(struct file_mem *fml, char *name, char **from)
Definition: cabextract.c:1059
struct file_mem * cab_args
Definition: cabextract.c:128
static char * cab_error(struct mscab_decompressor *cd)
Definition: cabextract.c:1146
static char * find_cabinet_file(char *origcab, char *cabname)
Definition: cabextract.c:622
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
#define basename
Definition: libiberty.h:109
int(* append)(struct mscab_decompressor *self, struct mscabd_cabinet *cab, struct mscabd_cabinet *nextcab)
Definition: mspack.h:1090
struct mscabd_cabinet *(* open)(struct mscab_decompressor *self, const char *filename)
Definition: mspack.h:978
int(* prepend)(struct mscab_decompressor *self, struct mscabd_cabinet *cab, struct mscabd_cabinet *prevcab)
Definition: mspack.h:1112
void(* close)(struct mscab_decompressor *self, struct mscabd_cabinet *cab)
Definition: mspack.h:1010
char * prevname
Definition: mspack.h:727
struct mscabd_cabinet * prevcab
Definition: mspack.h:721
char * previnfo
Definition: mspack.h:735
char * nextinfo
Definition: mspack.h:740
char * nextname
Definition: mspack.h:730
struct mscabd_cabinet * nextcab
Definition: mspack.h:724

References mscab_decompressor::append, args, basename, cab_args, cab_error(), cab_exts, cabd, mscab_decompressor::close, find_cabinet_file(), mscabd_cabinet::flags, memorise_file(), MSCAB_HDR_NEXTCAB, MSCAB_HDR_PREVCAB, name, mscabd_cabinet::nextcab, mscabd_cabinet::nextinfo, mscabd_cabinet::nextname, NULL, mscab_decompressor::open, mscab_decompressor::prepend, mscabd_cabinet::prevcab, mscabd_cabinet::previnfo, mscabd_cabinet::prevname, printf(), cabextract_args::quiet, recall_file(), and cabextract_args::single.

Referenced by process_cabinet().

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 211 of file cabextract.c.

211  {
212  int i, err;
213 
214  /* names for the UTF-8 charset recognised by different iconv_open()s */
215  char *utf8_names[] = {
216  "UTF-8", /* glibc, libiconv, FreeBSD, Solaris, not newlib or HPUX */
217  "UTF8", /* glibc, libiconv (< 1.13), newlib, HPUX */
218  "UTF_8", /* newlib, Solaris */
219  };
220 
221  /* attempt to set a UTF8-based locale, so that tolower()/towlower()
222  * in create_output_name() lowercase more than just A-Z in ASCII.
223  *
224  * We don't attempt to pick up the system default locale, "",
225  * because it might not be compatible with ASCII/ISO-8859-1/Unicode
226  * character codes and would mess up lowercased filenames
227  */
228  char *locales[] = {
229  "C.UTF-8", /* https://sourceware.org/glibc/wiki/Proposals/C.UTF-8 */
230  "en_US.UTF-8", "en_GB.UTF8", "de_DE.UTF-8", "UTF-8", "UTF8"
231  };
232  for (i = 0; i < (sizeof(locales)/sizeof(*locales)); i++) {
233  if (setlocale(LC_CTYPE, locales[i])) break;
234  }
235 
236  /* parse options */
237  while ((i = getopt_long(argc, argv, OPTSTRING, optlist, NULL)) != -1) {
238  switch (i) {
239  case 'd': args.dir = optarg; break;
240  case 'e': args.encoding = optarg; break;
241  case 'f': args.fix = 1; break;
242  case 'F': add_filter(optarg); break;
243  case 'h': args.help = 1; break;
244  case 'l': args.view = 1; break;
245  case 'L': args.lower = 1; break;
246  case 'p': args.pipe = 1; break;
247  case 'q': args.quiet = 1; break;
248  case 's': args.single = 1; break;
249  case 't': args.test = 1; break;
250  case 'v': args.view = 1; break;
251  }
252  }
253 
254  if (args.help) {
255  fprintf(stderr,
256  "Usage: %s [options] [-d dir] <cabinet file(s)>\n\n"
257  "This will extract all files from a cabinet or executable cabinet.\n"
258  "For multi-part cabinets, only specify the first file in the set.\n\n",
259  argv[0]);
260  fprintf(stderr,
261  "Options:\n"
262  " -v --version print version / list cabinet\n"
263  " -h --help show this help page\n"
264  " -l --list list contents of cabinet\n"
265  " -t --test test cabinet integrity\n"
266  " -q --quiet only print errors and warnings\n"
267  " -L --lowercase make filenames lowercase\n"
268  " -f --fix salvage as much as possible from corrupted cabinets\n");
269  fprintf(stderr,
270  " -p --pipe pipe extracted files to stdout\n"
271  " -s --single restrict search to cabs on the command line\n"
272  " -F --filter extract only files that match the given pattern\n"
273 #if HAVE_ICONV
274  " -e --encoding assume non-UTF8 filenames have the given encoding\n"
275 #endif
276  " -d --directory extract all files to the given directory\n\n"
277  "cabextract %s (C) 2000-2019 Stuart Caie <kyzer@cabextract.org.uk>\n"
278  "This is free software with ABSOLUTELY NO WARRANTY.\n",
279  VERSION);
280  return EXIT_FAILURE;
281  }
282 
283  if (args.test && args.view) {
284  fprintf(stderr, "%s: You cannot use --test and --list at the same time.\n"
285  "Try '%s --help' for more information.\n", argv[0], argv[0]);
286  return EXIT_FAILURE;
287  }
288 
289  if (optind == argc) {
290  /* no arguments other than the options */
291  if (args.view) {
292  printf("cabextract version %s\n", VERSION);
293  return 0;
294  }
295  else {
296  fprintf(stderr, "%s: No cabinet files specified.\nTry '%s --help' "
297  "for more information.\n", argv[0], argv[0]);
298  return EXIT_FAILURE;
299  }
300  }
301 
302  /* memorise command-line cabs if necessary */
303  if (args.single) {
304  for (i = optind; i < argc; i++) memorise_file(&cab_args, argv[i], NULL);
305  }
306 
307  /* extracting to stdout implies shutting up on stdout */
308  if (args.pipe && !args.view) args.quiet = 1;
309 
310  /* open libmspack */
312  if (err) {
313  if (err == MSPACK_ERR_SEEK) {
314  fprintf(stderr,
315  "FATAL ERROR: libmspack is compiled for %d-bit file IO,\n"
316  " cabextract is compiled for %d-bit file IO.\n",
317  (sizeof(off_t) == 4) ? 64 : 32,
318  (sizeof(off_t) == 4) ? 32 : 64);
319  }
320  else {
321  fprintf(stderr, "FATAL ERROR: libmspack self-test returned %d\n", err);
322  }
323  return EXIT_FAILURE;
324  }
325 
327  fprintf(stderr, "can't create libmspack CAB decompressor\n");
328  return EXIT_FAILURE;
329  }
330 
331  /* obtain user's umask */
332 #if HAVE_UMASK
333  umask(user_umask = umask(0));
334 #endif
335 
336  /* turn on/off 'fix MSZIP' and 'salvage' mode */
339 
340 #if HAVE_ICONV
341  /* set up converter from given encoding to UTF-8 */
342  if (args.encoding) {
343  for (i = 0; i < (sizeof(utf8_names)/sizeof(*utf8_names)); i++) {
344  converter = iconv_open(utf8_names[i], args.encoding);
345  if (converter != (iconv_t) -1) break;
346  }
347  if (converter == (iconv_t) -1) {
348  fprintf(stderr, "FATAL ERROR: encoding '%s' is not recognised\n",
349  args.encoding);
350  return EXIT_FAILURE;
351  }
352  }
353 #endif
354 
355  /* process cabinets */
356  for (i = optind, err = 0; i < argc; i++) {
357  err += process_cabinet(argv[i]);
358  }
359 
360  /* error summary */
361  if (!args.quiet) {
362  if (err) printf("\nAll done, errors in processing %d file(s)\n", err);
363  else printf("\nAll done, no errors.\n");
364  }
365 
366 #if HAVE_ICONV
367  if (converter) {
368  iconv_close(converter);
369  }
370 #endif
371 
372  /* close libmspack */
374 
375  /* empty file-memory lists */
379 
380  return err ? EXIT_FAILURE : EXIT_SUCCESS;
381 }
static bool err
Definition: armass.c:435
#define VERSION
Definition: config.h:54
#define MSPACK_SYS_SELFTEST(result)
Definition: mspack.h:191
#define MSCABD_PARAM_FIXMSZIP
Definition: mspack.h:934
#define MSCABD_PARAM_SALVAGE
Definition: mspack.h:943
const char * OPTSTRING
Definition: cabextract.c:104
struct option optlist[]
Definition: cabextract.c:83
struct file_mem * cab_seen
Definition: cabextract.c:130
static void forget_files(struct file_mem **fml)
Definition: cabextract.c:1078
static void add_filter(char *arg)
Definition: cabextract.c:1094
static struct mspack_system cabextract_system
Definition: cabextract.c:206
static int process_cabinet(char *cabname)
Definition: cabextract.c:391
const char * optarg
Definition: getopt.h:9
int optind
Definition: getopt.h:6
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz umask
Definition: sflib.h:65
int getopt_long()
void mspack_destroy_cab_decompressor(struct mscab_decompressor *base)
Definition: cabd.c:173
struct mscab_decompressor * mspack_create_cab_decompressor(struct mspack_system *sys)
Definition: cabd.c:140
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
int(* set_param)(struct mscab_decompressor *self, int param, int value)
Definition: mspack.h:1164

References add_filter(), args, argv, cab_args, cab_exts, cab_seen, cabd, cabextract_system, cabextract_args::dir, cabextract_args::encoding, err, cabextract_args::fix, forget_files(), getopt_long(), cabextract_args::help, i, cabextract_args::lower, memorise_file(), MSCABD_PARAM_FIXMSZIP, MSCABD_PARAM_SALVAGE, mspack_create_cab_decompressor(), mspack_destroy_cab_decompressor(), MSPACK_ERR_SEEK, MSPACK_SYS_SELFTEST, NULL, optarg, optind, optlist, OPTSTRING, cabextract_args::pipe, printf(), process_cabinet(), cabextract_args::quiet, mscab_decompressor::set_param, cabextract_args::single, cabextract_args::test, umask, user_umask, VERSION, and cabextract_args::view.

◆ memorise_file()

static void memorise_file ( struct file_mem **  fml,
char *  name,
char *  from 
)
static

Memorises a file by its device and inode number rather than its name. If the file does not exist, it will not be memorised.

Parameters
fmladdress of the file_mem list that will memorise this file.
namename of the file to memorise.
froma string that, if not NULL, will be duplicated stored with the memorised file.
See also
recall_file(), forget_files()

Definition at line 1034 of file cabextract.c.

1034  {
1035  struct file_mem *fm;
1036  struct stat st_buf;
1037  if (stat(name, &st_buf) != 0) return;
1038  if (!(fm = malloc(sizeof(struct file_mem)))) return;
1039  fm->st_dev = st_buf.st_dev;
1040  fm->st_ino = st_buf.st_ino;
1041  fm->from = (from) ? malloc(strlen(from)+1) : NULL;
1042  if (fm->from) strcpy(fm->from, from);
1043  fm->next = *fml;
1044  *fml = fm;
1045 }
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr from
Definition: sfsocketcall.h:123
ino_t st_ino
Definition: cabextract.c:110
dev_t st_dev
Definition: cabextract.c:109

References from, file_mem::from, malloc(), file_mem::next, NULL, file_mem::st_dev, file_mem::st_ino, and stat.

Referenced by load_spanning_cabinets(), main(), and process_cabinet().

◆ process_cabinet()

static int process_cabinet ( char *  basename)
static

Processes each file argument on the command line, as specified by the command line options. This does the main bulk of work in cabextract.

Parameters
basenamethe file to process
Returns
the number of files with errors, usually 0 for success or 1 for failure

Definition at line 391 of file cabextract.c.

391  {
392  struct mscabd_cabinet *basecab, *cab, *cab2;
393  struct mscabd_file *file;
394  int isunix, fname_offset, viewhdr = 0;
395  char *from, *name;
396  int errors = 0;
397 
398  /* do not process repeat cabinets */
399  if (recall_file(cab_seen, basename, &from) ||
401  if (!args.quiet) {
402  if (!from) printf("%s: skipping known cabinet\n", basename);
403  else printf("%s: skipping known cabinet (from %s)\n", basename, from);
404  }
405  return 0; /* return success */
406  }
408 
409  /* search the file for cabinets */
410  if (!(basecab = cabd->search(cabd, basename))) {
411  if (cabd->last_error(cabd)) {
412  fprintf(stderr, "%s: %s\n", basename, cab_error(cabd));
413  }
414  else {
415  fprintf(stderr, "%s: no valid cabinets found\n", basename);
416  }
417  return 1;
418  }
419 
420  /* iterate over all cabinets found in that file */
421  for (cab = basecab; cab; cab = cab->next) {
422 
423  /* load all spanning cabinets */
425 
426 #if HAVE_ICONV
427  /* convert all non-UTF8 filenames to UTF8 using given encoding */
428  if (converter) convert_filenames(cab->files);
429 #endif
430 
431  /* determine whether UNIX or MS-DOS path seperators are used */
432  isunix = unix_path_seperators(cab->files);
433 
434  /* print headers */
435  if (!viewhdr) {
436  if (args.view) {
437  if (!args.quiet) printf("Viewing cabinet: %s\n", basename);
438  printf(" File size | Date Time | Name\n");
439  printf("-----------+---------------------+-------------\n");
440  }
441  else {
442  if (!args.quiet) {
443  printf("%s cabinet: %s\n", args.test ? "Testing" : "Extracting",
444  basename);
445  }
446  }
447  viewhdr = 1;
448  }
449 
450  /* the full UNIX output filename includes the output
451  * directory. However, for filtering purposes, we don't want to
452  * include that. So, we work out where the filename part of the
453  * output name begins. This is the same for every extracted file.
454  */
455  fname_offset = args.dir ? (strlen(args.dir) + 1) : 0;
456 
457  /* process all files */
458  for (file = cab->files; file; file = file->next) {
459  /* create the full UNIX output filename */
460  if (!(name = create_output_name(file->filename, args.dir,
461  args.lower, isunix, file->attribs & MSCAB_ATTRIB_UTF_NAME)))
462  {
463  errors++;
464  continue;
465  }
466 
467  /* if filtering, do so now. skip if file doesn't match any filter */
468  if (args.filters) {
469  int matched = 0;
470  struct filter *f;
471  for (f = args.filters; f; f = f->next) {
472  if (!fnmatch(f->filter, &name[fname_offset], FNM_CASEFOLD)) {
473  matched = 1;
474  break;
475  }
476  }
477  if (!matched) {
478  free(name);
479  continue;
480  }
481  }
482 
483  /* view, extract or test the file */
484  if (args.view) {
485  printf("%10u | %02d.%02d.%04d %02d:%02d:%02d | %s\n",
486  file->length, file->date_d, file->date_m, file->date_y,
487  file->time_h, file->time_m, file->time_s, name);
488  }
489  else if (args.test) {
490  if (cabd->extract(cabd, file, TEST_FNAME)) {
491  /* file failed to extract */
492  printf(" %s failed (%s)\n", name, cab_error(cabd));
493  errors++;
494  }
495  else {
496  /* file extracted OK, print the MD5 checksum in md5_result. Print
497  * the checksum right-aligned to 79 columns if that's possible,
498  * otherwise just print it 2 spaces after the filename and "OK" */
499 
500  /* " filename OK " is 8 chars + the length of filename,
501  * the MD5 checksum itself is 32 chars. */
502  int spaces = 79 - (strlen(name) + 8 + 32);
503  printf(" %s OK ", name);
504  while (spaces-- > 0) putchar(' ');
505  printf("%02x%02x%02x%02x%02x%02x%02x%02x"
506  "%02x%02x%02x%02x%02x%02x%02x%02x\n",
509  md5_result[8], md5_result[9], md5_result[10],md5_result[11],
510  md5_result[12],md5_result[13],md5_result[14],md5_result[15]);
511  }
512  }
513  else {
514  /* extract the file */
515  if (args.pipe) {
516  /* extracting to stdout */
517  if (cabd->extract(cabd, file, STDOUT_FNAME)) {
518  fprintf(stderr, "%s(%s): %s\n", STDOUT_FNAME, name,
519  cab_error(cabd));
520  errors++;
521  }
522  }
523  else {
524  /* extracting to a regular file */
525  if (!args.quiet) printf(" extracting %s\n", name);
526 
527  if (!ensure_filepath(name)) {
528  fprintf(stderr, "%s: can't create file path\n", name);
529  errors++;
530  }
531  else {
532  if (cabd->extract(cabd, file, name)) {
533  fprintf(stderr, "%s: %s\n", name, cab_error(cabd));
534  errors++;
535  }
536  else {
538  }
539  }
540  }
541  }
542  free(name);
543  } /* for (all files in cab) */
544 
545  /* free the spanning cabinet filenames [not freed by cabd->close()] */
546  for (cab2 = cab->prevcab; cab2; cab2 = cab2->prevcab) free((void*)cab2->filename);
547  for (cab2 = cab->nextcab; cab2; cab2 = cab2->nextcab) free((void*)cab2->filename);
548  } /* for (all cabs) */
549 
550  /* free all loaded cabinets */
551  cabd->close(cabd, basecab);
552  return errors;
553 }
#define MSCAB_ATTRIB_UTF_NAME
Definition: mspack.h:929
static char * create_output_name(const char *fname, const char *dir, int lower, int isunix, int unicode)
Definition: cabextract.c:761
static void set_date_and_perm(struct mscabd_file *file, char *filename)
Definition: cabextract.c:914
static int unix_path_seperators(struct mscabd_file *files)
Definition: cabextract.c:690
static int ensure_filepath(char *path)
Definition: cabextract.c:1123
static void load_spanning_cabinets(struct mscabd_cabinet *basecab, char *basename)
Definition: cabextract.c:564
#define FNM_CASEFOLD
Definition: cabextract.c:74
int fnmatch(char *pattern, const char *string, int flags) const
Definition: fnmatch.c:60
const char * spaces(int count)
z_const unsigned char * next
Definition: gzappend.c:175
struct mscabd_cabinet *(* search)(struct mscab_decompressor *self, const char *filename)
Definition: mspack.h:1047
int(* last_error)(struct mscab_decompressor *self)
Definition: mspack.h:1179
int(* extract)(struct mscab_decompressor *self, struct mscabd_file *file, const char *filename)
Definition: mspack.h:1138
const char * filename
Definition: mspack.h:712
struct mscabd_cabinet * next
Definition: mspack.h:705
struct mscabd_file * files
Definition: mspack.h:743
static int file
Definition: z80asm.c:58

References args, basename, cab_error(), cab_exts, cab_seen, cabd, mscab_decompressor::close, create_output_name(), cabextract_args::dir, ensure_filepath(), mscab_decompressor::extract, f, file, mscabd_cabinet::filename, mscabd_cabinet::files, cabextract_args::filters, FNM_CASEFOLD, fnmatch(), free(), from, mscab_decompressor::last_error, load_spanning_cabinets(), cabextract_args::lower, md5_result, memorise_file(), MSCAB_ATTRIB_UTF_NAME, name, mscabd_cabinet::next, file::next, mscabd_cabinet::nextcab, NULL, cabextract_args::pipe, mscabd_cabinet::prevcab, printf(), cabextract_args::quiet, recall_file(), mscab_decompressor::search, set_date_and_perm(), spaces(), STDOUT_FNAME, cabextract_args::test, TEST_FNAME, unix_path_seperators(), and cabextract_args::view.

Referenced by main().

◆ recall_file()

static int recall_file ( struct file_mem fml,
char *  name,
char **  from 
)
static

Determines if a file has been memorised before, by its device and inode number. If the file does not exist, it cannot be recalled.

Parameters
fmllist to search for previously memorised file
namename of file to recall.
fromif non-NULL, this is an address that the associated "from" description pointer will be stored.
Returns
non-zero if the file has been previously memorised, zero if the file is unknown or does not exist.
See also
memorise_file(), forget_files()

Definition at line 1059 of file cabextract.c.

1059  {
1060  struct file_mem *fm;
1061  struct stat st_buf;
1062  if (stat(name, &st_buf) != 0) return 0;
1063  for (fm = fml; fm; fm = fm->next) {
1064  if ((st_buf.st_ino == fm->st_ino) && (st_buf.st_dev == fm->st_dev)) {
1065  if (from) *from = fm->from;
1066  return 1;
1067  }
1068  }
1069  return 0;
1070 }

References from, file_mem::from, file_mem::next, file_mem::st_dev, file_mem::st_ino, and stat.

Referenced by load_spanning_cabinets(), and process_cabinet().

◆ set_date_and_perm()

static void set_date_and_perm ( struct mscabd_file file,
char *  filename 
)
static

Sets the last-modified time and file permissions on a file.

Parameters
filethe internal CAB file whose date, time and attributes will be used.
filenamethe name of the UNIX file whose last-modified time and file permissions will be set.

Definition at line 914 of file cabextract.c.

914  {
915  mode_t mode;
916  struct tm tm;
917 #if HAVE_UTIME
918  struct utimbuf utb;
919 #elif HAVE_UTIMES
920  struct timeval tv[2];
921 #endif
922 
923  /* set last modified date */
924  tm.tm_sec = file->time_s;
925  tm.tm_min = file->time_m;
926  tm.tm_hour = file->time_h;
927  tm.tm_mday = file->date_d;
928  tm.tm_mon = file->date_m - 1;
929  tm.tm_year = file->date_y - 1900;
930  tm.tm_isdst = -1;
931 
932 #if HAVE_UTIME
933  utb.actime = utb.modtime = mktime(&tm);
934  utime(filename, &utb);
935 #elif HAVE_UTIMES
936  tv[0].tv_sec = tv[1].tv_sec = mktime(&tm);
937  tv[0].tv_usec = tv[1].tv_usec = 0;
938  utimes(filename, &tv[0]);
939 #endif
940 
941  /* set permissions */
942  mode = 0444;
943  if ( file->attribs & MSCAB_ATTRIB_EXEC) mode |= 0111;
944  if (!(file->attribs & MSCAB_ATTRIB_RDONLY)) mode |= 0222;
946 }
#define MSCAB_ATTRIB_EXEC
Definition: mspack.h:927
#define MSCAB_ATTRIB_RDONLY
Definition: mspack.h:919
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval tv
Definition: sflib.h:79
static static fork const void static count static fd const char const char static newpath const char static path chmod
Definition: sflib.h:35
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds utime
Definition: sflib.h:57
int mode_t
Definition: sftypes.h:42

References chmod, MSCAB_ATTRIB_EXEC, MSCAB_ATTRIB_RDONLY, tv, user_umask, and utime.

Referenced by process_cabinet().

◆ unix_path_seperators()

static int unix_path_seperators ( struct mscabd_file files)
static

Determines whether UNIX '/' or MS-DOS '\' path seperators are used in the cabinet file. The algorithm is as follows:

Look at all slashes in all filenames. If there are no slashes, MS-DOS seperators are assumed (it doesn't matter). If all are backslashes, MS-DOS seperators are assumed. If all are forward slashes, UNIX seperators are assumed.

If not all slashes are the same, go through each filename, looking for the first slash. If the part of the filename up to and including the slash matches the previous filename, that kind of slash is the directory seperator.

Parameters
fileslist of files in the cab file
Returns
0 for MS-DOS seperators, or 1 for UNIX seperators.

Definition at line 690 of file cabextract.c.

690  {
691  struct mscabd_file *fi;
692  char slash=0, backslash=0, *oldname;
693  int oldlen;
694 
695  for (fi = files; fi; fi = fi->next) {
696  char *p;
697  for (p = fi->filename; *p; p++) {
698  if (*p == '/') slash = 1;
699  if (*p == '\\') backslash = 1;
700  }
701  if (slash && backslash) break;
702  }
703 
704  if (slash) {
705  /* slashes, but no backslashes = UNIX */
706  if (!backslash) return 1;
707  }
708  else {
709  /* no slashes = MS-DOS */
710  return 0;
711  }
712 
713  /* special case if there's only one file - just take the first slash */
714  if (!files->next) {
715  char c, *p = fi->filename;
716  while ((c = *p++)) {
717  if (c == '\\') return 0; /* backslash = MS-DOS */
718  if (c == '/') return 1; /* slash = UNIX */
719  }
720  /* should not happen - at least one slash was found! */
721  return 0;
722  }
723 
724  oldname = NULL;
725  oldlen = 0;
726  for (fi = files; fi; fi = fi->next) {
727  char *name = fi->filename;
728  int len = 0;
729  while (name[len]) {
730  if ((name[len] == '\\') || (name[len] == '/')) break;
731  len++;
732  }
733  if (!name[len]) len = 0; else len++;
734 
735  if (len && (len == oldlen)) {
736  if (strncmp(name, oldname, (size_t) len) == 0)
737  return (name[len-1] == '\\') ? 0 : 1;
738  }
739  oldname = name;
740  oldlen = len;
741  }
742 
743  /* default */
744  return 0;
745 }
checking print the parsed form of the magic use in n conjunction with m to debug a new magic file n before installing it n output MIME type special files
Definition: file_opts.h:46
struct mscabd_file * next
Definition: mspack.h:868
char * filename
Definition: mspack.h:878

References c, mscabd_file::filename, files, len, name, mscabd_file::next, file::next, NULL, and p.

Referenced by process_cabinet().

Variable Documentation

◆ args

struct cabextract_args args
Initial value:
= {
0, 0, 0, 0, 0, 0, 0, 0,
}

Definition at line 132 of file cabextract.c.

Referenced by add_filter(), createdb(), free_filters(), insertkeys(), invoke_cgi_script(), load_spanning_cabinets(), main(), process_cabinet(), read_name(), setup_workers(), and spp_help().

◆ cab_args

struct file_mem* cab_args = NULL

Definition at line 128 of file cabextract.c.

Referenced by load_spanning_cabinets(), and main().

◆ cab_exts

struct file_mem* cab_exts = NULL

Definition at line 129 of file cabextract.c.

Referenced by load_spanning_cabinets(), main(), and process_cabinet().

◆ cab_seen

struct file_mem* cab_seen = NULL

Definition at line 130 of file cabextract.c.

Referenced by main(), and process_cabinet().

◆ cabd

◆ cabextract_system

struct mspack_system cabextract_system
static
Initial value:
= {
}
static off_t cabx_tell(struct mspack_file *file)
Definition: cabextract.c:1285
static void cabx_free(void *buffer)
Definition: cabextract.c:1308
static int cabx_write(struct mspack_file *file, void *buffer, int bytes)
Definition: cabextract.c:1251
static void cabx_close(struct mspack_file *file)
Definition: cabextract.c:1229
static int cabx_read(struct mspack_file *file, void *buffer, int bytes)
Definition: cabextract.c:1242
static void * cabx_alloc(struct mspack_system *this, size_t bytes)
Definition: cabextract.c:1305
static void cabx_copy(void *src, void *dest, size_t bytes)
Definition: cabextract.c:1311
static struct mspack_file * cabx_open(struct mspack_system *this, const char *filename, int mode)
Definition: cabextract.c:1176
static void cabx_msg(struct mspack_file *file, const char *format,...)
Definition: cabextract.c:1294
static int cabx_seek(struct mspack_file *file, off_t offset, int mode)
Definition: cabextract.c:1267

A cabextract-specific implementation of mspack_system that allows the NULL filename to be opened for writing as a synonym for writing to stdout.

Definition at line 199 of file cabextract.c.

Referenced by main().

◆ md5_context

struct md5_ctx md5_context

A global MD5 context, used when a file is written to TEST_FNAME

Definition at line 155 of file cabextract.c.

Referenced by cabx_close(), cabx_open(), and cabx_write().

◆ md5_result

unsigned char md5_result[16]

The resultant MD5 checksum, used when a file is written to TEST_FNAME

Definition at line 161 of file cabextract.c.

Referenced by cabx_close(), and process_cabinet().

◆ optlist

struct option optlist[]
Initial value:
= {
{ "directory", 1, NULL, 'd' },
{ "fix", 0, NULL, 'f' },
{ "filter", 1, NULL, 'F' },
{ "help", 0, NULL, 'h' },
{ "list", 0, NULL, 'l' },
{ "lowercase", 0, NULL, 'L' },
{ "pipe", 0, NULL, 'p' },
{ "quiet", 0, NULL, 'q' },
{ "single", 0, NULL, 's' },
{ "test", 0, NULL, 't' },
{ "version", 0, NULL, 'v' },
{ NULL, 0, NULL, 0 }
}

Definition at line 1 of file cabextract.c.

Referenced by main().

◆ OPTSTRING

const char* OPTSTRING = "d:fF:hlLpqstv"

Definition at line 104 of file cabextract.c.

Referenced by main().

◆ STDOUT_FNAME

const char* STDOUT_FNAME = "stdout"

A special filename. Extracting to this filename will send the output to standard output instead of a file on disk. The magic happens in cabx_open() when the STDOUT_FNAME pointer is given as a filename, so treat this like a constant rather than a string.

Definition at line 148 of file cabextract.c.

Referenced by cabx_open(), and process_cabinet().

◆ TEST_FNAME

const char* TEST_FNAME = "test"

A special filename. Extracting to this filename will send the output through an MD5 checksum calculator, instead of a file on disk. The magic happens in cabx_open() when the TEST_FNAME pointer is given as a filename, so treat this like a constant rather than a string.

Definition at line 155 of file cabextract.c.

Referenced by cabx_close(), cabx_open(), cabx_write(), and process_cabinet().

◆ user_umask

mode_t user_umask = 0

Definition at line 132 of file cabextract.c.

Referenced by ensure_filepath(), main(), and set_date_and_perm().