Projet

Général

Profil

Paste
Télécharger (86,2 ko) Statistiques
| Branche: | Révision:

root / drupal7 / modules / system / system.tar.inc @ 01dfd3b5

1 85ad3d82 Assos Assos
<?php
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
4
/**
5
 * File::CSV
6
 *
7
 * PHP versions 4 and 5
8
 *
9
 * Copyright (c) 1997-2008,
10
 * Vincent Blavet <vincent@phpconcept.net>
11
 * All rights reserved.
12
 *
13
 * Redistribution and use in source and binary forms, with or without
14
 * modification, are permitted provided that the following conditions are met:
15
 *
16
 *     * Redistributions of source code must retain the above copyright notice,
17
 *       this list of conditions and the following disclaimer.
18
 *     * Redistributions in binary form must reproduce the above copyright
19
 *       notice, this list of conditions and the following disclaimer in the
20
 *       documentation and/or other materials provided with the distribution.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
 *
33 30d5b9c5 Mathieu Schiano
 * @category  File_Formats
34
 * @package   Archive_Tar
35
 * @author    Vincent Blavet <vincent@phpconcept.net>
36
 * @copyright 1997-2010 The Authors
37
 * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
38
 * @version   CVS: $Id$
39
 * @link      http://pear.php.net/package/Archive_Tar
40
 */
41
42
 /**
43 27e02aed Assos Assos
 * Note on Drupal 7 porting.
44
 * This file origin is Tar.php, release 1.4.9 (stable) with some code
45
 * from PEAR.php, release 1.10.10 (stable) both at http://pear.php.net.
46 30d5b9c5 Mathieu Schiano
 * To simplify future porting from pear of this file, you should not
47
 * do cosmetic or other non significant changes to this file.
48
 * The following changes have been done:
49
 *  Removed require_once 'PEAR.php'.
50
 *  Added defintion of OS_WINDOWS taken from PEAR.php.
51
 *  Removed extends PEAR from class.
52
 *  Removed call parent:: __construct().
53
 *  Changed PEAR::loadExtension($extname) to this->loadExtension($extname).
54
 *  Added function loadExtension() taken from PEAR.php.
55
 *  Changed all calls of unlink() to drupal_unlink().
56
 *  Changed $this->error_object = &$this->raiseError($p_message)
57 27e02aed Assos Assos
 *  to throw new Exception($p_message).
58 30d5b9c5 Mathieu Schiano
 */
59
60
// Drupal removal require_once 'PEAR.php'.
61
62
// Drupal addition OS_WINDOWS as defined in PEAR.php.
63
if (substr(PHP_OS, 0, 3) == 'WIN') {
64
    define('OS_WINDOWS', true);
65
} else {
66
    define('OS_WINDOWS', false);
67
}
68
69
define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
70
define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
71
72
if (!function_exists('gzopen') && function_exists('gzopen64')) {
73
    function gzopen($filename, $mode, $use_include_path = 0)
74
    {
75
        return gzopen64($filename, $mode, $use_include_path);
76
    }
77
}
78
79
if (!function_exists('gztell') && function_exists('gztell64')) {
80
    function gztell($zp)
81
    {
82
        return gztell64($zp);
83
    }
84
}
85
86
if (!function_exists('gzseek') && function_exists('gzseek64')) {
87
    function gzseek($zp, $offset, $whence = SEEK_SET)
88
    {
89
        return gzseek64($zp, $offset, $whence);
90
    }
91
}
92 85ad3d82 Assos Assos
93
/**
94 30d5b9c5 Mathieu Schiano
 * Creates a (compressed) Tar archive
95
 *
96
 * @package Archive_Tar
97
 * @author  Vincent Blavet <vincent@phpconcept.net>
98
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
99
 * @version $Revision$
100
 */
101
// Drupal change class Archive_Tar extends PEAR.
102
class Archive_Tar
103 85ad3d82 Assos Assos
{
104
    /**
105 30d5b9c5 Mathieu Schiano
     * @var string Name of the Tar
106
     */
107
    public $_tarname = '';
108 85ad3d82 Assos Assos
109
    /**
110 30d5b9c5 Mathieu Schiano
     * @var boolean if true, the Tar file will be gzipped
111
     */
112
    public $_compress = false;
113 85ad3d82 Assos Assos
114
    /**
115 30d5b9c5 Mathieu Schiano
     * @var string Type of compression : 'none', 'gz', 'bz2' or 'lzma2'
116
     */
117
    public $_compress_type = 'none';
118 85ad3d82 Assos Assos
119
    /**
120 30d5b9c5 Mathieu Schiano
     * @var string Explode separator
121
     */
122
    public $_separator = ' ';
123 85ad3d82 Assos Assos
124
    /**
125 30d5b9c5 Mathieu Schiano
     * @var file descriptor
126
     */
127
    public $_file = 0;
128 85ad3d82 Assos Assos
129
    /**
130 30d5b9c5 Mathieu Schiano
     * @var string Local Tar name of a remote Tar (http:// or ftp://)
131
     */
132
    public $_temp_tarname = '';
133 85ad3d82 Assos Assos
134
    /**
135 30d5b9c5 Mathieu Schiano
     * @var string regular expression for ignoring files or directories
136
     */
137
    public $_ignore_regexp = '';
138
139
    /**
140
     * @var object PEAR_Error object
141
     */
142
    public $error_object = null;
143
144 27e02aed Assos Assos
    /**
145
     * Format for data extraction
146
     *
147
     * @var string
148
     */
149
    public $_fmt = '';
150
151
    /**
152
     * @var int Length of the read buffer in bytes
153
     */
154
    protected $buffer_length;
155
156 30d5b9c5 Mathieu Schiano
    /**
157
     * Archive_Tar Class constructor. This flavour of the constructor only
158
     * declare a new Archive_Tar object, identifying it by the name of the
159
     * tar file.
160
     * If the compress argument is set the tar will be read or created as a
161
     * gzip or bz2 compressed TAR file.
162
     *
163
     * @param string $p_tarname The name of the tar archive to create
164
     * @param string $p_compress can be null, 'gz', 'bz2' or 'lzma2'. This
165
     *               parameter indicates if gzip, bz2 or lzma2 compression
166
     *               is required.  For compatibility reason the
167
     *               boolean value 'true' means 'gz'.
168 27e02aed Assos Assos
     * @param int $buffer_length Length of the read buffer in bytes
169 30d5b9c5 Mathieu Schiano
     *
170
     * @return bool
171
     */
172 27e02aed Assos Assos
    public function __construct($p_tarname, $p_compress = null, $buffer_length = 512)
173 85ad3d82 Assos Assos
    {
174 30d5b9c5 Mathieu Schiano
        // Drupal removal parent::__construct().
175
176 85ad3d82 Assos Assos
        $this->_compress = false;
177
        $this->_compress_type = 'none';
178
        if (($p_compress === null) || ($p_compress == '')) {
179
            if (@file_exists($p_tarname)) {
180
                if ($fp = @fopen($p_tarname, "rb")) {
181
                    // look for gzip magic cookie
182
                    $data = fread($fp, 2);
183
                    fclose($fp);
184
                    if ($data == "\37\213") {
185
                        $this->_compress = true;
186
                        $this->_compress_type = 'gz';
187 30d5b9c5 Mathieu Schiano
                        // No sure it's enought for a magic code ....
188 85ad3d82 Assos Assos
                    } elseif ($data == "BZ") {
189
                        $this->_compress = true;
190
                        $this->_compress_type = 'bz2';
191 30d5b9c5 Mathieu Schiano
                    } elseif (file_get_contents($p_tarname, false, null, 1, 4) == '7zXZ') {
192
                        $this->_compress = true;
193
                        $this->_compress_type = 'lzma2';
194 85ad3d82 Assos Assos
                    }
195
                }
196
            } else {
197
                // probably a remote file or some file accessible
198
                // through a stream interface
199
                if (substr($p_tarname, -2) == 'gz') {
200
                    $this->_compress = true;
201
                    $this->_compress_type = 'gz';
202
                } elseif ((substr($p_tarname, -3) == 'bz2') ||
203 30d5b9c5 Mathieu Schiano
                    (substr($p_tarname, -2) == 'bz')
204
                ) {
205 85ad3d82 Assos Assos
                    $this->_compress = true;
206
                    $this->_compress_type = 'bz2';
207 30d5b9c5 Mathieu Schiano
                } else {
208
                    if (substr($p_tarname, -2) == 'xz') {
209
                        $this->_compress = true;
210
                        $this->_compress_type = 'lzma2';
211
                    }
212 85ad3d82 Assos Assos
                }
213
            }
214
        } else {
215
            if (($p_compress === true) || ($p_compress == 'gz')) {
216
                $this->_compress = true;
217
                $this->_compress_type = 'gz';
218
            } else {
219 30d5b9c5 Mathieu Schiano
                if ($p_compress == 'bz2') {
220
                    $this->_compress = true;
221
                    $this->_compress_type = 'bz2';
222
                } else {
223
                    if ($p_compress == 'lzma2') {
224
                        $this->_compress = true;
225
                        $this->_compress_type = 'lzma2';
226
                    } else {
227
                        $this->_error(
228
                            "Unsupported compression type '$p_compress'\n" .
229
                            "Supported types are 'gz', 'bz2' and 'lzma2'.\n"
230
                        );
231
                        return false;
232
                    }
233
                }
234 85ad3d82 Assos Assos
            }
235
        }
236
        $this->_tarname = $p_tarname;
237 30d5b9c5 Mathieu Schiano
        if ($this->_compress) { // assert zlib or bz2 or xz extension support
238
            if ($this->_compress_type == 'gz') {
239 85ad3d82 Assos Assos
                $extname = 'zlib';
240 30d5b9c5 Mathieu Schiano
            } else {
241
                if ($this->_compress_type == 'bz2') {
242
                    $extname = 'bz2';
243
                } else {
244
                    if ($this->_compress_type == 'lzma2') {
245
                        $extname = 'xz';
246
                    }
247
                }
248
            }
249 85ad3d82 Assos Assos
250
            if (!extension_loaded($extname)) {
251 30d5b9c5 Mathieu Schiano
                // Drupal change PEAR::loadExtension($extname).
252 85ad3d82 Assos Assos
                $this->loadExtension($extname);
253
            }
254
            if (!extension_loaded($extname)) {
255 30d5b9c5 Mathieu Schiano
                $this->_error(
256
                    "The extension '$extname' couldn't be found.\n" .
257
                    "Please make sure your version of PHP was built " .
258
                    "with '$extname' support.\n"
259
                );
260 85ad3d82 Assos Assos
                return false;
261
            }
262
        }
263 cd5c298a Geoffroy Desvernay
264
265
        if (version_compare(PHP_VERSION, "5.5.0-dev") < 0) {
266
            $this->_fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
267 27e02aed Assos Assos
                "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
268
                "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
269 cd5c298a Geoffroy Desvernay
        } else {
270
            $this->_fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
271 27e02aed Assos Assos
                "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
272
                "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
273 cd5c298a Geoffroy Desvernay
        }
274
275
276 27e02aed Assos Assos
        $this->buffer_length = $buffer_length;
277 85ad3d82 Assos Assos
    }
278
279 30d5b9c5 Mathieu Schiano
    public function __destruct()
280
    {
281
        $this->_close();
282
        // ----- Look for a local copy to delete
283
        if ($this->_temp_tarname != '') {
284
            @drupal_unlink($this->_temp_tarname);
285
        }
286
    }
287
288
    // Drupal addition from PEAR.php.
289 85ad3d82 Assos Assos
    /**
290
    * OS independent PHP extension load. Remember to take care
291
    * on the correct extension name for case sensitive OSes.
292
    *
293
    * @param string $ext The extension name
294
    * @return bool Success or not on the dl() call
295
    */
296 cd5c298a Geoffroy Desvernay
    public static function loadExtension($ext)
297 85ad3d82 Assos Assos
    {
298 30d5b9c5 Mathieu Schiano
        if (extension_loaded($ext)) {
299
            return true;
300
        }
301 85ad3d82 Assos Assos
302 30d5b9c5 Mathieu Schiano
        // if either returns true dl() will produce a FATAL error, stop that
303
        if (
304
            function_exists('dl') === false ||
305 cd5c298a Geoffroy Desvernay
            ini_get('enable_dl') != 1
306 30d5b9c5 Mathieu Schiano
        ) {
307
            return false;
308
        }
309 85ad3d82 Assos Assos
310 30d5b9c5 Mathieu Schiano
        if (OS_WINDOWS) {
311
            $suffix = '.dll';
312
        } elseif (PHP_OS == 'HP-UX') {
313
            $suffix = '.sl';
314
        } elseif (PHP_OS == 'AIX') {
315
            $suffix = '.a';
316
        } elseif (PHP_OS == 'OSX') {
317
            $suffix = '.bundle';
318
        } else {
319
            $suffix = '.so';
320 85ad3d82 Assos Assos
        }
321
322 30d5b9c5 Mathieu Schiano
        return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
323 85ad3d82 Assos Assos
    }
324
325
326
    /**
327 30d5b9c5 Mathieu Schiano
     * This method creates the archive file and add the files / directories
328
     * that are listed in $p_filelist.
329
     * If a file with the same name exist and is writable, it is replaced
330
     * by the new tar.
331
     * The method return false and a PEAR error text.
332
     * The $p_filelist parameter can be an array of string, each string
333
     * representing a filename or a directory name with their path if
334
     * needed. It can also be a single string with names separated by a
335
     * single blank.
336
     * For each directory added in the archive, the files and
337
     * sub-directories are also added.
338
     * See also createModify() method for more details.
339
     *
340
     * @param array $p_filelist An array of filenames and directory names, or a
341
     *              single string with names separated by a single
342
     *              blank space.
343
     *
344
     * @return true on success, false on error.
345
     * @see    createModify()
346
     */
347
    public function create($p_filelist)
348 85ad3d82 Assos Assos
    {
349
        return $this->createModify($p_filelist, '', '');
350
    }
351
352
    /**
353 30d5b9c5 Mathieu Schiano
     * This method add the files / directories that are listed in $p_filelist in
354
     * the archive. If the archive does not exist it is created.
355
     * The method return false and a PEAR error text.
356
     * The files and directories listed are only added at the end of the archive,
357
     * even if a file with the same name is already archived.
358
     * See also createModify() method for more details.
359
     *
360
     * @param array $p_filelist An array of filenames and directory names, or a
361
     *              single string with names separated by a single
362
     *              blank space.
363
     *
364
     * @return true on success, false on error.
365
     * @see    createModify()
366
     * @access public
367
     */
368
    public function add($p_filelist)
369 85ad3d82 Assos Assos
    {
370
        return $this->addModify($p_filelist, '', '');
371
    }
372
373 30d5b9c5 Mathieu Schiano
    /**
374
     * @param string $p_path
375
     * @param bool $p_preserve
376 27e02aed Assos Assos
     * @param bool $p_symlinks
377 30d5b9c5 Mathieu Schiano
     * @return bool
378
     */
379 27e02aed Assos Assos
    public function extract($p_path = '', $p_preserve = false, $p_symlinks = true)
380 85ad3d82 Assos Assos
    {
381 27e02aed Assos Assos
        return $this->extractModify($p_path, '', $p_preserve, $p_symlinks);
382 85ad3d82 Assos Assos
    }
383
384 30d5b9c5 Mathieu Schiano
    /**
385
     * @return array|int
386
     */
387
    public function listContent()
388 85ad3d82 Assos Assos
    {
389
        $v_list_detail = array();
390
391
        if ($this->_openRead()) {
392
            if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
393
                unset($v_list_detail);
394
                $v_list_detail = 0;
395
            }
396
            $this->_close();
397
        }
398
399
        return $v_list_detail;
400
    }
