rlm@3: <?php
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | PHP version 5                                                        |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | This source file is subject to version 2 of the GPL license,         |
rlm@3: // | that is bundled with this package in the file license.txt and is     |
rlm@3: // | available through the world-wide-web at the following url:           |
rlm@3: // | http://www.gnu.org/copyleft/gpl.html                                 |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | Authors: James Heinrich <infoØgetid3*org>                            |
rlm@3: // |          Allan Hansen <ahØartemis*dk>                                |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | module.archive.tar.php                                               |
rlm@3: // | module for analyzing TAR files                                       |
rlm@3: // | dependencies: NONE                                                   |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | Module originally written by Mike Mozolin <teddybearØmail*ru>        |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: //
rlm@3: // $Id: module.archive.tar.php,v 1.2 2006/11/02 10:48:00 ah Exp $
rlm@3: 
rlm@3:         
rlm@3:         
rlm@3: class getid3_tar extends getid3_handler
rlm@3: {
rlm@3: 
rlm@3:     function Analyze() {
rlm@3: 
rlm@3:         $info = &$this->getid3->info;
rlm@3: 
rlm@3:         $info['fileformat'] = 'tar';
rlm@3: 
rlm@3:         $fp = $this->getid3->fp;
rlm@3:         
rlm@3:         fseek($fp, 0);
rlm@3:         
rlm@3:         $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155/prefix';
rlm@3: 
rlm@3:         $null_512k = str_repeat("\0", 512); // end-of-file marker
rlm@3: 
rlm@3:         $already_warned = false;
rlm@3: 
rlm@3:         while (!feof($fp)) {
rlm@3:             
rlm@3:             $buffer = fread($fp, 512);
rlm@3:             
rlm@3:             // check the block
rlm@3:             $checksum = 0;
rlm@3:             for ($i = 0; $i < 148; $i++) {
rlm@3:                 $checksum += ord(substr($buffer, $i, 1));
rlm@3:             }
rlm@3:             for ($i = 148; $i < 156; $i++) {
rlm@3:                 $checksum += ord(' ');
rlm@3:             }
rlm@3:             for ($i = 156; $i < 512; $i++) {
rlm@3:                 $checksum += ord(substr($buffer, $i, 1));
rlm@3:             }
rlm@3:             $attr    = unpack($unpack_header, $buffer);
rlm@3:             $name    =        trim(@$attr['fname']);
rlm@3:             $mode    = octdec(trim(@$attr['mode']));
rlm@3:             $uid     = octdec(trim(@$attr['uid']));
rlm@3:             $gid     = octdec(trim(@$attr['gid']));
rlm@3:             $size    = octdec(trim(@$attr['size']));
rlm@3:             $mtime   = octdec(trim(@$attr['mtime']));
rlm@3:             $chksum  = octdec(trim(@$attr['chksum']));
rlm@3:             $typflag =        trim(@$attr['typflag']);
rlm@3:             $lnkname =        trim(@$attr['lnkname']);
rlm@3:             $magic   =        trim(@$attr['magic']);
rlm@3:             $ver     =        trim(@$attr['ver']);
rlm@3:             $uname   =        trim(@$attr['uname']);
rlm@3:             $gname   =        trim(@$attr['gname']);
rlm@3:             $devmaj  = octdec(trim(@$attr['devmaj']));
rlm@3:             $devmin  = octdec(trim(@$attr['devmin']));
rlm@3:             $prefix  =        trim(@$attr['prefix']);
rlm@3: 
rlm@3:             // EOF Found
rlm@3:             if (($checksum == 256) && ($chksum == 0)) {
rlm@3:                 break;
rlm@3:             }
rlm@3: 
rlm@3:             // Check if filename if 7bit as spec requires
rlm@3:             if (!$already_warned) {
rlm@3:                 for ($i = 0; $i < strlen($name); $i++) {
rlm@3:                     if ($name{$i} < chr(32) || $name{$i} > chr(127)) {
rlm@3:                         $this->getid3->warning('Some filenames contains extended characters, which breaks the tar specifation. This is not uncommon, but you will have to handle the character encoding for filenames yourself.');
rlm@3:                         $already_warned = true;
rlm@3:                         break;
rlm@3:                     }
rlm@3:                 }
rlm@3:             }
rlm@3:             
rlm@3:             if ($prefix) {
rlm@3:                 $name = $prefix.'/'.$name;
rlm@3:             }
rlm@3:             if ((preg_match('#/$#', $name)) && !$name) {
rlm@3:                 $typeflag = 5;
rlm@3:             }
rlm@3:             
rlm@3:             // If it's the end of the tar-file...
rlm@3:             if ($buffer == $null_512k) {
rlm@3:                 break;
rlm@3:             }
rlm@3:             
rlm@3:             // Protect against tar-files with garbage at the end
rlm@3:             if ($name == '') {
rlm@3:                 break;
rlm@3:             }
rlm@3:             
rlm@3:             $info['tar']['file_details'][$name] = array (
rlm@3:                 'name'     => $name,
rlm@3:                 'mode_raw' => $mode,
rlm@3:                 'mode'     => getid3_tar::display_perms($mode),
rlm@3:                 'uid'      => $uid,
rlm@3:                 'gid'      => $gid,
rlm@3:                 'size'     => $size,
rlm@3:                 'mtime'    => $mtime,
rlm@3:                 'chksum'   => $chksum,
rlm@3:                 'typeflag' => getid3_tar::get_flag_type($typflag),
rlm@3:                 'linkname' => $lnkname,
rlm@3:                 'magic'    => $magic,
rlm@3:                 'version'  => $ver,
rlm@3:                 'uname'    => $uname,
rlm@3:                 'gname'    => $gname,
rlm@3:                 'devmajor' => $devmaj,
rlm@3:                 'devminor' => $devmin
rlm@3:             );
rlm@3:             
rlm@3:             // Skip the next chunk
rlm@3:             fseek($fp, $size, SEEK_CUR);
rlm@3: 
rlm@3:             // Throw away padding
rlm@3:             if ($size % 512) {
rlm@3:                 fseek($fp, 512 - $diff, SEEK_CUR);
rlm@3:             }
rlm@3:             
rlm@3:         }
rlm@3:         return true;
rlm@3:     }
rlm@3: 
rlm@3: 
rlm@3:     // Parses the file mode to file permissions
rlm@3:     public static function display_perms($mode) {
rlm@3: 
rlm@3:         // Determine Type
rlm@3:         if ($mode & 0x1000) {
rlm@3:             $type='p'; // FIFO pipe
rlm@3:         }
rlm@3:         elseif ($mode & 0x2000) {
rlm@3:             $type='c'; // Character special
rlm@3:         }
rlm@3:         elseif ($mode & 0x4000) {
rlm@3:             $type='d'; // Directory
rlm@3:         }
rlm@3:         elseif ($mode & 0x6000) {
rlm@3:             $type='b'; // Block special
rlm@3:         }
rlm@3:         elseif ($mode & 0x8000) {
rlm@3:             $type='-'; // Regular
rlm@3:         }
rlm@3:         elseif ($mode & 0xA000) {
rlm@3:             $type='l'; // Symbolic Link
rlm@3:         }
rlm@3:         elseif ($mode & 0xC000) {
rlm@3:             $type='s'; // Socket
rlm@3:         }
rlm@3:         else {
rlm@3:             $type='u'; // UNKNOWN
rlm@3:         }
rlm@3: 
rlm@3:         // Determine permissions
rlm@3:         $owner['read']    = (($mode & 00400) ? 'r' : '-');
rlm@3:         $owner['write']   = (($mode & 00200) ? 'w' : '-');
rlm@3:         $owner['execute'] = (($mode & 00100) ? 'x' : '-');
rlm@3:         $group['read']    = (($mode & 00040) ? 'r' : '-');
rlm@3:         $group['write']   = (($mode & 00020) ? 'w' : '-');
rlm@3:         $group['execute'] = (($mode & 00010) ? 'x' : '-');
rlm@3:         $world['read']    = (($mode & 00004) ? 'r' : '-');
rlm@3:         $world['write']   = (($mode & 00002) ? 'w' : '-');
rlm@3:         $world['execute'] = (($mode & 00001) ? 'x' : '-');
rlm@3: 
rlm@3:         // Adjust for SUID, SGID and sticky bit
rlm@3:         if ($mode & 0x800) {
rlm@3:             $owner['execute'] = ($owner['execute'] == 'x') ? 's' : 'S';
rlm@3:         }
rlm@3:         if ($mode & 0x400) {
rlm@3:             $group['execute'] = ($group['execute'] == 'x') ? 's' : 'S';
rlm@3:         }
rlm@3:         if ($mode & 0x200) {
rlm@3:             $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T';
rlm@3:         }
rlm@3: 
rlm@3:         $s  = sprintf('%1s', $type);
rlm@3:         $s .= sprintf('%1s%1s%1s',      $owner['read'], $owner['write'], $owner['execute']);
rlm@3:         $s .= sprintf('%1s%1s%1s',      $group['read'], $group['write'], $group['execute']);
rlm@3:         $s .= sprintf('%1s%1s%1s'."\n", $world['read'], $world['write'], $world['execute']);
rlm@3: 
rlm@3:         return $s;
rlm@3:     }
rlm@3: 
rlm@3: 
rlm@3:     // Converts the file type
rlm@3:     public static function get_flag_type($typflag) {
rlm@3: 
rlm@3:         static $flag_types = array (
rlm@3:             '0' => 'LF_NORMAL',
rlm@3:             '1' => 'LF_LINK',
rlm@3:             '2' => 'LF_SYNLINK',
rlm@3:             '3' => 'LF_CHR',
rlm@3:             '4' => 'LF_BLK',
rlm@3:             '5' => 'LF_DIR',
rlm@3:             '6' => 'LF_FIFO',
rlm@3:             '7' => 'LF_CONFIG',
rlm@3:             'D' => 'LF_DUMPDIR',
rlm@3:             'K' => 'LF_LONGLINK',
rlm@3:             'L' => 'LF_LONGNAME',
rlm@3:             'M' => 'LF_MULTIVOL',
rlm@3:             'N' => 'LF_NAMES',
rlm@3:             'S' => 'LF_SPARSE',
rlm@3:             'V' => 'LF_VOLHDR'
rlm@3:         );
rlm@3: 
rlm@3:         return @$flag_types[$typflag];
rlm@3:     }
rlm@3:     
rlm@3: }
rlm@3: 
rlm@3: ?>