diff options
-rw-r--r-- | fake-winterop.c | 17 | ||||
-rwxr-xr-x | makecab.py | 107 |
2 files changed, 112 insertions, 12 deletions
diff --git a/fake-winterop.c b/fake-winterop.c index eb891c4..cc69179 100644 --- a/fake-winterop.c +++ b/fake-winterop.c | |||
@@ -26,7 +26,6 @@ uint32_t ResetAcls(const char16_t **pwzFiles, uint32_t cFiles) | |||
26 | } | 26 | } |
27 | 27 | ||
28 | typedef struct CabCreateContext { | 28 | typedef struct CabCreateContext { |
29 | char *tempdir; | ||
30 | char *outdir; | 29 | char *outdir; |
31 | char *outfile; | 30 | char *outfile; |
32 | 31 | ||
@@ -43,14 +42,11 @@ uint32_t CreateCabBegin(const char16_t *wzCab, const char16_t *wzCabDir, | |||
43 | ctx->outdir = ascii(wzCabDir, true); | 42 | ctx->outdir = ascii(wzCabDir, true); |
44 | ctx->outfile = dupcat(ctx->outdir, "/", | 43 | ctx->outfile = dupcat(ctx->outdir, "/", |
45 | ascii(wzCab, true), (const char *)NULL); | 44 | ascii(wzCab, true), (const char *)NULL); |
46 | ctx->tempdir = dupcat(ctx->outdir, "/cabXXXXXX", (const char *)NULL); | ||
47 | if (!mkdtemp(ctx->tempdir)) | ||
48 | err(1, "mkdtemp"); | ||
49 | ctx->nargs = 0; | 45 | ctx->nargs = 0; |
50 | ctx->argsize = 16; | 46 | ctx->argsize = 16; |
51 | ctx->args = snewn(ctx->argsize, char *); | 47 | ctx->args = snewn(ctx->argsize, char *); |
52 | ctx->args[ctx->nargs++] = dupcat("lcab", (const char *)NULL); | 48 | ctx->args[ctx->nargs++] = dupcat("makecab.py", (const char *)NULL); |
53 | ctx->args[ctx->nargs++] = dupcat("-n", (const char *)NULL); | 49 | ctx->args[ctx->nargs++] = ctx->outfile; |
54 | *out_ctx = ctx; | 50 | *out_ctx = ctx; |
55 | return 0; | 51 | return 0; |
56 | } | 52 | } |
@@ -61,16 +57,14 @@ uint32_t CreateCabAddFile(const char16_t *wzFile, const char16_t *wzToken, | |||
61 | char *file = ascii(wzFile, true); | 57 | char *file = ascii(wzFile, true); |
62 | char *file_abs = realpath(file, NULL); | 58 | char *file_abs = realpath(file, NULL); |
63 | char *cabname = ascii(wzToken, true); | 59 | char *cabname = ascii(wzToken, true); |
64 | char *cab_abs = dupcat(ctx->tempdir, "/", cabname, (const char *)NULL); | ||
65 | printf("CreateCabAddFile: %s :: %s <- %s\n", ctx->outfile, | 60 | printf("CreateCabAddFile: %s :: %s <- %s\n", ctx->outfile, |
66 | cabname, file_abs); | 61 | cabname, file_abs); |
67 | if (symlink(file_abs, cab_abs) < 0) | ||
68 | err(1, "symlink"); | ||
69 | if (ctx->nargs + 1 >= ctx->argsize) { | 62 | if (ctx->nargs + 1 >= ctx->argsize) { |
70 | ctx->argsize = ctx->nargs * 5 / 4 + 16; | 63 | ctx->argsize = ctx->nargs * 5 / 4 + 16; |
71 | ctx->args = sresize(ctx->args, ctx->argsize, char *); | 64 | ctx->args = sresize(ctx->args, ctx->argsize, char *); |
72 | } | 65 | } |
73 | ctx->args[ctx->nargs++] = cab_abs; | 66 | ctx->args[ctx->nargs++] = cabname; |
67 | ctx->args[ctx->nargs++] = file_abs; | ||
74 | return 0; | 68 | return 0; |
75 | } | 69 | } |
76 | 70 | ||
@@ -86,11 +80,10 @@ uint32_t CreateCabAddFiles(const char16_t *const *pwzFiles, | |||
86 | 80 | ||
87 | uint32_t CreateCabFinish(CabCreateContext *ctx, void (*split_callback)(void)) | 81 | uint32_t CreateCabFinish(CabCreateContext *ctx, void (*split_callback)(void)) |
88 | { | 82 | { |
89 | if (ctx->nargs + 2 >= ctx->argsize) { | 83 | if (ctx->nargs + 1 >= ctx->argsize) { |
90 | ctx->argsize = ctx->nargs * 5 / 4 + 16; | 84 | ctx->argsize = ctx->nargs * 5 / 4 + 16; |
91 | ctx->args = sresize(ctx->args, ctx->argsize, char *); | 85 | ctx->args = sresize(ctx->args, ctx->argsize, char *); |
92 | } | 86 | } |
93 | ctx->args[ctx->nargs++] = ctx->outfile; | ||
94 | ctx->args[ctx->nargs++] = NULL; | 87 | ctx->args[ctx->nargs++] = NULL; |
95 | system_argv_array(ctx->args); | 88 | system_argv_array(ctx->args); |
96 | return 0; | 89 | return 0; |
diff --git a/makecab.py b/makecab.py new file mode 100755 index 0000000..befa94a --- /dev/null +++ b/makecab.py | |||
@@ -0,0 +1,107 @@ | |||
1 | #!/usr/bin/env python | ||
2 | |||
3 | import sys | ||
4 | import os | ||
5 | import time | ||
6 | import zlib | ||
7 | import struct | ||
8 | from collections import namedtuple | ||
9 | |||
10 | CFHEADER_s = struct.Struct("<4sLLLLLBBHHHHH") | ||
11 | CFHEADER = namedtuple("CFHEADER", "sig res0 size res1 firstfile res2 " | ||
12 | "verminor vermajor folders files flags setid icabinet") | ||
13 | CFHEADER_sig = "MSCF" | ||
14 | |||
15 | CFFOLDER_s = struct.Struct("<LHH") | ||
16 | CFFOLDER = namedtuple("CFFOLDER", "firstdata ndata compresstype") | ||
17 | |||
18 | CFFILE_s = struct.Struct("<LLHHHH") | ||
19 | CFFILE = namedtuple("CFFILE", "size offset ifolder date time attrs") | ||
20 | |||
21 | CFDATA_s = struct.Struct("<LHH") | ||
22 | CFDATA = namedtuple("CFDATA", "checksum compressedlen uncompressedlen") | ||
23 | |||
24 | def mszip(data): | ||
25 | compressor = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS, | ||
26 | zlib.DEF_MEM_LEVEL, zlib.Z_DEFAULT_STRATEGY) | ||
27 | compressed = compressor.compress(data) | ||
28 | compressed += compressor.flush() | ||
29 | return "CK" + compressed # add MSZIP header | ||
30 | |||
31 | def packdate(y,m,d): | ||
32 | return ((y - 1980) << 9) | (m << 5) | d | ||
33 | def packtime(h,m,s): | ||
34 | return ((h << 11) | (m << 5) | (s >> 1)) | ||
35 | |||
36 | def checksum(data): | ||
37 | data += "\0" * (3 & -len(data)) # pad to multiple of 4 bytes | ||
38 | toret = 0 | ||
39 | for offset in xrange(0, len(data), 4): | ||
40 | toret ^= struct.unpack_from("<L", data, offset)[0] | ||
41 | return toret | ||
42 | |||
43 | def build_cab(files): | ||
44 | uncompressed_data = "" | ||
45 | fileheaders = "" | ||
46 | for name, data, mtime in files: | ||
47 | mtime_u = time.gmtime(mtime) | ||
48 | fileheader = CFFILE( | ||
49 | size=len(data), offset=len(uncompressed_data), ifolder=0, attrs=0, | ||
50 | date=packdate(mtime_u.tm_year, mtime_u.tm_mon, mtime_u.tm_mday), | ||
51 | time=packtime(mtime_u.tm_hour, mtime_u.tm_min, mtime_u.tm_sec)) | ||
52 | uncompressed_data += data | ||
53 | fileheaders += CFFILE_s.pack(*fileheader) + name + "\0" | ||
54 | |||
55 | compressed_data = "" | ||
56 | offset = 0 | ||
57 | n_data_blocks = 0 | ||
58 | while offset < len(uncompressed_data): | ||
59 | uncompressed_block = uncompressed_data[offset:offset+0x8000] | ||
60 | compressed_block = mszip(uncompressed_block) | ||
61 | blockheader = CFDATA( | ||
62 | checksum=0, | ||
63 | compressedlen=len(compressed_block), | ||
64 | uncompressedlen=len(uncompressed_block)) | ||
65 | header_after_checksum = CFDATA_s.pack(*blockheader)[4:] | ||
66 | blockheader = blockheader._replace( | ||
67 | checksum=checksum(header_after_checksum + compressed_block)) | ||
68 | compressed_data += CFDATA_s.pack(*blockheader) + compressed_block | ||
69 | offset += len(uncompressed_block) | ||
70 | n_data_blocks += 1 | ||
71 | |||
72 | totalsize = (CFHEADER_s.size + | ||
73 | CFFOLDER_s.size + | ||
74 | len(fileheaders) + | ||
75 | len(compressed_data)) | ||
76 | |||
77 | header = CFHEADER( | ||
78 | sig=CFHEADER_sig, res0=0, res1=0, res2=0, | ||
79 | vermajor=1, verminor=3, folders=1, files=len(files), | ||
80 | flags=0, setid=0, icabinet=0, size=totalsize, | ||
81 | firstfile=CFHEADER_s.size + CFFOLDER_s.size) | ||
82 | |||
83 | folder = CFFOLDER( | ||
84 | ndata=n_data_blocks, compresstype=1, | ||
85 | firstdata = (CFHEADER_s.size + CFFOLDER_s.size + len(fileheaders))) | ||
86 | |||
87 | return (CFHEADER_s.pack(*header) + | ||
88 | CFFOLDER_s.pack(*folder) + | ||
89 | fileheaders + | ||
90 | compressed_data) | ||
91 | |||
92 | def main(): | ||
93 | args = sys.argv[1:] | ||
94 | outfile = args.pop(0) | ||
95 | files = [] | ||
96 | while len(args) > 0: | ||
97 | cabname = args.pop(0) | ||
98 | filename = args.pop(0) | ||
99 | with open(filename, "rb") as f: | ||
100 | filedata = f.read() | ||
101 | files.append((cabname, filedata, os.stat(filename).st_mtime)) | ||
102 | cabdata = build_cab(files) | ||
103 | with open(outfile, "wb") as f: | ||
104 | f.write(cabdata) | ||
105 | |||
106 | if __name__ == '__main__': | ||
107 | main() | ||