401
402
    /**
403 30d5b9c5 Mathieu Schiano
     * This method creates the archive file and add the files / directories
404
     * that are listed in $p_filelist.
405
     * If the file already exists and is writable, it is replaced by the
406
     * new tar. It is a create and not an add. If the file exists and is
407
     * read-only or is a directory it is not replaced. The method return
408
     * false and a PEAR error text.
409
     * The $p_filelist parameter can be an array of string, each string
410
     * representing a filename or a directory name with their path if
411
     * needed. It can also be a single string with names separated by a
412
     * single blank.
413
     * The path indicated in $p_remove_dir will be removed from the
414
     * memorized path of each file / directory listed when this path
415
     * exists. By default nothing is removed (empty path '')
416
     * The path indicated in $p_add_dir will be added at the beginning of
417
     * the memorized path of each file / directory listed. However it can
418
     * be set to empty ''. The adding of a path is done after the removing
419
     * of path.
420
     * The path add/remove ability enables the user to prepare an archive
421
     * for extraction in a different path than the origin files are.
422
     * See also addModify() method for file adding properties.
423
     *
424
     * @param array $p_filelist An array of filenames and directory names,
425
     *                             or a single string with names separated by
426
     *                             a single blank space.
427
     * @param string $p_add_dir A string which contains a path to be added
428
     *                             to the memorized path of each element in
429
     *                             the list.
430
     * @param string $p_remove_dir A string which contains a path to be
431
     *                             removed from the memorized path of each
432
     *                             element in the list, when relevant.
433
     *
434
     * @return boolean true on success, false on error.
435
     * @see addModify()
436
     */
437
    public function createModify($p_filelist, $p_add_dir, $p_remove_dir = '')
438 85ad3d82 Assos Assos
    {
439
        $v_result = true;
440
441 30d5b9c5 Mathieu Schiano
        if (!$this->_openWrite()) {
442 85ad3d82 Assos Assos
            return false;
443 30d5b9c5 Mathieu Schiano
        }
444 85ad3d82 Assos Assos
445
        if ($p_filelist != '') {
446 30d5b9c5 Mathieu Schiano
            if (is_array($p_filelist)) {
447 85ad3d82 Assos Assos
                $v_list = $p_filelist;
448 30d5b9c5 Mathieu Schiano
            } elseif (is_string($p_filelist)) {
449 85ad3d82 Assos Assos
                $v_list = explode($this->_separator, $p_filelist);
450 30d5b9c5 Mathieu Schiano
            } else {
451 85ad3d82 Assos Assos
                $this->_cleanFile();
452
                $this->_error('Invalid file list');
453
                return false;
454
            }
455
456
            $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
457
        }
458
459
        if ($v_result) {
460
            $this->_writeFooter();
461
            $this->_close();
462 30d5b9c5 Mathieu Schiano
        } else {
463 85ad3d82 Assos Assos
            $this->_cleanFile();
464 30d5b9c5 Mathieu Schiano
        }
465 85ad3d82 Assos Assos
466
        return $v_result;
467
    }
468
469
    /**
470 30d5b9c5 Mathieu Schiano
     * This method add the files / directories listed in $p_filelist at the
471
     * end of the existing archive. If the archive does not yet exists it
472
     * is created.
473
     * The $p_filelist parameter can be an array of string, each string
474
     * representing a filename or a directory name with their path if
475
     * needed. It can also be a single string with names separated by a
476
     * single blank.
477
     * The path indicated in $p_remove_dir will be removed from the
478
     * memorized path of each file / directory listed when this path
479
     * exists. By default nothing is removed (empty path '')
480
     * The path indicated in $p_add_dir will be added at the beginning of
481
     * the memorized path of each file / directory listed. However it can
482
     * be set to empty ''. The adding of a path is done after the removing
483
     * of path.
484
     * The path add/remove ability enables the user to prepare an archive
485
     * for extraction in a different path than the origin files are.
486
     * If a file/dir is already in the archive it will only be added at the
487
     * end of the archive. There is no update of the existing archived
488
     * file/dir. However while extracting the archive, the last file will
489
     * replace the first one. This results in a none optimization of the
490
     * archive size.
491
     * If a file/dir does not exist the file/dir is ignored. However an
492
     * error text is send to PEAR error.
493
     * If a file/dir is not readable the file/dir is ignored. However an
494
     * error text is send to PEAR error.
495
     *
496
     * @param array $p_filelist An array of filenames and directory
497
     *                             names, or a single string with names
498
     *                             separated by a single blank space.
499
     * @param string $p_add_dir A string which contains a path to be
500
     *                             added to the memorized path of each
501
     *                             element in the list.
502
     * @param string $p_remove_dir A string which contains a path to be
503
     *                             removed from the memorized path of
504
     *                             each element in the list, when
505
     *                             relevant.
506
     *
507
     * @return true on success, false on error.
508
     */
509
    public function addModify($p_filelist, $p_add_dir, $p_remove_dir = '')
510 85ad3d82 Assos Assos
    {
511
        $v_result = true;
512
513 30d5b9c5 Mathieu Schiano
        if (!$this->_isArchive()) {
514
            $v_result = $this->createModify(
515
                $p_filelist,
516
                $p_add_dir,
517
                $p_remove_dir
518
            );
519
        } else {
520
            if (is_array($p_filelist)) {
521 85ad3d82 Assos Assos
                $v_list = $p_filelist;
522 30d5b9c5 Mathieu Schiano
            } elseif (is_string($p_filelist)) {
523 85ad3d82 Assos Assos
                $v_list = explode($this->_separator, $p_filelist);
524 30d5b9c5 Mathieu Schiano
            } else {
525 85ad3d82 Assos Assos
                $this->_error('Invalid file list');
526
                return false;
527
            }
528
529
            $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
530
        }
531
532
        return $v_result;
533
    }
534
535
    /**
536 30d5b9c5 Mathieu Schiano
     * This method add a single string as a file at the
537
     * end of the existing archive. If the archive does not yet exists it
538
     * is created.
539
     *
540
     * @param string $p_filename A string which contains the full
541
     *                           filename path that will be associated
542
     *                           with the string.
543
     * @param string $p_string The content of the file added in
544
     *                           the archive.
545
     * @param bool|int $p_datetime A custom date/time (unix timestamp)
546
     *                           for the file (optional).
547
     * @param array $p_params An array of optional params:
548
     *                               stamp => the datetime (replaces
549
     *                                   datetime above if it exists)
550
     *                               mode => the permissions on the
551
     *                                   file (600 by default)
552
     *                               type => is this a link?  See the
553
     *                                   tar specification for details.
554
     *                                   (default = regular file)
555
     *                               uid => the user ID of the file
556
     *                                   (default = 0 = root)
557
     *                               gid => the group ID of the file
558
     *                                   (default = 0 = root)
559
     *
560
     * @return true on success, false on error.
561
     */
562
    public function addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
563 85ad3d82 Assos Assos
    {
564 30d5b9c5 Mathieu Schiano
        $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
565
        $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
566
        $p_type = @$p_params["type"] ? $p_params["type"] : "";
567
        $p_uid = @$p_params["uid"] ? $p_params["uid"] : "";
568
        $p_gid = @$p_params["gid"] ? $p_params["gid"] : "";
569 85ad3d82 Assos Assos
        $v_result = true;
570
571
        if (!$this->_isArchive()) {
572
            if (!$this->_openWrite()) {
573
                return false;
574
            }
575
            $this->_close();
576
        }
577
578 30d5b9c5 Mathieu Schiano
        if (!$this->_openAppend()) {
579 85ad3d82 Assos Assos
            return false;
580 30d5b9c5 Mathieu Schiano
        }
581 85ad3d82 Assos Assos
582
        // Need to check the get back to the temporary file ? ....
583 30d5b9c5 Mathieu Schiano
        $v_result = $this->_addString($p_filename, $p_string, $p_datetime, $p_params);
584 85ad3d82 Assos Assos
585
        $this->_writeFooter();
586
587
        $this->_close();
588
589
        return $v_result;
590
    }
591
592
    /**
593 30d5b9c5 Mathieu Schiano
     * This method extract all the content of the archive in the directory
594
     * indicated by $p_path. When relevant the memorized path of the
595
     * files/dir can be modified by removing the $p_remove_path path at the
596
     * beginning of the file/dir path.
597
     * While extracting a file, if the directory path does not exists it is
598
     * created.
599
     * While extracting a file, if the file already exists it is replaced
600
     * without looking for last modification date.
601
     * While extracting a file, if the file already exists and is write
602
     * protected, the extraction is aborted.
603
     * While extracting a file, if a directory with the same name already
604
     * exists, the extraction is aborted.
605
     * While extracting a directory, if a file with the same name already
606
     * exists, the extraction is aborted.
607
     * While extracting a file/directory if the destination directory exist
608
     * and is write protected, or does not exist but can not be created,
609
     * the extraction is aborted.
610
     * If after extraction an extracted file does not show the correct
611
     * stored file size, the extraction is aborted.
612
     * When the extraction is aborted, a PEAR error text is set and false
613
     * is returned. However the result can be a partial extraction that may
614
     * need to be manually cleaned.
615
     *
616
     * @param string $p_path The path of the directory where the
617
     *                               files/dir need to by extracted.
618
     * @param string $p_remove_path Part of the memorized path that can be
619
     *                               removed if present at the beginning of
620
     *                               the file/dir path.
621
     * @param boolean $p_preserve Preserve user/group ownership of files
622 27e02aed Assos Assos
     * @param boolean $p_symlinks Allow symlinks.
623 30d5b9c5 Mathieu Schiano
     *
624
     * @return boolean true on success, false on error.
625
     * @see    extractList()
626
     */
627 27e02aed Assos Assos
    public function extractModify($p_path, $p_remove_path, $p_preserve = false, $p_symlinks = true)
628 85ad3d82 Assos Assos
    {
629
        $v_result = true;
630
        $v_list_detail = array();
631
632
        if ($v_result = $this->_openRead()) {
633 30d5b9c5 Mathieu Schiano
            $v_result = $this->_extractList(
634
                $p_path,
635
                $v_list_detail,
636
                "complete",
637
                0,
638
                $p_remove_path,
639 27e02aed Assos Assos
                $p_preserve,
640
                $p_symlinks
641 30d5b9c5 Mathieu Schiano
            );
642 85ad3d82 Assos Assos
            $this->_close();
643
        }
644
645
        return $v_result;
646
    }
