]> git.draconx.ca Git - liblbx.git/blob - src/lbxtool.c
Fix lbx_extract's seeking to maintain a correct offset even on errors.
[liblbx.git] / src / lbxtool.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <getopt.h>
6
7 #include "lbx.h"
8
9 static const char *progname;
10 #define errmsg(fmt, ...) (\
11         fprintf(stderr, "%s: " fmt, progname, __VA_ARGS__)\
12 )
13
14 enum {
15         MODE_NONE,
16         MODE_LIST,
17         MODE_EXTRACT,
18 };
19
20 int list(FILE *f, const char *name, int verbose) {
21         LBX *lbx;
22         size_t nfiles;
23         unsigned int i;
24
25         lbx = lbx_fopen(f, name);
26         if (!lbx) {
27                 errmsg("failed to open archive: %s.\n", lbx_strerror());
28                 return EXIT_FAILURE;
29         }
30
31         nfiles = lbx_numfiles(lbx);
32         if (verbose) {
33                 printf("Files in archive: %zu\n", nfiles);
34         }
35
36         for (i = 0; i < nfiles; i++) {
37                 struct lbx_statbuf stat;
38
39                 lbx_stat(lbx, i, &stat);
40                 printf("%s", stat.name);
41                 if (verbose) {
42                         printf(" size=%zu bytes", stat.size);
43                 }
44
45                 putchar('\n');
46         }
47
48         lbx_close(lbx);
49         return EXIT_SUCCESS;
50 }
51
52 int extract(FILE *f, const char *name, int verbose) {
53         LBX *lbx;
54         size_t nfiles;
55         unsigned int i;
56
57         lbx = lbx_fopen(f, name);
58         if (!lbx) {
59                 errmsg("failed to open archive: %s.\n", lbx_strerror());
60                 return EXIT_FAILURE;
61         }
62
63         nfiles = lbx_numfiles(lbx);
64         if (verbose) {
65                 printf("Files in archive: %zu\n", nfiles);
66         }
67
68         for (i = 0; i < nfiles; i++) {
69                 struct lbx_statbuf stat;
70                 size_t rc;
71                 FILE *of;
72
73                 lbx_stat(lbx, i, &stat);
74                 of = fopen(stat.name, "wbx");
75                 if (!of) {
76                         errmsg("failed to create output file %s: %m.\n",
77                                                              stat.name);
78                         break;
79                 }
80
81                 if (verbose) printf("extracting %s...\n", stat.name);
82                 rc = lbx_extract(lbx, i, of);
83                 if (rc < stat.size) {
84                         if (rc == 0) remove(stat.name);
85                         errmsg("error extracting %s: %s.\n",
86                                stat.name, lbx_strerror());
87                         break;
88                 }
89                 if (verbose) printf("wrote %zu bytes.\n", rc);
90         }
91
92         lbx_close(lbx);
93         return EXIT_SUCCESS;
94 }
95
96 int main(int argc, char **argv)
97 {
98         int mode = MODE_NONE, verbose = 0;
99         const char *name = "stdin";
100         FILE *f  = stdin;
101         int opt;
102
103         static const char         *sopts   = "lxf:i:v";
104         static const struct option lopts[] = {
105                 { "list",    0, NULL, 'l' },
106                 { "extract", 0, NULL, 'x' },
107
108                 { "file",    1, NULL, 'f' },
109                 { "index",   1, NULL, 'i' },
110
111                 { "verbose", 0, NULL, 'v' },
112
113                 { 0 }
114         };
115
116         progname = "lbxtool"; /* argv[0]; */
117         while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
118                 switch(opt) {
119                 case 'l':
120                         mode = MODE_LIST;
121                         break;
122                 case 'x':
123                         mode = MODE_EXTRACT;
124                         break;
125                 case 'f':
126                         if (strcmp(optarg, "-") == 0)
127                                 break;
128
129                         name = strrchr(optarg, '/');
130                         name = name ? name+1 : optarg;
131
132                         f = fopen(optarg, "rb");
133                         if (!f) {
134                                 errmsg("failed to open file %s: %m\n", optarg);
135                                 return EXIT_FAILURE;
136                         }
137                         break;
138                 case 'i':
139                         /* FIXME: Add index file support. */
140                         break;
141                 case 'v':
142                         verbose = 1;
143                         break;
144                 default:
145                         return EXIT_FAILURE;
146                 }
147         }
148
149         switch (mode) {
150         case MODE_LIST:
151                 return list(f, name, verbose);
152         case MODE_EXTRACT:
153                 return extract(f, name, verbose);
154         }
155
156         fprintf(stderr, "%s: you must specify a mode.\n", progname);
157         return EXIT_FAILURE;
158 }