1
+ /*
2
+ +----------------------------------------------------------------------+
3
+ | phar php single-file executable PHP extension |
4
+ +----------------------------------------------------------------------+
5
+ | Copyright (c) 2006-2007 The PHP Group |
6
+ +----------------------------------------------------------------------+
7
+ | This source file is subject to version 3.01 of the PHP license, |
8
+ | that is bundled with this package in the file LICENSE, and is |
9
+ | available through the world-wide-web at the following url: |
10
+ | http://www.php.net/license/3_01.txt. |
11
+ | If you did not receive a copy of the PHP license and are unable to |
12
+ | obtain it through the world-wide-web, please send a note to |
13
+ | license@php.net so we can mail you a copy immediately. |
14
+ +----------------------------------------------------------------------+
15
+ | Authors: Gregory Beaver <cellog@php.net> |
16
+ | Marcus Boerger <helly@php.net> |
17
+ | based on work by Dmitry Stogov <dmitry@zend.com> |
18
+ +----------------------------------------------------------------------+
19
+ */
20
+
21
+ /* $Id$ */
22
+
23
+ #include "phar_internal.h"
24
+
25
+
26
+ #define TAR_FILE '0'
27
+ #define TAR_LINK '1'
28
+ #define TAR_SYMLINK '2'
29
+ #define TAR_DIR '5'
30
+ #define TAR_NEW '8'
31
+
32
+ /**
33
+ * the format of the header block for a file, in the older UNIX-compatible
34
+ * TAR format
35
+ */
36
+ typedef struct _old_tar_header { /* {{{ */
37
+ char name [100 ]; /* name of file;
38
+ directory is indicated by a trailing slash (/) */
39
+ char mode [8 ]; /* file mode */
40
+ char uid [8 ]; /* owner user ID */
41
+ char gid [8 ]; /* owner group ID */
42
+ char size [12 ]; /* length of file in bytes */
43
+ char mtime [12 ]; /* modify time of file */
44
+ char chksum [8 ]; /* checksum for header */
45
+ char link ; /* indicator for links;
46
+ 1 for a linked file,
47
+ 2 for a symbolic link,
48
+ 0 otherwise */
49
+ char linkname [100 ]; /* name of linked file */
50
+ } old_tar_header ;
51
+ /* }}} */
52
+
53
+ /**
54
+ * the new USTAR header format.
55
+ * Note that tar can determine that the USTAR format is being used by the
56
+ * presence of the null-terminated string "ustar" in the magic field.
57
+ */
58
+ typedef struct _tar_header { /* {{{ */
59
+ char name [100 ]; /* name of file */
60
+ char mode [8 ]; /* file mode */
61
+ char uid [8 ]; /* owner user ID */
62
+ char gid [8 ]; /* owner group ID */
63
+ char size [12 ]; /* length of file in bytes */
64
+ char mtime [12 ]; /* modify time of file */
65
+ char chksum [8 ]; /* checksum for header */
66
+ char typeflag ; /* type of file
67
+ 0 Regular file
68
+ 1 Link to another file already archived
69
+ 2 Symbolic link
70
+ 3 Character special device
71
+ 4 Block special device
72
+ 5 Directory
73
+ 6 FIFO special file
74
+ 7 Reserved */
75
+ char linkname [100 ]; /* name of linked file */
76
+ char magic [6 ]; /* USTAR indicator */
77
+ char version [2 ]; /* USTAR version */
78
+ char uname [32 ]; /* owner user name */
79
+ char gname [32 ]; /* owner group name */
80
+ char devmajor [8 ]; /* device major number */
81
+ char devminor [8 ]; /* device minor number */
82
+ char prefix [155 ]; /* prefix for file name;
83
+ the value of the prefix field, if non-null,
84
+ is prefixed to the name field to allow names
85
+ longer then 100 characters */
86
+ } tar_header ;
87
+ /* }}} */
88
+
89
+ typedef struct _tar_file tar_file ;
90
+
91
+ typedef struct _tar_entry { /* {{{ */
92
+ tar_file * tar ;
93
+ char type ;
94
+ off_t start ;
95
+ off_t pos ;
96
+ off_t size ;
97
+ mode_t mode ;
98
+ time_t mtime ;
99
+ uid_t uid ;
100
+ gid_t gid ;
101
+ union {
102
+ HashTable * content ;
103
+ char * link ;
104
+ } u ;
105
+ } tar_entry ;
106
+ /* }}} */
107
+
108
+ struct _tar_file { /* {{{ */
109
+ php_stream * stream ;
110
+ char * real_name ;
111
+ int refcount ;
112
+ int opened ;
113
+ tar_entry root ;
114
+ };
115
+ /* }}} */
116
+
117
+ static int tar_number (char * buf , int len ) /* {{{ */
118
+ {
119
+ int num = 0 ;
120
+ int i = 0 ;
121
+
122
+ while (i < len && buf [i ] == ' ' ) {
123
+ i ++ ;
124
+ }
125
+ while (i < len &&
126
+ buf [i ] >= '0' &&
127
+ buf [i ] <= '7' ) {
128
+ num = num * 8 + (buf [i ] - '0' );
129
+ i ++ ;
130
+ }
131
+ return num ;
132
+ }
133
+ /* }}} */
134
+
135
+ static int tar_checksum (char * buf , int len ) /* {{{ */
136
+ {
137
+ int sum = 0 ;
138
+ char * end = buf + len ;
139
+
140
+ while (buf != end ) {
141
+ sum += (unsigned char )* buf ;
142
+ buf ++ ;
143
+ }
144
+ return sum ;
145
+ }
146
+ /* }}} */
147
+ #define MAPPHAR_ALLOC_FAIL (msg ) \
148
+ php_stream_close(fp);\
149
+ if (error) {\
150
+ spprintf(error, 0, msg, fname);\
151
+ }\
152
+ return FAILURE;
153
+
154
+ #ifdef WORDS_BIGENDIAN
155
+ # define PHAR_GET_32 (buffer , var ) \
156
+ var = ((((unsigned char*)(buffer))[3]) << 24) \
157
+ | ((((unsigned char*)(buffer))[2]) << 16) \
158
+ | ((((unsigned char*)(buffer))[1]) << 8) \
159
+ | (((unsigned char*)(buffer))[0]); \
160
+ (buffer) += 4
161
+ # define PHAR_GET_16 (buffer , var ) \
162
+ var = ((((unsigned char*)(buffer))[1]) << 8) \
163
+ | (((unsigned char*)(buffer))[0]); \
164
+ (buffer) += 2
165
+ #else
166
+ # define PHAR_GET_32 (buffer , var ) \
167
+ var = *(php_uint32*)(buffer); \
168
+ buffer += 4
169
+ # define PHAR_GET_16 (buffer , var ) \
170
+ var = *(php_uint16*)(buffer); \
171
+ buffer += 2
172
+ #endif
173
+
174
+ int phar2_open_file (php_stream * fp , char * fname , int fname_len , char * alias , int alias_len , long halt_offset , phar_archive_data * * pphar , char * buffer , char * * error TSRMLS_DC ) /* {{{ */
175
+ {
176
+ /* The structure of a tar-based phar archive is as follows:
177
+ - the first file contains the loader stub and file hash. The file hash is a mapping
178
+ of filename hash to location of manifest data within the official phar manifest using
179
+ an implementation of open hash that allows the entire thing to be read in without any
180
+ processing beyond signature check.
181
+ - the second file contains the official phar manifest as used in phar 1.x
182
+ - third file to second-to-last file contain the phar's files
183
+ - final file contains the phar signature
184
+ */
185
+ php_uint32 openhash_len ;
186
+ phar_archive_data * mydata ;
187
+
188
+ buffer += 6 ;
189
+ PHAR_GET_32 (buffer ), openhash_len );
190
+ if (openhash_len != sizeof (phar2_openhash ) && openhash_len != sizeof (phar2_openhash_large )) {
191
+ MAPPHAR_ALLOC_FAIL ("Corrupted phar2 archive, filename hash is wrong size in phar \"%s\"" );
192
+ }
193
+ buffer -= 6 ;
194
+ buffer = (char * ) erealloc ((void * ) buffer , openhash_len );
195
+ if (!buffer ) {
196
+ MAPPHAR_ALLOC_FAIL ("Could not allocate space for fast filename hash in phar \"%s\"" );
197
+ }
198
+ if (openhash_len != php_stream_read (fp , buffer , openhash_len )) {
199
+ MAPPHAR_ALLOC_FAIL ("Could not read fast filename hash in phar \"%s\"" );
200
+ }
201
+
202
+ PHAR_G (fast_fname_map ) = (phar2_openhash * ) buffer ;
203
+ mydata = ecalloc (sizeof (phar_archive_data ), 1 );
204
+
205
+ /* check whether we have meta data, zero check works regardless of byte order */
206
+ if (phar_parse_metadata (fp , & buffer , endbuffer , & mydata -> metadata TSRMLS_CC ) == FAILURE ) {
207
+ MAPPHAR_FAIL ("unable to read phar metadata in .phar file \"%s\"" );
208
+ }
209
+
210
+ /* set up our manifest - entries will be created JIT as accessed */
211
+ zend_hash_init (& mydata -> manifest , sizeof (phar_entry_info ),
212
+ zend_get_hash_value , destroy_phar_manifest , 0 );
213
+ snprintf (mydata -> version , sizeof (mydata -> version ), "%u.%u.%u" , manifest_ver >> 12 , (manifest_ver >> 8 ) & 0xF , (manifest_ver >> 4 ) & 0xF );
214
+ mydata -> internal_file_start = halt_offset + manifest_len + 4 ;
215
+ mydata -> halt_offset = halt_offset ;
216
+ mydata -> flags = manifest_flags ;
217
+ mydata -> fp = fp ;
218
+ mydata -> fname = estrndup (fname , fname_len );
219
+ #ifdef PHP_WIN32
220
+ phar_unixify_path_separators (mydata -> fname , fname_len );
221
+ #endif
222
+ mydata -> fname_len = fname_len ;
223
+ mydata -> alias = alias ? estrndup (alias , alias_len ) : mydata -> fname ;
224
+ mydata -> alias_len = alias ? alias_len : fname_len ;
225
+ mydata -> sig_flags = sig_flags ;
226
+ mydata -> sig_len = sig_len ;
227
+ mydata -> signature = signature ;
228
+ phar_request_initialize (TSRMLS_C );
229
+ zend_hash_add (& (PHAR_GLOBALS -> phar_fname_map ), mydata -> fname , fname_len , (void * )& mydata , sizeof (phar_archive_data * ), NULL );
230
+ if (register_alias ) {
231
+ mydata -> is_explicit_alias = 1 ;
232
+ zend_hash_add (& (PHAR_GLOBALS -> phar_alias_map ), alias , alias_len , (void * )& mydata , sizeof (phar_archive_data * ), NULL );
233
+ } else {
234
+ mydata -> is_explicit_alias = 0 ;
235
+ }
236
+ efree (savebuf );
237
+
238
+ if (pphar ) {
239
+ * pphar = mydata ;
240
+ }
241
+
242
+ return SUCCESS ;
243
+ }
244
+ /* }}} */
0 commit comments