647
648
    /**
649 30d5b9c5 Mathieu Schiano
     * This method extract from the archive one file identified by $p_filename.
650
     * The return value is a string with the file content, or NULL on error.
651
     *
652
     * @param string $p_filename The path of the file to extract in a string.
653
     *
654
     * @return a string with the file content or NULL.
655
     */
656
    public function extractInString($p_filename)
657 85ad3d82 Assos Assos
    {
658
        if ($this->_openRead()) {
659
            $v_result = $this->_extractInString($p_filename);
660
            $this->_close();
661
        } else {
662 30d5b9c5 Mathieu Schiano
            $v_result = null;
663 85ad3d82 Assos Assos
        }
664
665
        return $v_result;
666
    }
667
668
    /**
669 30d5b9c5 Mathieu Schiano
     * This method extract from the archive only the files indicated in the
670
     * $p_filelist. These files are extracted in the current directory or
671
     * in the directory indicated by the optional $p_path parameter.
672
     * If indicated the $p_remove_path can be used in the same way as it is
673
     * used in extractModify() method.
674
     *
675
     * @param array $p_filelist An array of filenames and directory names,
676
     *                               or a single string with names separated
677
     *                               by a single blank space.
678
     * @param string $p_path The path of the directory where the
679
     *                               files/dir need to by extracted.
680
     * @param string $p_remove_path Part of the memorized path that can be
681
     *                               removed if present at the beginning of
682
     *                               the file/dir path.
683
     * @param boolean $p_preserve Preserve user/group ownership of files
684 27e02aed Assos Assos
     * @param boolean $p_symlinks Allow symlinks.
685 30d5b9c5 Mathieu Schiano
     *
686
     * @return true on success, false on error.
687
     * @see    extractModify()
688
     */
689 27e02aed Assos Assos
    public function extractList($p_filelist, $p_path = '', $p_remove_path = '', $p_preserve = false, $p_symlinks = true)
690 85ad3d82 Assos Assos
    {
691
        $v_result = true;
692
        $v_list_detail = array();
693
694 30d5b9c5 Mathieu Schiano
        if (is_array($p_filelist)) {
695 85ad3d82 Assos Assos
            $v_list = $p_filelist;
696 30d5b9c5 Mathieu Schiano
        } elseif (is_string($p_filelist)) {
697 85ad3d82 Assos Assos
            $v_list = explode($this->_separator, $p_filelist);
698 30d5b9c5 Mathieu Schiano
        } else {
699 85ad3d82 Assos Assos
            $this->_error('Invalid string list');
700
            return false;
701
        }
702
703
        if ($v_result = $this->_openRead()) {
704 30d5b9c5 Mathieu Schiano
            $v_result = $this->_extractList(
705
                $p_path,
706
                $v_list_detail,
707
                "partial",
708
                $v_list,
709
                $p_remove_path,
710 27e02aed Assos Assos
                $p_preserve,
711
                $p_symlinks
712 30d5b9c5 Mathieu Schiano
            );
713 85ad3d82 Assos Assos
            $this->_close();
714
        }
715
716
        return $v_result;
717
    }
718
719
    /**
720 30d5b9c5 Mathieu Schiano
     * This method set specific attributes of the archive. It uses a variable
721
     * list of parameters, in the format attribute code + attribute values :
722
     * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
723
     *
724
     * @return true on success, false on error.
725
     */
726
    public function setAttribute()
727 85ad3d82 Assos Assos
    {
728
        $v_result = true;
729
730
        // ----- Get the number of variable list of arguments
731
        if (($v_size = func_num_args()) == 0) {
732
            return true;
733
        }
734
735
        // ----- Get the arguments
736 cd5c298a Geoffroy Desvernay
        $v_att_list = func_get_args();
737 85ad3d82 Assos Assos
738
        // ----- Read the attributes
739 30d5b9c5 Mathieu Schiano
        $i = 0;
740
        while ($i < $v_size) {
741 85ad3d82 Assos Assos
742
            // ----- Look for next option
743
            switch ($v_att_list[$i]) {
744
                // ----- Look for options that request a string value
745
                case ARCHIVE_TAR_ATT_SEPARATOR :
746
                    // ----- Check the number of parameters
747 30d5b9c5 Mathieu Schiano
                    if (($i + 1) >= $v_size) {
748
                        $this->_error(
749
                            'Invalid number of parameters for '
750
                            . 'attribute ARCHIVE_TAR_ATT_SEPARATOR'
751
                        );
752 85ad3d82 Assos Assos
                        return false;
753
                    }
754
755
                    // ----- Get the value
756 30d5b9c5 Mathieu Schiano
                    $this->_separator = $v_att_list[$i + 1];
757 85ad3d82 Assos Assos
                    $i++;
758 30d5b9c5 Mathieu Schiano
                    break;
759 85ad3d82 Assos Assos
760
                default :
761 30d5b9c5 Mathieu Schiano
                    $this->_error('Unknown attribute code ' . $v_att_list[$i] . '');
762 85ad3d82 Assos Assos
                    return false;
763
            }
764
765
            // ----- Next attribute
766
            $i++;
767
        }
768
769
        return $v_result;
770
    }
771
772 30d5b9c5 Mathieu Schiano
    /**
773
     * This method sets the regular expression for ignoring files and directories
774
     * at import, for example:
775
     * $arch->setIgnoreRegexp("#CVS|\.svn#");
776
     *
777
     * @param string $regexp regular expression defining which files or directories to ignore
778
     */
779
    public function setIgnoreRegexp($regexp)
780
    {
781
        $this->_ignore_regexp = $regexp;
782
    }
783
784
    /**
785
     * This method sets the regular expression for ignoring all files and directories
786
     * matching the filenames in the array list at import, for example:
787
     * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool'));
788
     *
789
     * @param array $list a list of file or directory names to ignore
790
     *
791
     * @access public
792
     */
793
    public function setIgnoreList($list)
794
    {
795
        $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list);
796
        $regexp = '#/' . join('$|/', $list) . '#';
797
        $this->setIgnoreRegexp($regexp);
798
    }
799
800
    /**
801
     * @param string $p_message
802
     */
803
    public function _error($p_message)
804 85ad3d82 Assos Assos
    {
805 30d5b9c5 Mathieu Schiano
        // Drupal change $this->error_object = $this->raiseError($p_message).
806 85ad3d82 Assos Assos
        throw new Exception($p_message);
807
    }
808
809 30d5b9c5 Mathieu Schiano
    /**
810
     * @param string $p_message
811
     */
812
    public function _warning($p_message)
813 85ad3d82 Assos Assos
    {
814 30d5b9c5 Mathieu Schiano
        // Drupal change $this->error_object = $this->raiseError($p_message).
815 85ad3d82 Assos Assos
        throw new Exception($p_message);
816
    }
817
818 30d5b9c5 Mathieu Schiano
    /**
819
     * @param string $p_filename
820
     * @return bool
821
     */
822
    public function _isArchive($p_filename = null)
823 85ad3d82 Assos Assos
    {
824 30d5b9c5 Mathieu Schiano
        if ($p_filename == null) {
825 85ad3d82 Assos Assos
            $p_filename = $this->_tarname;
826
        }
827
        clearstatcache();
828
        return @is_file($p_filename) && !@is_link($p_filename);
829
    }
830
831 30d5b9c5 Mathieu Schiano
    /**
832
     * @return bool
833
     */
834
    public function _openWrite()
835 85ad3d82 Assos Assos
    {
836 30d5b9c5 Mathieu Schiano
        if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
837 85ad3d82 Assos Assos
            $this->_file = @gzopen($this->_tarname, "wb9");
838 30d5b9c5 Mathieu Schiano
        } else {
839
            if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
840
                $this->_file = @bzopen($this->_tarname, "w");
841
            } else {
842
                if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
843
                    $this->_file = @xzopen($this->_tarname, 'w');
844
                } else {
845
                    if ($this->_compress_type == 'none') {
846
                        $this->_file = @fopen($this->_tarname, "wb");
847
                    } else {
848
                        $this->_error(
849
                            'Unknown or missing compression type ('
850
                            . $this->_compress_type . ')'
851
                        );
852
                        return false;
853
                    }
854
                }
855
            }
856
        }
857 85ad3d82 Assos Assos
858
        if ($this->_file == 0) {
859 30d5b9c5 Mathieu Schiano
            $this->_error(
860
                'Unable to open in write mode \''
861
                . $this->_tarname . '\''
862
            );
863 85ad3d82 Assos Assos
            return false;
864
        }
865
866
        return true;
867
    }
868
869 30d5b9c5 Mathieu Schiano
    /**
870
     * @return bool
871
     */
872
    public function _openRead()
873 85ad3d82 Assos Assos
    {
874
        if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
875
876 30d5b9c5 Mathieu Schiano
            // ----- Look if a local copy need to be done
877
            if ($this->_temp_tarname == '') {
878
                $this->_temp_tarname = uniqid('tar') . '.tmp';
879
                if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
880
                    $this->_error(
881
                        'Unable to open in read mode \''
882
                        . $this->_tarname . '\''
883
                    );
884
                    $this->_temp_tarname = '';
885
                    return false;
886
                }
887
                if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
888
                    $this->_error(
889
                        'Unable to open in write mode \''
890
                        . $this->_temp_tarname . '\''
891
                    );
892
                    $this->_temp_tarname = '';
893
                    return false;
894
                }
895
                while ($v_data = @fread($v_file_from, 1024)) {
896
                    @fwrite($v_file_to, $v_data);
897
                }
898
                @fclose($v_file_from);
899
                @fclose($v_file_to);
900
            }
901 85ad3d82 Assos Assos
902 30d5b9c5 Mathieu Schiano
            // ----- File to open if the local copy
903
            $v_filename = $this->_temp_tarname;
904
        } else {
905
            // ----- File to open if the normal Tar file
906 85ad3d82 Assos Assos
907 30d5b9c5 Mathieu Schiano
            $v_filename = $this->_tarname;
908
        }
909 85ad3d82 Assos Assos
910 30d5b9c5 Mathieu Schiano
        if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
911 85ad3d82 Assos Assos
            $this->_file = @gzopen($v_filename, "rb");
912 30d5b9c5 Mathieu Schiano
        } else {
913
            if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
914
                $this->_file = @bzopen($v_filename, "r");
915
            } else {
916
                if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
917
                    $this->_file = @xzopen($v_filename, "r");
918
                } else {
919
                    if ($this->_compress_type == 'none') {
920
                        $this->_file = @fopen($v_filename, "rb");
921
                    } else {
922
                        $this->_error(
923
                            'Unknown or missing compression type ('
924
                            . $this->_compress_type . ')'
925
                        );
926
                        return false;
927
                    }
928
                }
929
            }
930
        }
931 85ad3d82 Assos Assos
932
        if ($this->_file == 0) {
933 30d5b9c5 Mathieu Schiano
            $this->_error('Unable to open in read mode \'' . $v_filename . '\'');
934 85ad3d82 Assos Assos
            return false;
935
        }
936
937
        return true;
938
    }
939
940 30d5b9c5 Mathieu Schiano
    /**
941
     * @return bool
942
     */
943
    public function _openReadWrite()
944 85ad3d82 Assos Assos
    {
945 30d5b9c5 Mathieu Schiano
        if ($this->_compress_type == 'gz') {
946 85ad3d82 Assos Assos
            $this->_file = @gzopen($this->_tarname, "r+b");
947 30d5b9c5 Mathieu Schiano
        } else {
948
            if ($this->_compress_type == 'bz2') {
949
                $this->_error(
950
                    'Unable to open bz2 in read/write mode \''
951
                    . $this->_tarname . '\' (limitation of bz2 extension)'
952
                );
953
                return false;
954
            } else {
955
                if ($this->_compress_type == 'lzma2') {
956
                    $this->_error(
957
                        'Unable to open lzma2 in read/write mode \''
958
                        . $this->_tarname . '\' (limitation of lzma2 extension)'
959
                    );
960
                    return false;
961
                } else {
962
                    if ($this->_compress_type == 'none') {
963
                        $this->_file = @fopen($this->_tarname, "r+b");
964
                    } else {
965
                        $this->_error(
966
                            'Unknown or missing compression type ('
967
                            . $this->_compress_type . ')'
968
                        );
969
                        return false;
970
                    }
971
                }
972
            }
973
        }
974 85ad3d82 Assos Assos
975
        if ($this->_file == 0) {
976 30d5b9c5 Mathieu Schiano
            $this->_error(
977
                'Unable to open in read/write mode \''
978
                . $this->_tarname . '\''
979
            );
980 85ad3d82 Assos Assos
            return false;
981
        }
982
983
        return true;
984
    }
985
986 30d5b9c5 Mathieu Schiano
    /**
987
     * @return bool
988
     */
989
    public function _close()
