1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <time.h>
5 
6 #include "physfs.h"
7 
8 
9 static int failure = 0;
10 
modTimeToStr(PHYSFS_sint64 modtime,char * modstr,size_t strsize)11 static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
12 {
13     const char *str = "unknown modtime";
14     if (modtime != -1)
15     {
16         time_t t = (time_t) modtime;
17         str = ctime(&t);
18     } /* if */
19 
20     strncpy(modstr, str, strsize);
21     modstr[strsize-1] = '\0';
22     strsize = strlen(modstr);
23     while ((modstr[strsize-1] == '\n') || (modstr[strsize-1] == '\r'))
24         modstr[--strsize] = '\0';
25 } /* modTimeToStr */
26 
27 
fail(const char * what,const char * why)28 static void fail(const char *what, const char *why)
29 {
30     if (why == NULL)
31         why = PHYSFS_getLastError();
32     fprintf(stderr, "%s failed: %s\n", what, why);
33     failure = 1;
34 } /* fail */
35 
36 
dumpFile(const char * fname)37 static void dumpFile(const char *fname)
38 {
39     const int origfailure = failure;
40     PHYSFS_File *out = NULL;
41     PHYSFS_File *in = NULL;
42 
43     failure = 0;
44 
45     if ((in = PHYSFS_openRead(fname)) == NULL)
46         fail("\nPHYSFS_openRead", NULL);
47     else if ((out = PHYSFS_openWrite(fname)) == NULL)
48         fail("\nPHYSFS_openWrite", NULL);
49     else
50     {
51         char modstr[64];
52         PHYSFS_sint64 size = PHYSFS_fileLength(in);
53 
54         printf("(");
55         if (size == -1)
56             printf("?");
57         else
58             printf("%lld", (long long) size);
59         printf(" bytes");
60 
61         modTimeToStr(PHYSFS_getLastModTime(fname), modstr, sizeof (modstr));
62         printf(", %s)\n", modstr);
63 
64         while ( (!failure) && (!PHYSFS_eof(in)) )
65         {
66             static char buf[64 * 1024];
67             PHYSFS_sint64 br = PHYSFS_read(in, buf, 1, sizeof (buf));
68             if (br == -1)
69                 fail("PHYSFS_read", NULL);
70             else
71             {
72                 PHYSFS_sint64 bw = PHYSFS_write(out, buf, 1, br);
73                 if (bw != br)
74                     fail("PHYSFS_write", NULL);
75                 else
76                     size -= bw;
77             } /* else */
78         } /* while */
79 
80         if ((!failure) && (size != 0))
81             fail("PHYSFS_eof", "BUG! eof != PHYSFS_fileLength bytes!");
82     } /* else */
83 
84     if (in != NULL)
85         PHYSFS_close(in);
86 
87     if (out != NULL)
88     {
89         if (!PHYSFS_close(out))
90             fail("PHYSFS_close", NULL);
91     } /* if */
92 
93     if (failure)
94         PHYSFS_delete(fname);
95     else
96         failure = origfailure;
97 } /* dumpFile */
98 
99 
unpackCallback(void * _depth,const char * origdir,const char * str)100 static void unpackCallback(void *_depth, const char *origdir, const char *str)
101 {
102     int depth = *((int *) _depth);
103     const int len = strlen(origdir) + strlen(str) + 2;
104     char *fname = (char *) malloc(len);
105     if (fname == NULL)
106         fail("malloc", "Out of memory!");
107     else
108     {
109         if (strcmp(origdir, "/") == 0)
110             origdir = "";
111 
112         snprintf(fname, len, "%s/%s", origdir, str);
113 
114         printf("%s ", fname);
115         if (PHYSFS_isDirectory(fname))
116         {
117             depth++;
118             printf("(directory)\n");
119             if (!PHYSFS_mkdir(fname))
120                 fail("PHYSFS_mkdir", NULL);
121             else
122                 PHYSFS_enumerateFilesCallback(fname, unpackCallback, &depth);
123         } /* if */
124 
125         else if (PHYSFS_isSymbolicLink(fname))
126         {
127             printf("(symlink)\n");
128             /* !!! FIXME: ?  if (!symlink(fname, */
129         } /* else if */
130 
131         else  /* ...file. */
132         {
133             dumpFile(fname);
134         } /* else */
135 
136         free(fname);
137     } /* else */
138 } /* unpackCallback */
139 
140 
main(int argc,char ** argv)141 int main(int argc, char **argv)
142 {
143     int zero = 0;
144 
145     if (argc != 3)
146     {
147         fprintf(stderr, "USAGE: %s <archive> <unpackDirectory>\n", argv[0]);
148         return 1;
149     } /* if */
150 
151     if (!PHYSFS_init(argv[0]))
152     {
153         fprintf(stderr, "PHYSFS_init() failed: %s\n", PHYSFS_getLastError());
154         return 2;
155     } /* if */
156 
157     if (!PHYSFS_setWriteDir(argv[2]))
158     {
159         fprintf(stderr, "PHYSFS_setWriteDir('%s') failed: %s\n",
160                 argv[2], PHYSFS_getLastError());
161         return 3;
162     } /* if */
163 
164     if (!PHYSFS_mount(argv[1], NULL, 1))
165     {
166         fprintf(stderr, "PHYSFS_mount('%s') failed: %s\n",
167                 argv[1], PHYSFS_getLastError());
168         return 4;
169     } /* if */
170 
171     PHYSFS_permitSymbolicLinks(1);
172     PHYSFS_enumerateFilesCallback("/", unpackCallback, &zero);
173     PHYSFS_deinit();
174     if (failure)
175         return 5;
176 
177     return 0;
178 } /* main */
179 
180 /* end of physfsunpack.c ... */
181 
182