Example #1
0
 /**
  * Open metatable file
  * @param string
  * @param int defaults to self::READWRITE | self::STRINGS_GC
  * @return metatable|bool
  */
 public static function open($filename, $flags = 6)
 {
     // check flags
     if (($flags & self::READONLY) === self::READONLY && ($flags & self::READWRITE) === self::READWRITE) {
         return FALSE;
     }
     // initialize
     $tries_left = self::LOCK_TRIES;
     $inode = @fileinode($filename);
     $handle = @fopen($filename, 'rb' . (($flags & self::READWRITE) === self::READWRITE ? '+' : ''));
     $locking = NULL;
     $tmp = NULL;
     $structure = array();
     $handle_filename = NULL;
     $tmp_filename = NULL;
     // open metatable file
     if ($handle) {
         // file exists
         while (true) {
             // try to lock
             if (!flock($handle, ($flags & self::READONLY) === self::READONLY ? LOCK_SH : LOCK_EX)) {
                 fclose($handle);
                 return FALSE;
             }
             // check inode
             clearstatcache();
             $current_inode = fileinode($filename);
             if ($current_inode === $inode) {
                 break;
             }
             if ($tries_left <= 0) {
                 fclose($handle);
                 return FALSE;
             }
             // try to open again
             fclose($handle);
             $tries_left--;
             $inode = $current_inode;
             $handle = @fopen($filename, 'rb' . (($flags & self::READWRITE) === self::READWRITE ? '+' : ''));
             if (!$handle) {
                 return FALSE;
             }
         }
     } else {
         // file does not exist
         if (($flags & self::READONLY) === self::READONLY) {
             return FALSE;
         }
         $handle = NULL;
     }
     // read structure
     $structure = array('signature' => self::MAGIC_STRING, 'version' => self::VERSION, 'frames' => array(), 'frames_indexes' => array());
     $frames = array();
     if ($handle) {
         $structure = self::structure_read($handle);
     }
     // open write and temporary file
     if (($flags & self::READWRITE) === self::READWRITE) {
         $locking = $handle;
         list($tmp_filename, $tmp) = self::tmp();
         if (!$tmp_filename || !$tmp) {
             if ($locking) {
                 fclose($locking);
             }
             return FALSE;
         }
         list($handle_filename, $handle) = array($filename . '~handle', @fopen($filename . '~handle', 'w+'));
         if (!$handle_filename || !$handle) {
             fclose($tmp);
             unlink($tmp_filename);
             if ($locking) {
                 fclose($locking);
             }
             return FALSE;
         }
         // copy data to temporary
         if ($locking) {
             foreach ($structure['frames'] as $i => $frame) {
                 if ($frame['name'] === self::FRAME_STRINGS) {
                     $structure['frames'][$i]['used_at_start'] = $structure['frames'][$i]['used'];
                     $structure['frames'][$i]['offset_at_start'] = $structure['frames'][$i]['offset'];
                 }
                 if (!(($flags & self::STRINGS_GC) === self::STRINGS_GC && $frame['name'] === self::FRAME_STRINGS)) {
                     if (!(fseek($locking, $frame['offset'], SEEK_SET) !== -1 && fseek($handle, $frame['offset'], SEEK_SET) !== -1 && stream_copy_to_stream($locking, $handle, $frame['used']) === $frame['used'])) {
                         fclose($locking);
                         fclose($handle);
                         unlink($handle_filename);
                         fclose($tmp);
                         unlink($tmp_filename);
                         return FALSE;
                     }
                 }
             }
         }
     }
     // create instance
     $that = new self();
     $that->flags = $flags;
     $that->filename = $filename;
     $that->handle_filename = $handle_filename;
     $that->tmp_filename = $tmp_filename;
     $that->locking = $locking;
     $that->handle = $handle;
     $that->tmp = $tmp;
     $that->structure = $structure;
     if (!isset($structure['frames_indexes'][self::FRAME_INDEXES])) {
         $that->frame_create(self::FRAME_INDEXES, 0);
     }
     if (!isset($structure['frames_indexes'][self::FRAME_STRINGS])) {
         $that->frame_create(self::FRAME_STRINGS, 1);
     }
     if (!isset($structure['frames_indexes'][self::FRAME_DATA])) {
         $that->frame_create(self::FRAME_DATA, 2);
     }
     // get indexes
     fseek($that->handle, $that->structure['frames'][$that->structure['frames_indexes'][self::FRAME_INDEXES]]['offset'], SEEK_SET);
     for ($i = 0, $N = $that->structure['frames'][$that->structure['frames_indexes'][self::FRAME_INDEXES]]['used'] / self::SIZEOF_INDEX_RECORD; $i < $N; $i++) {
         $data = fread($that->handle, self::SIZEOF_INDEX_RECORD);
         if (strlen($data) < self::SIZEOF_INDEX_RECORD) {
             continue;
         }
         $data = unpack(self::INDEX_RECORD_UNPACK, $data);
         $that->indexes[$data['start']] = array($data['lower'], $data['upper']);
     }
     // return
     return $that;
 }