990 85ad3d82 Assos Assos
    {
991
        //if (isset($this->_file)) {
992
        if (is_resource($this->_file)) {
993 30d5b9c5 Mathieu Schiano
            if ($this->_compress_type == 'gz') {
994 85ad3d82 Assos Assos
                @gzclose($this->_file);
995 30d5b9c5 Mathieu Schiano
            } else {
996
                if ($this->_compress_type == 'bz2') {
997
                    @bzclose($this->_file);
998
                } else {
999
                    if ($this->_compress_type == 'lzma2') {
1000
                        @xzclose($this->_file);
1001
                    } else {
1002
                        if ($this->_compress_type == 'none') {
1003
                            @fclose($this->_file);
1004
                        } else {
1005
                            $this->_error(
1006
                                'Unknown or missing compression type ('
1007
                                . $this->_compress_type . ')'
1008
                            );
1009
                        }
1010
                    }
1011
                }
1012
            }
1013 85ad3d82 Assos Assos
1014
            $this->_file = 0;
1015
        }
1016
1017
        // ----- Look if a local copy need to be erase
1018
        // Note that it might be interesting to keep the url for a time : ToDo
1019
        if ($this->_temp_tarname != '') {
1020
            @drupal_unlink($this->_temp_tarname);
1021
            $this->_temp_tarname = '';
1022
        }
1023
1024
        return true;
1025
    }
1026
1027 30d5b9c5 Mathieu Schiano
    /**
1028
     * @return bool
1029
     */
1030
    public function _cleanFile()
1031 85ad3d82 Assos Assos
    {
1032
        $this->_close();
1033
1034
        // ----- Look for a local copy
1035
        if ($this->_temp_tarname != '') {
1036
            // ----- Remove the local copy but not the remote tarname
1037
            @drupal_unlink($this->_temp_tarname);
1038
            $this->_temp_tarname = '';
1039
        } else {
1040
            // ----- Remove the local tarname file
1041
            @drupal_unlink($this->_tarname);
1042
        }
1043
        $this->_tarname = '';
1044
1045
        return true;
1046
    }
1047
1048 30d5b9c5 Mathieu Schiano
    /**
1049
     * @param mixed $p_binary_data
1050
     * @param integer $p_len
1051
     * @return bool
1052
     */
1053
    public function _writeBlock($p_binary_data, $p_len = null)
1054 85ad3d82 Assos Assos
    {
1055 30d5b9c5 Mathieu Schiano
        if (is_resource($this->_file)) {
1056
            if ($p_len === null) {
1057
                if ($this->_compress_type == 'gz') {
1058
                    @gzputs($this->_file, $p_binary_data);
1059
                } else {
1060
                    if ($this->_compress_type == 'bz2') {
1061
                        @bzwrite($this->_file, $p_binary_data);
1062
                    } else {
1063
                        if ($this->_compress_type == 'lzma2') {
1064
                            @xzwrite($this->_file, $p_binary_data);
1065
                        } else {
1066
                            if ($this->_compress_type == 'none') {
1067
                                @fputs($this->_file, $p_binary_data);
1068
                            } else {
1069
                                $this->_error(
1070
                                    'Unknown or missing compression type ('
1071
                                    . $this->_compress_type . ')'
1072
                                );
1073
                            }
1074
                        }
1075
                    }
1076
                }
1077
            } else {
1078
                if ($this->_compress_type == 'gz') {
1079
                    @gzputs($this->_file, $p_binary_data, $p_len);
1080
                } else {
1081
                    if ($this->_compress_type == 'bz2') {
1082
                        @bzwrite($this->_file, $p_binary_data, $p_len);
1083
                    } else {
1084
                        if ($this->_compress_type == 'lzma2') {
1085
                            @xzwrite($this->_file, $p_binary_data, $p_len);
1086
                        } else {
1087
                            if ($this->_compress_type == 'none') {
1088
                                @fputs($this->_file, $p_binary_data, $p_len);
1089
                            } else {
1090
                                $this->_error(
1091
                                    'Unknown or missing compression type ('
1092
                                    . $this->_compress_type . ')'
1093
                                );
1094
                            }
1095
                        }
1096
                    }
1097
                }
1098
            }
1099
        }
1100
        return true;
1101 85ad3d82 Assos Assos
    }
1102
1103 30d5b9c5 Mathieu Schiano
    /**
1104
     * @return null|string
1105
     */
1106
    public function _readBlock()
1107 85ad3d82 Assos Assos
    {
1108 30d5b9c5 Mathieu Schiano
        $v_block = null;
1109
        if (is_resource($this->_file)) {
1110
            if ($this->_compress_type == 'gz') {
1111
                $v_block = @gzread($this->_file, 512);
1112
            } else {
1113
                if ($this->_compress_type == 'bz2') {
1114
                    $v_block = @bzread($this->_file, 512);
1115
                } else {
1116
                    if ($this->_compress_type == 'lzma2') {
1117
                        $v_block = @xzread($this->_file, 512);
1118
                    } else {
1119
                        if ($this->_compress_type == 'none') {
1120
                            $v_block = @fread($this->_file, 512);
1121
                        } else {
1122
                            $this->_error(
1123
                                'Unknown or missing compression type ('
1124
                                . $this->_compress_type . ')'
1125
                            );
1126
                        }
1127
                    }
1128
                }
1129
            }
1130
        }
1131
        return $v_block;
1132 85ad3d82 Assos Assos
    }
1133
1134 30d5b9c5 Mathieu Schiano
    /**
1135
     * @param null $p_len
1136
     * @return bool
1137
     */
1138
    public function _jumpBlock($p_len = null)
1139
    {
1140
        if (is_resource($this->_file)) {
1141
            if ($p_len === null) {
1142
                $p_len = 1;
1143
            }
1144
1145
            if ($this->_compress_type == 'gz') {
1146
                @gzseek($this->_file, gztell($this->_file) + ($p_len * 512));
1147
            } else {
1148
                if ($this->_compress_type == 'bz2') {
1149
                    // ----- Replace missing bztell() and bzseek()
1150
                    for ($i = 0; $i < $p_len; $i++) {
1151
                        $this->_readBlock();
1152
                    }
1153
                } else {
1154
                    if ($this->_compress_type == 'lzma2') {
1155
                        // ----- Replace missing xztell() and xzseek()
1156
                        for ($i = 0; $i < $p_len; $i++) {
1157
                            $this->_readBlock();
1158
                        }
1159
                    } else {
1160
                        if ($this->_compress_type == 'none') {
1161
                            @fseek($this->_file, $p_len * 512, SEEK_CUR);
1162
                        } else {
1163
                            $this->_error(
1164
                                'Unknown or missing compression type ('
1165
                                . $this->_compress_type . ')'
1166
                            );
1167
                        }
1168
                    }
1169
                }
1170
            }
1171
        }
1172
        return true;
1173
    }
1174
1175
    /**
1176
     * @return bool
1177
     */
1178
    public function _writeFooter()
1179
    {
1180
        if (is_resource($this->_file)) {
1181
            // ----- Write the last 0 filled block for end of archive
1182
            $v_binary_data = pack('a1024', '');
1183
            $this->_writeBlock($v_binary_data);
1184
        }
1185
        return true;
1186
    }
1187
1188
    /**
1189
     * @param array $p_list
1190
     * @param string $p_add_dir
1191
     * @param string $p_remove_dir
1192
     * @return bool
1193
     */
1194
    public function _addList($p_list, $p_add_dir, $p_remove_dir)
1195
    {
1196
        $v_result = true;
1197
        $v_header = array();
1198
1199
        // ----- Remove potential windows directory separator
1200
        $p_add_dir = $this->_translateWinPath($p_add_dir);
1201
        $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
1202
1203
        if (!$this->_file) {
1204
            $this->_error('Invalid file descriptor');
1205
            return false;
1206
        }
1207
1208
        if (sizeof($p_list) == 0) {
1209
            return true;
1210
        }
1211
1212
        foreach ($p_list as $v_filename) {
1213
            if (!$v_result) {
1214
                break;
1215
            }
1216
1217
            // ----- Skip the current tar name
1218
            if ($v_filename == $this->_tarname) {
1219
                continue;
1220
            }
1221
1222
            if ($v_filename == '') {
1223
                continue;
1224
            }
1225
1226
            // ----- ignore files and directories matching the ignore regular expression
1227
            if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/' . $v_filename)) {
1228
                $this->_warning("File '$v_filename' ignored");
1229
                continue;
1230
            }
1231
1232
            if (!file_exists($v_filename) && !is_link($v_filename)) {
1233
                $this->_warning("File '$v_filename' does not exist");
1234
                continue;
1235
            }
1236
1237
            // ----- Add the file or directory header
1238
            if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) {
1239
                return false;
1240
            }
1241
1242
            if (@is_dir($v_filename) && !@is_link($v_filename)) {
1243
                if (!($p_hdir = opendir($v_filename))) {
1244
                    $this->_warning("Directory '$v_filename' can not be read");
1245
                    continue;
1246
                }
1247
                while (false !== ($p_hitem = readdir($p_hdir))) {
1248
                    if (($p_hitem != '.') && ($p_hitem != '..')) {
1249
                        if ($v_filename != ".") {
1250
                            $p_temp_list[0] = $v_filename . '/' . $p_hitem;
1251
                        } else {
1252
                            $p_temp_list[0] = $p_hitem;
1253
                        }
1254
1255
                        $v_result = $this->_addList(
1256
                            $p_temp_list,
1257
                            $p_add_dir,
1258
                            $p_remove_dir
1259
                        );
1260
                    }
1261
                }
1262
1263
                unset($p_temp_list);
1264
                unset($p_hdir);
1265
                unset($p_hitem);
1266
            }
1267
        }
1268 85ad3d82 Assos Assos
1269 30d5b9c5 Mathieu Schiano
        return $v_result;
1270 85ad3d82 Assos Assos
    }
1271
1272 30d5b9c5 Mathieu Schiano
    /**
1273
     * @param string $p_filename
1274
     * @param mixed $p_header
1275
     * @param string $p_add_dir
1276
     * @param string $p_remove_dir
1277
     * @param null $v_stored_filename
1278
     * @return bool
1279
     */
1280
    public function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $v_stored_filename = null)
1281 85ad3d82 Assos Assos
    {
1282 30d5b9c5 Mathieu Schiano
        if (!$this->_file) {
1283
            $this->_error('Invalid file descriptor');
1284
            return false;
1285
        }
1286 85ad3d82 Assos Assos
1287 30d5b9c5 Mathieu Schiano
        if ($p_filename == '') {
1288
            $this->_error('Invalid file name');
1289
            return false;
1290
        }
1291 85ad3d82 Assos Assos
1292 30d5b9c5 Mathieu Schiano
        if (is_null($v_stored_filename)) {
1293
            // ----- Calculate the stored filename
1294
            $p_filename = $this->_translateWinPath($p_filename, false);
1295
            $v_stored_filename = $p_filename;
1296 85ad3d82 Assos Assos
1297 30d5b9c5 Mathieu Schiano
            if (strcmp($p_filename, $p_remove_dir) == 0) {
1298
                return true;
1299
            }
1300 85ad3d82 Assos Assos
1301 30d5b9c5 Mathieu Schiano
            if ($p_remove_dir != '') {
1302
                if (substr($p_remove_dir, -1) != '/') {
1303
                    $p_remove_dir .= '/';
1304
                }
1305 85ad3d82 Assos Assos
1306 30d5b9c5 Mathieu Schiano
                if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) {
1307
                    $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
1308
                }
1309
            }
1310 85ad3d82 Assos Assos
1311 30d5b9c5 Mathieu Schiano
            $v_stored_filename = $this->_translateWinPath($v_stored_filename);
1312
            if ($p_add_dir != '') {
1313
                if (substr($p_add_dir, -1) == '/') {
1314
                    $v_stored_filename = $p_add_dir . $v_stored_filename;
1315
                } else {
1316
                    $v_stored_filename = $p_add_dir . '/' . $v_stored_filename;
1317
                }
1318
            }
1319 85ad3d82 Assos Assos
1320 30d5b9c5 Mathieu Schiano
            $v_stored_filename = $this->_pathReduction($v_stored_filename);
1321 85ad3d82 Assos Assos
        }
1322
1323 30d5b9c5 Mathieu Schiano
        if ($this->_isArchive($p_filename)) {
1324
            if (($v_file = @fopen($p_filename, "rb")) == 0) {
1325
                $this->_warning(
1326
                    "Unable to open file '" . $p_filename
1327
                    . "' in binary read mode"
1328
                );
1329
                return true;
1330
            }
1331 85ad3d82 Assos Assos
1332 30d5b9c5 Mathieu Schiano
            if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
1333
                return false;
1334 85ad3d82 Assos Assos
            }
1335 30d5b9c5 Mathieu Schiano
1336 27e02aed Assos Assos
            while (($v_buffer = fread($v_file, $this->buffer_length)) != '') {
1337
                $buffer_length = strlen("$v_buffer");
1338
                if ($buffer_length != $this->buffer_length) {
1339
                    $pack_size = ((int)($buffer_length / 512) + 1) * 512;
1340
                    $pack_format = sprintf('a%d', $pack_size);
1341
                } else {
1342
                    $pack_format = sprintf('a%d', $this->buffer_length);
1343
                }
1344
                $v_binary_data = pack($pack_format, "$v_buffer");
1345 30d5b9c5 Mathieu Schiano
                $this->_writeBlock($v_binary_data);
1346 85ad3d82 Assos Assos
            }
1347
1348 30d5b9c5 Mathieu Schiano
            fclose($v_file);
1349
        } else {
1350
            // ----- Only header for dir
1351
            if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
1352
                return false;
1353
            }
1354 85ad3d82 Assos Assos
        }
1355
1356 30d5b9c5 Mathieu Schiano
        return true;
1357 85ad3d82 Assos Assos
    }
1358
1359 30d5b9c5 Mathieu Schiano
    /**
1360
     * @param string $p_filename
1361
     * @param string $p_string
1362
     * @param bool $p_datetime
1363
     * @param array $p_params
1364
     * @return bool
1365
     */
1366
    public function _addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
1367 85ad3d82 Assos Assos
    {
1368 30d5b9c5 Mathieu Schiano
        $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
1369
        $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
1370
        $p_type = @$p_params["type"] ? $p_params["type"] : "";
1371
        $p_uid = @$p_params["uid"] ? $p_params["uid"] : 0;
1372
        $p_gid = @$p_params["gid"] ? $p_params["gid"] : 0;
1373
        if (!$this->_file) {
1374
            $this->_error('Invalid file descriptor');
1375
            return false;
1376
        }
1377 85ad3d82 Assos Assos
1378 30d5b9c5 Mathieu Schiano
        if ($p_filename == '') {
1379
            $this->_error('Invalid file name');
1380
            return false;
1381
        }
1382
1383
        // ----- Calculate the stored filename
1384
        $p_filename = $this->_translateWinPath($p_filename, false);
1385
1386
        // ----- If datetime is not specified, set current time
1387
        if ($p_datetime === false) {
1388
            $p_datetime = time();
1389
        }
1390
1391
        if (!$this->_writeHeaderBlock(
1392
            $p_filename,
1393
            strlen($p_string),
1394
            $p_stamp,
1395
            $p_mode,
1396
            $p_type,
1397
            $p_uid,
1398
            $p_gid
1399
        )
1400
        ) {
1401
            return false;
1402
        }
1403
1404
        $i = 0;
1405
        while (($v_buffer = substr($p_string, (($i++) * 512), 512)) != '') {
1406
            $v_binary_data = pack("a512", $v_buffer);
1407
            $this->_writeBlock($v_binary_data);
1408
        }
1409
1410
        return true;
1411 85ad3d82 Assos Assos
    }
1412
1413 30d5b9c5 Mathieu Schiano
    /**
1414
     * @param string $p_filename
1415
     * @param string $p_stored_filename
1416
     * @return bool
1417
     */
1418
    public function _writeHeader($p_filename, $p_stored_filename)
1419 85ad3d82 Assos Assos
    {
1420 30d5b9c5 Mathieu Schiano
        if ($p_stored_filename == '') {
1421 85ad3d82 Assos Assos
            $p_stored_filename = $p_filename;
1422 30d5b9c5 Mathieu Schiano
        }
1423 85ad3d82 Assos Assos
1424 cd5c298a Geoffroy Desvernay
        $v_reduced_filename = $this->_pathReduction($p_stored_filename);
1425
1426
        if (strlen($v_reduced_filename) > 99) {
1427
            if (!$this->_writeLongHeader($v_reduced_filename, false)) {
1428
                return false;
1429
            }
1430
        }
1431
1432
        $v_linkname = '';
1433
        if (@is_link($p_filename)) {
1434
            $v_linkname = readlink($p_filename);
1435
        }
1436
1437
        if (strlen($v_linkname) > 99) {
1438
            if (!$this->_writeLongHeader($v_linkname, true)) {
1439 30d5b9c5 Mathieu Schiano
                return false;
1440
            }
1441 85ad3d82 Assos Assos
        }
1442
1443
        $v_info = lstat($p_filename);
1444 30d5b9c5 Mathieu Schiano
        $v_uid = sprintf("%07s", DecOct($v_info[4]));
1445
        $v_gid = sprintf("%07s", DecOct($v_info[5]));
1446
        $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
1447
        $v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
1448 85ad3d82 Assos Assos
1449
        if (@is_link($p_filename)) {
1450 30d5b9c5 Mathieu Schiano
            $v_typeflag = '2';
1451
            $v_size = sprintf("%011s", DecOct(0));
1452 85ad3d82 Assos Assos
        } elseif (@is_dir($p_filename)) {
1453 30d5b9c5 Mathieu Schiano
            $v_typeflag = "5";
1454
            $v_size = sprintf("%011s", DecOct(0));
1455 85ad3d82 Assos Assos
        } else {
1456 30d5b9c5 Mathieu Schiano
            $v_typeflag = '0';
1457
            clearstatcache();
1458
            $v_size = sprintf("%011s", DecOct($v_info['size']));
1459 85ad3d82 Assos Assos
        }
1460
1461 30d5b9c5 Mathieu Schiano
        $v_magic = 'ustar ';
1462
        $v_version = ' ';
1463 85ad3d82 Assos Assos
1464 30d5b9c5 Mathieu Schiano
        if (function_exists('posix_getpwuid')) {
1465
            $userinfo = posix_getpwuid($v_info[4]);
1466
            $groupinfo = posix_getgrgid($v_info[5]);
1467 85ad3d82 Assos Assos
1468 30d5b9c5 Mathieu Schiano
            $v_uname = $userinfo['name'];
1469
            $v_gname = $groupinfo['name'];
1470
        } else {
1471
            $v_uname = '';
1472
            $v_gname = '';
1473
        }
1474 85ad3d82 Assos Assos
1475
        $v_devmajor = '';
1476
        $v_devminor = '';
1477
        $v_prefix = '';
1478
1479 30d5b9c5 Mathieu Schiano
        $v_binary_data_first = pack(
1480
            "a100a8a8a8a12a12",
1481 cd5c298a Geoffroy Desvernay
            $v_reduced_filename,
1482 30d5b9c5 Mathieu Schiano
            $v_perms,
1483
            $v_uid,
1484
            $v_gid,
1485
            $v_size,
1486
            $v_mtime
1487
        );
1488
        $v_binary_data_last = pack(
1489
            "a1a100a6a2a32a32a8a8a155a12",
1490
            $v_typeflag,
1491
            $v_linkname,
1492
            $v_magic,
1493
            $v_version,
1494
            $v_uname,
1495
            $v_gname,
1496
            $v_devmajor,
1497
            $v_devminor,
1498
            $v_prefix,
1499
            ''
1500
        );
1501 85ad3d82 Assos Assos
1502
        // ----- Calculate the checksum
1503
        $v_checksum = 0;
1504
        // ..... First part of the header
1505 30d5b9c5 Mathieu Schiano
        for ($i = 0; $i < 148; $i++) {
1506
            $v_checksum += ord(substr($v_binary_data_first, $i, 1));
1507
        }
1508 85ad3d82 Assos Assos
        // ..... Ignore the checksum value and replace it by ' ' (space)
1509 30d5b9c5 Mathieu Schiano
        for ($i = 148; $i < 156; $i++) {
1510 85ad3d82 Assos Assos
            $v_checksum += ord(' ');
1511 30d5b9c5 Mathieu Schiano
        }
1512 85ad3d82 Assos Assos
        // ..... Last part of the header
1513 30d5b9c5 Mathieu Schiano
        for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
1514
            $v_checksum += ord(substr($v_binary_data_last, $j, 1));
1515
        }
1516 85ad3d82 Assos Assos
1517
        // ----- Write the first 148 bytes of the header in the archive
1518
        $this->_writeBlock($v_binary_data_first, 148);
1519
1520
        // ----- Write the calculated checksum
1521 cd5c298a Geoffroy Desvernay
        $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
1522 85ad3d82 Assos Assos
        $v_binary_data = pack("a8", $v_checksum);
1523
        $this->_writeBlock($v_binary_data, 8);
1524
1525
        // ----- Write the last 356 bytes of the header in the archive
1526
        $this->_writeBlock($v_binary_data_last, 356);
1527
1528
        return true;
1529
    }
1530
1531 30d5b9c5 Mathieu Schiano
    /**
1532
     * @param string $p_filename
1533
     * @param int $p_size
1534
     * @param int $p_mtime
1535
     * @param int $p_perms
1536
     * @param string $p_type
1537
     * @param int $p_uid
1538
     * @param int $p_gid
1539
     * @return bool
1540
     */
1541
    public function _writeHeaderBlock(
1542
        $p_filename,
1543
        $p_size,
1544
        $p_mtime = 0,
1545
        $p_perms = 0,
1546
        $p_type = '',
1547
        $p_uid = 0,
1548
        $p_gid = 0
1549 27e02aed Assos Assos
    )
1550
    {
1551 85ad3d82 Assos Assos
        $p_filename = $this->_pathReduction($p_filename);
1552
1553
        if (strlen($p_filename) > 99) {
1554 cd5c298a Geoffroy Desvernay
            if (!$this->_writeLongHeader($p_filename, false)) {
1555 30d5b9c5 Mathieu Schiano
                return false;
1556
            }
1557 85ad3d82 Assos Assos
        }
1558
1559
        if ($p_type == "5") {
1560 30d5b9c5 Mathieu Schiano
            $v_size = sprintf("%011s", DecOct(0));
1561 85ad3d82 Assos Assos
        } else {
1562 30d5b9c5 Mathieu Schiano
            $v_size = sprintf("%011s", DecOct($p_size));
1563 85ad3d82 Assos Assos
        }
1564
1565 30d5b9c5 Mathieu Schiano
        $v_uid = sprintf("%07s", DecOct($p_uid));
1566
        $v_gid = sprintf("%07s", DecOct($p_gid));
1567
        $v_perms = sprintf("%07s", DecOct($p_perms & 000777));
1568 85ad3d82 Assos Assos
1569
        $v_mtime = sprintf("%11s", DecOct($p_mtime));
1570
1571
        $v_linkname = '';
1572
1573 30d5b9c5 Mathieu Schiano
        $v_magic = 'ustar ';
1574 85ad3d82 Assos Assos
1575 30d5b9c5 Mathieu Schiano
        $v_version = ' ';
1576 85ad3d82 Assos Assos
1577 30d5b9c5 Mathieu Schiano
        if (function_exists('posix_getpwuid')) {
1578
            $userinfo = posix_getpwuid($p_uid);
1579
            $groupinfo = posix_getgrgid($p_gid);
1580 85ad3d82 Assos Assos
1581 30d5b9c5 Mathieu Schiano
            $v_uname = $userinfo['name'];
1582
            $v_gname = $groupinfo['name'];
1583
        } else {
1584
            $v_uname = '';
1585
            $v_gname = '';
1586
        }
1587 85ad3d82 Assos Assos
1588
        $v_devmajor = '';
1589
1590
        $v_devminor = '';
1591
1592
        $v_prefix = '';
1593
1594 30d5b9c5 Mathieu Schiano
        $v_binary_data_first = pack(
1595
            "a100a8a8a8a12A12",
1596
            $p_filename,
1597
            $v_perms,
1598
            $v_uid,
1599
            $v_gid,
1600
            $v_size,
1601
            $v_mtime
1602
        );
1603
        $v_binary_data_last = pack(
1604
            "a1a100a6a2a32a32a8a8a155a12",
1605
            $p_type,
1606
            $v_linkname,
1607
            $v_magic,
1608
            $v_version,
1609
            $v_uname,
1610
            $v_gname,
1611
            $v_devmajor,
1612
            $v_devminor,
1613
            $v_prefix,
1614
            ''
1615
        );
1616 85ad3d82 Assos Assos
1617
        // ----- Calculate the checksum
1618
        $v_checksum = 0;
1619
        // ..... First part of the header
1620 30d5b9c5 Mathieu Schiano
        for ($i = 0; $i < 148; $i++) {
1621
            $v_checksum += ord(substr($v_binary_data_first, $i, 1));
1622
        }
1623 85ad3d82 Assos Assos
        // ..... Ignore the checksum value and replace it by ' ' (space)
1624 30d5b9c5 Mathieu Schiano
        for ($i = 148; $i < 156; $i++) {
1625 85ad3d82 Assos Assos
            $v_checksum += ord(' ');
1626 30d5b9c5 Mathieu Schiano
        }
1627 85ad3d82 Assos Assos
        // ..... Last part of the header
1628 30d5b9c5 Mathieu Schiano
        for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
1629
            $v_checksum += ord(substr($v_binary_data_last, $j, 1));
1630
        }
1631 85ad3d82 Assos Assos
1632
        // ----- Write the first 148 bytes of the header in the archive
1633
        $this->_writeBlock($v_binary_data_first, 148);
1634
1635
        // ----- Write the calculated checksum
1636 30d5b9c5 Mathieu Schiano
        $v_checksum = sprintf("%06s ", DecOct($v_checksum));
1637 85ad3d82 Assos Assos
        $v_binary_data = pack("a8", $v_checksum);
1638
        $this->_writeBlock($v_binary_data, 8);
1639
1640
        // ----- Write the last 356 bytes of the header in the archive
1641
        $this->_writeBlock($v_binary_data_last, 356);
1642
1643
        return true;
1644
    }
1645
1646 30d5b9c5 Mathieu Schiano
    /**
1647
     * @param string $p_filename
1648
     * @return bool
1649
     */
1650 cd5c298a Geoffroy Desvernay
    public function _writeLongHeader($p_filename, $is_link = false)
1651 85ad3d82 Assos Assos
    {
1652 cd5c298a Geoffroy Desvernay
        $v_uid = sprintf("%07s", 0);
1653
        $v_gid = sprintf("%07s", 0);
1654
        $v_perms = sprintf("%07s", 0);
1655
        $v_size = sprintf("%'011s", DecOct(strlen($p_filename)));
1656
        $v_mtime = sprintf("%011s", 0);
1657
        $v_typeflag = ($is_link ? 'K' : 'L');
1658 85ad3d82 Assos Assos
        $v_linkname = '';
1659 cd5c298a Geoffroy Desvernay
        $v_magic = 'ustar ';
1660
        $v_version = ' ';
1661 85ad3d82 Assos Assos
        $v_uname = '';
1662
        $v_gname = '';
1663
        $v_devmajor = '';
1664
        $v_devminor = '';
1665
        $v_prefix = '';
1666
1667 30d5b9c5 Mathieu Schiano
        $v_binary_data_first = pack(
1668
            "a100a8a8a8a12a12",
1669
            '././@LongLink',
1670 cd5c298a Geoffroy Desvernay
            $v_perms,
1671
            $v_uid,
1672
            $v_gid,
1673 30d5b9c5 Mathieu Schiano
            $v_size,
1674 cd5c298a Geoffroy Desvernay
            $v_mtime
1675 30d5b9c5 Mathieu Schiano
        );
1676
        $v_binary_data_last = pack(
1677
            "a1a100a6a2a32a32a8a8a155a12",
1678
            $v_typeflag,
1679
            $v_linkname,
1680
            $v_magic,
1681
            $v_version,
1682
            $v_uname,
1683
            $v_gname,
1684
            $v_devmajor,
1685
            $v_devminor,
1686
            $v_prefix,
1687
            ''
1688
        );
1689 85ad3d82 Assos Assos
1690
        // ----- Calculate the checksum
1691
        $v_checksum = 0;
1692
        // ..... First part of the header
1693 30d5b9c5 Mathieu Schiano
        for ($i = 0; $i < 148; $i++) {
1694
            $v_checksum += ord(substr($v_binary_data_first, $i, 1));
1695
        }
1696 85ad3d82 Assos Assos
        // ..... Ignore the checksum value and replace it by ' ' (space)
1697 30d5b9c5 Mathieu Schiano
        for ($i = 148; $i < 156; $i++) {
1698 85ad3d82 Assos Assos
            $v_checksum += ord(' ');
1699 30d5b9c5 Mathieu Schiano
        }
1700 85ad3d82 Assos Assos
        // ..... Last part of the header
1701 30d5b9c5 Mathieu Schiano
        for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
1702
            $v_checksum += ord(substr($v_binary_data_last, $j, 1));
1703
        }
1704 85ad3d82 Assos Assos
1705
        // ----- Write the first 148 bytes of the header in the archive
1706
        $this->_writeBlock($v_binary_data_first, 148);
1707
1708
        // ----- Write the calculated checksum
1709 cd5c298a Geoffroy Desvernay
        $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
1710 85ad3d82 Assos Assos
        $v_binary_data = pack("a8", $v_checksum);
1711
        $this->_writeBlock($v_binary_data, 8);
1712
1713
        // ----- Write the last 356 bytes of the header in the archive
1714
        $this->_writeBlock($v_binary_data_last, 356);
1715
1716
        // ----- Write the filename as content of the block
1717 30d5b9c5 Mathieu Schiano
        $i = 0;
1718
        while (($v_buffer = substr($p_filename, (($i++) * 512), 512)) != '') {
1719 85ad3d82 Assos Assos
            $v_binary_data = pack("a512", "$v_buffer");
1720
            $this->_writeBlock($v_binary_data);
1721
        }
1722
1723
        return true;
1724
    }
1725
1726 30d5b9c5 Mathieu Schiano
    /**
1727
     * @param mixed $v_binary_data
1728
     * @param mixed $v_header
1729
     * @return bool
1730
     */
1731
    public function _readHeader($v_binary_data, &$v_header)
1732 85ad3d82 Assos Assos
    {
1733 30d5b9c5 Mathieu Schiano
        if (strlen($v_binary_data) == 0) {
1734 85ad3d82 Assos Assos
            $v_header['filename'] = '';
1735
            return true;
1736
        }
1737
1738
        if (strlen($v_binary_data) != 512) {
1739
            $v_header['filename'] = '';
1740 30d5b9c5 Mathieu Schiano
            $this->_error('Invalid block size : ' . strlen($v_binary_data));
1741 85ad3d82 Assos Assos
            return false;
1742
        }
1743
1744
        if (!is_array($v_header)) {
1745
            $v_header = array();
1746
        }
1747
        // ----- Calculate the checksum
1748
        $v_checksum = 0;
1749
        // ..... First part of the header
1750 cd5c298a Geoffroy Desvernay
        $v_binary_split = str_split($v_binary_data);
1751
        $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 0, 148)));
1752
        $v_checksum += array_sum(array_map('ord', array(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',)));
1753
        $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 156, 512)));
1754 85ad3d82 Assos Assos
1755 cd5c298a Geoffroy Desvernay
1756
        $v_data = unpack($this->_fmt, $v_binary_data);
1757 30d5b9c5 Mathieu Schiano
1758
        if (strlen($v_data["prefix"]) > 0) {
1759
            $v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
1760
        }
1761 85ad3d82 Assos Assos
1762
        // ----- Extract the checksum
1763 27e02aed Assos Assos
        $v_data_checksum = trim($v_data['checksum']);
1764
        if (!preg_match('/^[0-7]*$/', $v_data_checksum)) {
1765
            $this->_error(
1766
                'Invalid checksum for file "' . $v_data['filename']
1767
                . '" : ' . $v_data_checksum . ' extracted'
1768
            );
1769
            return false;
1770
        }
1771
1772
        $v_header['checksum'] = OctDec($v_data_checksum);
1773 85ad3d82 Assos Assos
        if ($v_header['checksum'] != $v_checksum) {
1774
            $v_header['filename'] = '';
1775
1776
            // ----- Look for last block (empty block)
1777 30d5b9c5 Mathieu Schiano
            if (($v_checksum == 256) && ($v_header['checksum'] == 0)) {
1778 85ad3d82 Assos Assos
                return true;
1779 30d5b9c5 Mathieu Schiano
            }
1780 85ad3d82 Assos Assos
1781 30d5b9c5 Mathieu Schiano
            $this->_error(
1782
                'Invalid checksum for file "' . $v_data['filename']
1783
                . '" : ' . $v_checksum . ' calculated, '
1784
                . $v_header['checksum'] . ' expected'
1785
            );
1786 85ad3d82 Assos Assos
            return false;
1787
        }
1788
1789
        // ----- Extract the properties
1790 30d5b9c5 Mathieu Schiano
        $v_header['filename'] = rtrim($v_data['filename'], "\0");
1791 01dfd3b5 Assos Assos
        if ($this->_isMaliciousFilename($v_header['filename'])) {
1792 30d5b9c5 Mathieu Schiano
            $this->_error(
1793
                'Malicious .tar detected, file "' . $v_header['filename'] .
1794
                '" will not install in desired directory tree'
1795
            );
1796 85ad3d82 Assos Assos
            return false;
1797
        }
1798
        $v_header['mode'] = OctDec(trim($v_data['mode']));
1799
        $v_header['uid'] = OctDec(trim($v_data['uid']));
1800
        $v_header['gid'] = OctDec(trim($v_data['gid']));
1801 cd5c298a Geoffroy Desvernay
        $v_header['size'] = $this->_tarRecToSize($v_data['size']);
1802 85ad3d82 Assos Assos
        $v_header['mtime'] = OctDec(trim($v_data['mtime']));
1803
        if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
1804 30d5b9c5 Mathieu Schiano
            $v_header['size'] = 0;
1805 85ad3d82 Assos Assos
        }
1806
        $v_header['link'] = trim($v_data['link']);
1807
        /* ----- All these fields are removed form the header because
1808 30d5b9c5 Mathieu Schiano
        they do not carry interesting info
1809 85ad3d82 Assos Assos
        $v_header[magic] = trim($v_data[magic]);
1810
        $v_header[version] = trim($v_data[version]);
1811
        $v_header[uname] = trim($v_data[uname]);
1812
        $v_header[gname] = trim($v_data[gname]);
1813
        $v_header[devmajor] = trim($v_data[devmajor]);
1814
        $v_header[devminor] = trim($v_data[devminor]);
1815
        */
1816
1817
        return true;
1818
    }
1819
1820 cd5c298a Geoffroy Desvernay
    /**
1821
     * Convert Tar record size to actual size
1822
     *
1823
     * @param string $tar_size
1824
     * @return size of tar record in bytes
1825
     */
1826
    private function _tarRecToSize($tar_size)
1827
    {
1828
        /*
1829
         * First byte of size has a special meaning if bit 7 is set.
1830
         *
1831
         * Bit 7 indicates base-256 encoding if set.
1832
         * Bit 6 is the sign bit.
1833
         * Bits 5:0 are most significant value bits.
1834
         */
1835
        $ch = ord($tar_size[0]);
1836
        if ($ch & 0x80) {
1837
            // Full 12-bytes record is required.
1838
            $rec_str = $tar_size . "\x00";
1839
1840
            $size = ($ch & 0x40) ? -1 : 0;
1841
            $size = ($size << 6) | ($ch & 0x3f);
1842
1843
            for ($num_ch = 1; $num_ch < 12; ++$num_ch) {
1844
                $size = ($size * 256) + ord($rec_str[$num_ch]);
1845
            }
1846
1847
            return $size;
1848
1849
        } else {
1850
            return OctDec(trim($tar_size));
1851
        }
1852
    }
1853
1854 85ad3d82 Assos Assos
    /**
1855
     * Detect and report a malicious file name
1856
     *
1857
     * @param string $file
1858 30d5b9c5 Mathieu Schiano
     *
1859 85ad3d82 Assos Assos
     * @return bool
1860
     */
1861 01dfd3b5 Assos Assos
    private function _isMaliciousFilename($file)
1862 85ad3d82 Assos Assos
    {
1863 01dfd3b5 Assos Assos
        if (strpos($file, '://') !== false) {
1864 85ad3d82 Assos Assos
            return true;
1865
        }
1866 27e02aed Assos Assos
        if (strpos($file, '../') !== false || strpos($file, '..\\') !== false) {
1867 85ad3d82 Assos Assos
            return true;
1868
        }
1869
        return false;
1870
    }
1871
1872 30d5b9c5 Mathieu Schiano
    /**
1873
     * @param $v_header
1874
     * @return bool
1875
     */
1876
    public function _readLongHeader(&$v_header)
1877 85ad3d82 Assos Assos
    {
1878 30d5b9c5 Mathieu Schiano
        $v_filename = '';
1879
        $v_filesize = $v_header['size'];
1880
        $n = floor($v_header['size'] / 512);
1881
        for ($i = 0; $i < $n; $i++) {
1882
            $v_content = $this->_readBlock();
1883
            $v_filename .= $v_content;
1884
        }
1885
        if (($v_header['size'] % 512) != 0) {
1886
            $v_content = $this->_readBlock();
1887
            $v_filename .= $v_content;
1888
        }
1889 85ad3d82 Assos Assos
1890 30d5b9c5 Mathieu Schiano
        // ----- Read the next header
1891
        $v_binary_data = $this->_readBlock();
1892
1893
        if (!$this->_readHeader($v_binary_data, $v_header)) {
1894
            return false;
1895
        }
1896
1897
        $v_filename = rtrim(substr($v_filename, 0, $v_filesize), "\0");
1898
        $v_header['filename'] = $v_filename;
1899 01dfd3b5 Assos Assos
        if ($this->_isMaliciousFilename($v_filename)) {
1900 30d5b9c5 Mathieu Schiano
            $this->_error(
1901
                'Malicious .tar detected, file "' . $v_filename .
1902
                '" will not install in desired directory tree'
1903
            );
1904 85ad3d82 Assos Assos
            return false;
1905 30d5b9c5 Mathieu Schiano
        }
1906 85ad3d82 Assos Assos
1907 30d5b9c5 Mathieu Schiano
        return true;
1908 85ad3d82 Assos Assos
    }
1909
1910
    /**
1911 30d5b9c5 Mathieu Schiano
     * This method extract from the archive one file identified by $p_filename.
1912
     * The return value is a string with the file content, or null on error.
1913
     *
1914
     * @param string $p_filename The path of the file to extract in a string.
1915
     *
1916
     * @return a string with the file content or null.
1917
     */
1918
    private function _extractInString($p_filename)
1919 85ad3d82 Assos Assos
    {
1920
        $v_result_str = "";
1921
1922 30d5b9c5 Mathieu Schiano
        while (strlen($v_binary_data = $this->_readBlock()) != 0) {
1923
            if (!$this->_readHeader($v_binary_data, $v_header)) {
1924
                return null;
1925
            }
1926 85ad3d82 Assos Assos
1927 30d5b9c5 Mathieu Schiano
            if ($v_header['filename'] == '') {
1928
                continue;
1929
            }
1930
1931 cd5c298a Geoffroy Desvernay
            switch ($v_header['typeflag']) {
1932 27e02aed Assos Assos
                case 'L':
1933
                    {
1934
                        if (!$this->_readLongHeader($v_header)) {
1935
                            return null;
1936
                        }
1937 cd5c298a Geoffroy Desvernay
                    }
1938 27e02aed Assos Assos
                    break;
1939 cd5c298a Geoffroy Desvernay
1940 27e02aed Assos Assos
                case 'K':
1941
                    {
1942
                        $v_link_header = $v_header;
1943
                        if (!$this->_readLongHeader($v_link_header)) {
1944
                            return null;
1945
                        }
1946
                        $v_header['link'] = $v_link_header['filename'];
1947 cd5c298a Geoffroy Desvernay
                    }
1948 27e02aed Assos Assos
                    break;
1949 30d5b9c5 Mathieu Schiano
            }
1950
1951
            if ($v_header['filename'] == $p_filename) {
1952
                if ($v_header['typeflag'] == "5") {
1953
                    $this->_error(
1954
                        'Unable to extract in string a directory '
1955
                        . 'entry {' . $v_header['filename'] . '}'
1956
                    );
1957
                    return null;
1958
                } else {
1959
                    $n = floor($v_header['size'] / 512);
1960
                    for ($i = 0; $i < $n; $i++) {
1961
                        $v_result_str .= $this->_readBlock();
1962
                    }
1963
                    if (($v_header['size'] % 512) != 0) {
1964
                        $v_content = $this->_readBlock();
1965
                        $v_result_str .= substr(
1966
                            $v_content,
1967
                            0,
1968
                            ($v_header['size'] % 512)
1969
                        );
1970
                    }
1971
                    return $v_result_str;
1972
                }
1973
            } else {
1974
                $this->_jumpBlock(ceil(($v_header['size'] / 512)));
1975
            }
1976
        }
1977
1978
        return null;
1979 85ad3d82 Assos Assos
    }
1980
1981 30d5b9c5 Mathieu Schiano
    /**
1982
     * @param string $p_path
1983
     * @param string $p_list_detail
1984
     * @param string $p_mode
1985
     * @param string $p_file_list
1986
     * @param string $p_remove_path
1987
     * @param bool $p_preserve
1988 27e02aed Assos Assos
     * @param bool $p_symlinks
1989 30d5b9c5 Mathieu Schiano
     * @return bool
1990
     */
1991
    public function _extractList(
1992
        $p_path,
1993
        &$p_list_detail,
1994
        $p_mode,
1995
        $p_file_list,
1996
        $p_remove_path,
1997 27e02aed Assos Assos
        $p_preserve = false,
1998
        $p_symlinks = true
1999
    )
2000
    {
2001 30d5b9c5 Mathieu Schiano
        $v_result = true;
2002
        $v_nb = 0;
2003
        $v_extract_all = true;
2004
        $v_listing = false;
2005
2006
        $p_path = $this->_translateWinPath($p_path, false);
2007
        if ($p_path == '' || (substr($p_path, 0, 1) != '/'
2008
                && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))
2009
        ) {
2010
            $p_path = "./" . $p_path;
2011
        }
2012
        $p_remove_path = $this->_translateWinPath($p_remove_path);
2013
2014
        // ----- Look for path to remove format (should end by /)
2015
        if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) {
2016
            $p_remove_path .= '/';
2017
        }
2018
        $p_remove_path_size = strlen($p_remove_path);
2019 85ad3d82 Assos Assos
2020 30d5b9c5 Mathieu Schiano
        switch ($p_mode) {
2021
            case "complete" :
2022
                $v_extract_all = true;
2023
                $v_listing = false;
2024
                break;
2025
            case "partial" :
2026
                $v_extract_all = false;
2027
                $v_listing = false;
2028
                break;
2029
            case "list" :
2030
                $v_extract_all = false;
2031
                $v_listing = true;
2032
                break;
2033
            default :
2034
                $this->_error('Invalid extract mode (' . $p_mode . ')');
2035
                return false;
2036
        }
2037 85ad3d82 Assos Assos
2038 30d5b9c5 Mathieu Schiano
        clearstatcache();
2039 85ad3d82 Assos Assos
2040 30d5b9c5 Mathieu Schiano
        while (strlen($v_binary_data = $this->_readBlock()) != 0) {
2041
            $v_extract_file = false;
2042
            $v_extraction_stopped = 0;
2043
2044
            if (!$this->_readHeader($v_binary_data, $v_header)) {
2045
                return false;
2046
            }
2047
2048
            if ($v_header['filename'] == '') {
2049
                continue;
2050 85ad3d82 Assos Assos
            }
2051
2052 cd5c298a Geoffroy Desvernay
            switch ($v_header['typeflag']) {
2053 27e02aed Assos Assos
                case 'L':
2054
                    {
2055
                        if (!$this->_readLongHeader($v_header)) {
2056
                            return null;
2057
                        }
2058 cd5c298a Geoffroy Desvernay
                    }
2059 27e02aed Assos Assos
                    break;
2060 cd5c298a Geoffroy Desvernay
2061 27e02aed Assos Assos
                case 'K':
2062
                    {
2063
                        $v_link_header = $v_header;
2064
                        if (!$this->_readLongHeader($v_link_header)) {
2065
                            return null;
2066
                        }
2067
                        $v_header['link'] = $v_link_header['filename'];
2068 cd5c298a Geoffroy Desvernay
                    }
2069 27e02aed Assos Assos
                    break;
2070 85ad3d82 Assos Assos
            }
2071
2072 30d5b9c5 Mathieu Schiano
            // ignore extended / pax headers
2073
            if ($v_header['typeflag'] == 'x' || $v_header['typeflag'] == 'g') {
2074
                $this->_jumpBlock(ceil(($v_header['size'] / 512)));
2075
                continue;
2076
            }
2077 85ad3d82 Assos Assos
2078 30d5b9c5 Mathieu Schiano
            if ((!$v_extract_all) && (is_array($p_file_list))) {
2079
                // ----- By default no unzip if the file is not found
2080
                $v_extract_file = false;
2081
2082
                for ($i = 0; $i < sizeof($p_file_list); $i++) {
2083
                    // ----- Look if it is a directory
2084
                    if (substr($p_file_list[$i], -1) == '/') {
2085
                        // ----- Look if the directory is in the filename path
2086
                        if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
2087
                            && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
2088
                                == $p_file_list[$i])
2089
                        ) {
2090
                            $v_extract_file = true;
2091
                            break;
2092
                        }
2093
                    } // ----- It is a file, so compare the file names
2094
                    elseif ($p_file_list[$i] == $v_header['filename']) {
2095
                        $v_extract_file = true;
2096
                        break;
2097
                    }
2098
                }
2099
            } else {
2100
                $v_extract_file = true;
2101 85ad3d82 Assos Assos
            }
2102
2103 30d5b9c5 Mathieu Schiano
            // ----- Look if this file need to be extracted
2104
            if (($v_extract_file) && (!$v_listing)) {
2105
                if (($p_remove_path != '')
2106
                    && (substr($v_header['filename'] . '/', 0, $p_remove_path_size)
2107
                        == $p_remove_path)
2108
                ) {
2109
                    $v_header['filename'] = substr(
2110
                        $v_header['filename'],
2111
                        $p_remove_path_size
2112
                    );
2113
                    if ($v_header['filename'] == '') {
2114
                        continue;
2115
                    }
2116
                }
2117
                if (($p_path != './') && ($p_path != '/')) {
2118
                    while (substr($p_path, -1) == '/') {
2119
                        $p_path = substr($p_path, 0, strlen($p_path) - 1);
2120
                    }
2121 85ad3d82 Assos Assos
2122 30d5b9c5 Mathieu Schiano
                    if (substr($v_header['filename'], 0, 1) == '/') {
2123
                        $v_header['filename'] = $p_path . $v_header['filename'];
2124
                    } else {
2125
                        $v_header['filename'] = $p_path . '/' . $v_header['filename'];
2126
                    }
2127
                }
2128
                if (file_exists($v_header['filename'])) {
2129
                    if ((@is_dir($v_header['filename']))
2130
                        && ($v_header['typeflag'] == '')
2131
                    ) {
2132
                        $this->_error(
2133
                            'File ' . $v_header['filename']
2134
                            . ' already exists as a directory'
2135
                        );
2136
                        return false;
2137
                    }
2138
                    if (($this->_isArchive($v_header['filename']))
2139
                        && ($v_header['typeflag'] == "5")
2140
                    ) {
2141
                        $this->_error(
2142
                            'Directory ' . $v_header['filename']
2143
                            . ' already exists as a file'
2144
                        );
2145
                        return false;
2146
                    }
2147
                    if (!is_writeable($v_header['filename'])) {
2148
                        $this->_error(
2149
                            'File ' . $v_header['filename']
2150
                            . ' already exists and is write protected'
2151
                        );
2152
                        return false;
2153
                    }
2154
                    if (filemtime($v_header['filename']) > $v_header['mtime']) {
2155
                        // To be completed : An error or silent no replace ?
2156
                    }
2157
                } // ----- Check the directory availability and create it if necessary
2158
                elseif (($v_result
2159
                        = $this->_dirCheck(
2160
                        ($v_header['typeflag'] == "5"
2161
                            ? $v_header['filename']
2162
                            : dirname($v_header['filename']))
2163
                    )) != 1
2164
                ) {
2165
                    $this->_error('Unable to create path for ' . $v_header['filename']);
2166
                    return false;
2167
                }
2168 85ad3d82 Assos Assos
2169 30d5b9c5 Mathieu Schiano
                if ($v_extract_file) {
2170
                    if ($v_header['typeflag'] == "5") {
2171
                        if (!@file_exists($v_header['filename'])) {
2172
                            if (!@mkdir($v_header['filename'], 0777)) {
2173
                                $this->_error(
2174
                                    'Unable to create directory {'
2175
                                    . $v_header['filename'] . '}'
2176
                                );
2177
                                return false;
2178
                            }
2179
                        }
2180
                    } elseif ($v_header['typeflag'] == "2") {
2181 27e02aed Assos Assos
                        if (!$p_symlinks) {
2182
                            $this->_warning('Symbolic links are not allowed. '
2183
                                . 'Unable to extract {'
2184
                                . $v_header['filename'] . '}'
2185
                            );
2186
                            return false;
2187
                        }
2188 30d5b9c5 Mathieu Schiano
                        if (@file_exists($v_header['filename'])) {
2189
                            @drupal_unlink($v_header['filename']);
2190
                        }
2191
                        if (!@symlink($v_header['link'], $v_header['filename'])) {
2192
                            $this->_error(
2193
                                'Unable to extract symbolic link {'
2194
                                . $v_header['filename'] . '}'
2195
                            );
2196
                            return false;
2197
                        }
2198
                    } else {
2199
                        if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
2200
                            $this->_error(
2201
                                'Error while opening {' . $v_header['filename']
2202
                                . '} in write binary mode'
2203
                            );
2204
                            return false;
2205
                        } else {
2206
                            $n = floor($v_header['size'] / 512);
2207
                            for ($i = 0; $i < $n; $i++) {
2208
                                $v_content = $this->_readBlock();
2209
                                fwrite($v_dest_file, $v_content, 512);
2210
                            }
2211
                            if (($v_header['size'] % 512) != 0) {
2212
                                $v_content = $this->_readBlock();
2213
                                fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
2214
                            }
2215
2216
                            @fclose($v_dest_file);
2217
2218
                            if ($p_preserve) {
2219
                                @chown($v_header['filename'], $v_header['uid']);
2220
                                @chgrp($v_header['filename'], $v_header['gid']);
2221
                            }
2222
2223
                            // ----- Change the file mode, mtime
2224
                            @touch($v_header['filename'], $v_header['mtime']);
2225
                            if ($v_header['mode'] & 0111) {
2226
                                // make file executable, obey umask
2227
                                $mode = fileperms($v_header['filename']) | (~umask() & 0111);
2228
                                @chmod($v_header['filename'], $mode);
2229
                            }
2230
                        }
2231
2232
                        // ----- Check the file size
2233
                        clearstatcache();
2234
                        if (!is_file($v_header['filename'])) {
2235
                            $this->_error(
2236
                                'Extracted file ' . $v_header['filename']
2237
                                . 'does not exist. Archive may be corrupted.'
2238
                            );
2239
                            return false;
2240
                        }
2241
2242
                        $filesize = filesize($v_header['filename']);
2243
                        if ($filesize != $v_header['size']) {
2244
                            $this->_error(
2245
                                'Extracted file ' . $v_header['filename']
2246
                                . ' does not have the correct file size \''
2247
                                . $filesize
2248
                                . '\' (' . $v_header['size']
2249
                                . ' expected). Archive may be corrupted.'
2250
                            );
2251
                            return false;
2252
                        }
2253
                    }
2254
                } else {
2255
                    $this->_jumpBlock(ceil(($v_header['size'] / 512)));
2256
                }
2257
            } else {
2258
                $this->_jumpBlock(ceil(($v_header['size'] / 512)));
2259
            }
2260
2261
            /* TBC : Seems to be unused ...
2262
            if ($this->_compress)
2263
              $v_end_of_file = @gzeof($this->_file);
2264
            else
2265
              $v_end_of_file = @feof($this->_file);
2266
              */
2267
2268
            if ($v_listing || $v_extract_file || $v_extraction_stopped) {
2269
                // ----- Log extracted files
2270
                if (($v_file_dir = dirname($v_header['filename']))
2271
                    == $v_header['filename']
2272
                ) {
2273
                    $v_file_dir = '';
2274
                }
2275
                if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) {
2276
                    $v_file_dir = '/';
2277
                }
2278
2279
                $p_list_detail[$v_nb++] = $v_header;
2280
                if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
2281
                    return true;
2282
                }
2283
            }
2284 85ad3d82 Assos Assos
        }
2285
2286
        return true;
2287
    }
2288
2289 30d5b9c5 Mathieu Schiano
    /**
2290
     * @return bool
2291
     */
2292
    public function _openAppend()
2293 85ad3d82 Assos Assos
    {
2294 30d5b9c5 Mathieu Schiano
        if (filesize($this->_tarname) == 0) {
2295
            return $this->_openWrite();
2296
        }
2297 85ad3d82 Assos Assos
2298
        if ($this->_compress) {
2299
            $this->_close();
2300
2301 30d5b9c5 Mathieu Schiano
            if (!@rename($this->_tarname, $this->_tarname . ".tmp")) {
2302
                $this->_error(
2303
                    'Error while renaming \'' . $this->_tarname
2304
                    . '\' to temporary file \'' . $this->_tarname
2305
                    . '.tmp\''
2306
                );
2307 85ad3d82 Assos Assos
                return false;
2308
            }
2309
2310 30d5b9c5 Mathieu Schiano
            if ($this->_compress_type == 'gz') {
2311
                $v_temp_tar = @gzopen($this->_tarname . ".tmp", "rb");
2312
            } elseif ($this->_compress_type == 'bz2') {
2313
                $v_temp_tar = @bzopen($this->_tarname . ".tmp", "r");
2314
            } elseif ($this->_compress_type == 'lzma2') {
2315
                $v_temp_tar = @xzopen($this->_tarname . ".tmp", "r");
2316
            }
2317
2318 85ad3d82 Assos Assos
2319
            if ($v_temp_tar == 0) {
2320 30d5b9c5 Mathieu Schiano
                $this->_error(
2321
                    'Unable to open file \'' . $this->_tarname
2322
                    . '.tmp\' in binary read mode'
2323
                );
2324
                @rename($this->_tarname . ".tmp", $this->_tarname);
2325 85ad3d82 Assos Assos
                return false;
2326
            }
2327
2328
            if (!$this->_openWrite()) {
2329 30d5b9c5 Mathieu Schiano
                @rename($this->_tarname . ".tmp", $this->_tarname);
2330 85ad3d82 Assos Assos
                return false;
2331
            }
2332
2333
            if ($this->_compress_type == 'gz') {
2334 30d5b9c5 Mathieu Schiano
                $end_blocks = 0;
2335
2336 85ad3d82 Assos Assos
                while (!@gzeof($v_temp_tar)) {
2337
                    $v_buffer = @gzread($v_temp_tar, 512);
2338 30d5b9c5 Mathieu Schiano
                    if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
2339
                        $end_blocks++;
2340 85ad3d82 Assos Assos
                        // do not copy end blocks, we will re-make them
2341
                        // after appending
2342
                        continue;
2343 30d5b9c5 Mathieu Schiano
                    } elseif ($end_blocks > 0) {
2344
                        for ($i = 0; $i < $end_blocks; $i++) {
2345
                            $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
2346
                        }
2347
                        $end_blocks = 0;
2348 85ad3d82 Assos Assos
                    }
2349
                    $v_binary_data = pack("a512", $v_buffer);
2350
                    $this->_writeBlock($v_binary_data);
2351
                }
2352
2353
                @gzclose($v_temp_tar);
2354 30d5b9c5 Mathieu Schiano
            } elseif ($this->_compress_type == 'bz2') {
2355
                $end_blocks = 0;
2356
2357 85ad3d82 Assos Assos
                while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
2358 30d5b9c5 Mathieu Schiano
                    if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
2359
                        $end_blocks++;
2360
                        // do not copy end blocks, we will re-make them
2361
                        // after appending
2362 85ad3d82 Assos Assos
                        continue;
2363 30d5b9c5 Mathieu Schiano
                    } elseif ($end_blocks > 0) {
2364
                        for ($i = 0; $i < $end_blocks; $i++) {
2365
                            $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
2366
                        }
2367
                        $end_blocks = 0;
2368 85ad3d82 Assos Assos
                    }
2369
                    $v_binary_data = pack("a512", $v_buffer);
2370
                    $this->_writeBlock($v_binary_data);
2371
                }
2372
2373
                @bzclose($v_temp_tar);
2374 30d5b9c5 Mathieu Schiano
            } elseif ($this->_compress_type == 'lzma2') {
2375
                $end_blocks = 0;
2376
2377
                while (strlen($v_buffer = @xzread($v_temp_tar, 512)) > 0) {
2378
                    if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
2379
                        $end_blocks++;
2380
                        // do not copy end blocks, we will re-make them
2381
                        // after appending
2382
                        continue;
2383
                    } elseif ($end_blocks > 0) {
2384
                        for ($i = 0; $i < $end_blocks; $i++) {
2385
                            $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
2386
                        }
2387
                        $end_blocks = 0;
2388
                    }
2389
                    $v_binary_data = pack("a512", $v_buffer);
2390
                    $this->_writeBlock($v_binary_data);
2391
                }
2392 85ad3d82 Assos Assos
2393 30d5b9c5 Mathieu Schiano
                @xzclose($v_temp_tar);
2394 85ad3d82 Assos Assos
            }
2395
2396 30d5b9c5 Mathieu Schiano
            if (!@drupal_unlink($this->_tarname . ".tmp")) {
2397
                $this->_error(
2398
                    'Error while deleting temporary file \''
2399
                    . $this->_tarname . '.tmp\''
2400
                );
2401
            }
2402 85ad3d82 Assos Assos
        } else {
2403
            // ----- For not compressed tar, just add files before the last
2404 30d5b9c5 Mathieu Schiano
            //       one or two 512 bytes block
2405
            if (!$this->_openReadWrite()) {
2406
                return false;
2407
            }
2408 85ad3d82 Assos Assos
2409
            clearstatcache();
2410
            $v_size = filesize($this->_tarname);
2411
2412
            // We might have zero, one or two end blocks.
2413
            // The standard is two, but we should try to handle
2414
            // other cases.
2415
            fseek($this->_file, $v_size - 1024);
2416
            if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
2417
                fseek($this->_file, $v_size - 1024);
2418 30d5b9c5 Mathieu Schiano
            } elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
2419 85ad3d82 Assos Assos
                fseek($this->_file, $v_size - 512);
2420
            }
2421
        }
2422
2423
        return true;
2424
    }
2425
2426 30d5b9c5 Mathieu Schiano
    /**
2427
     * @param $p_filelist
2428
     * @param string $p_add_dir
2429
     * @param string $p_remove_dir
2430
     * @return bool
2431
     */
2432
    public function _append($p_filelist, $p_add_dir = '', $p_remove_dir = '')
2433 85ad3d82 Assos Assos
    {
2434 30d5b9c5 Mathieu Schiano
        if (!$this->_openAppend()) {
2435 85ad3d82 Assos Assos
            return false;
2436 30d5b9c5 Mathieu Schiano
        }
2437 85ad3d82 Assos Assos
2438 30d5b9c5 Mathieu Schiano
        if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) {
2439
            $this->_writeFooter();
2440
        }
2441 85ad3d82 Assos Assos
2442
        $this->_close();
2443
2444
        return true;
2445
    }
2446
2447
    /**
2448
     * Check if a directory exists and create it (including parent
2449
     * dirs) if not.
2450
     *
2451
     * @param string $p_dir directory to check
2452
     *
2453 30d5b9c5 Mathieu Schiano
     * @return bool true if the directory exists or was created
2454 85ad3d82 Assos Assos
     */
2455 30d5b9c5 Mathieu Schiano
    public function _dirCheck($p_dir)
2456 85ad3d82 Assos Assos
    {
2457
        clearstatcache();
2458 30d5b9c5 Mathieu Schiano
        if ((@is_dir($p_dir)) || ($p_dir == '')) {
2459 85ad3d82 Assos Assos
            return true;
2460 30d5b9c5 Mathieu Schiano
        }
2461 85ad3d82 Assos Assos
2462
        $p_parent_dir = dirname($p_dir);
2463
2464
        if (($p_parent_dir != $p_dir) &&
2465
            ($p_parent_dir != '') &&
2466 30d5b9c5 Mathieu Schiano
            (!$this->_dirCheck($p_parent_dir))
2467
        ) {
2468
            return false;
2469
        }
2470 85ad3d82 Assos Assos
2471 30d5b9c5 Mathieu Schiano
        if (!@mkdir($p_dir, 0777)) {
2472 85ad3d82 Assos Assos
            $this->_error("Unable to create directory '$p_dir'");
2473
            return false;
2474
        }
2475
2476
        return true;
2477
    }
2478
2479
    /**
2480
     * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
2481
     * rand emove double slashes.
2482
     *
2483
     * @param string $p_dir path to reduce
2484
     *
2485
     * @return string reduced path
2486
     */
2487 30d5b9c5 Mathieu Schiano
    private function _pathReduction($p_dir)
2488 85ad3d82 Assos Assos
    {
2489
        $v_result = '';
2490
2491
        // ----- Look for not empty path
2492
        if ($p_dir != '') {
2493
            // ----- Explode path by directory names
2494
            $v_list = explode('/', $p_dir);
2495
2496
            // ----- Study directories from last to first
2497 30d5b9c5 Mathieu Schiano
            for ($i = sizeof($v_list) - 1; $i >= 0; $i--) {
2498 85ad3d82 Assos Assos
                // ----- Look for current path
2499
                if ($v_list[$i] == ".") {
2500
                    // ----- Ignore this directory
2501
                    // Should be the first $i=0, but no check is done
2502
                } else {
2503 30d5b9c5 Mathieu Schiano
                    if ($v_list[$i] == "..") {
2504
                        // ----- Ignore it and ignore the $i-1
2505
                        $i--;
2506
                    } else {
2507
                        if (($v_list[$i] == '')
2508
                            && ($i != (sizeof($v_list) - 1))
2509
                            && ($i != 0)
2510
                        ) {
2511
                            // ----- Ignore only the double '//' in path,
2512
                            // but not the first and last /
2513
                        } else {
2514
                            $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? '/'
2515
                                    . $v_result : '');
2516
                        }
2517
                    }
2518 85ad3d82 Assos Assos
                }
2519
            }
2520
        }
2521 30d5b9c5 Mathieu Schiano
2522
        if (defined('OS_WINDOWS') && OS_WINDOWS) {
2523
            $v_result = strtr($v_result, '\\', '/');
2524
        }
2525
2526 85ad3d82 Assos Assos
        return $v_result;
2527
    }
2528
2529 30d5b9c5 Mathieu Schiano
    /**
2530
     * @param $p_path
2531
     * @param bool $p_remove_disk_letter
2532
     * @return string
2533
     */
2534
    public function _translateWinPath($p_path, $p_remove_disk_letter = true)
2535 85ad3d82 Assos Assos
    {
2536 30d5b9c5 Mathieu Schiano
        if (defined('OS_WINDOWS') && OS_WINDOWS) {
2537
            // ----- Look for potential disk letter
2538
            if (($p_remove_disk_letter)
2539
                && (($v_position = strpos($p_path, ':')) != false)
2540
            ) {
2541
                $p_path = substr($p_path, $v_position + 1);
2542
            }
2543
            // ----- Change potential windows directory separator
2544
            if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
2545
                $p_path = strtr($p_path, '\\', '/');
2546
            }
2547
        }
2548
        return $p_path;
2549 85ad3d82 Assos Assos
    }
2550
}