From: Stig Bakken Date: Mon, 11 Mar 2002 15:13:19 +0000 (+0000) Subject: * added file locking X-Git-Tag: help~79 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=32d3a0afd7fe8175526149e0075545ee64c3aa3a;p=php * added file locking * added file name to package map --- diff --git a/pear/PEAR/Registry.php b/pear/PEAR/Registry.php index d22623e06d..7bb9b9b47d 100644 --- a/pear/PEAR/Registry.php +++ b/pear/PEAR/Registry.php @@ -19,39 +19,113 @@ // $Id$ require_once "System.php"; +require_once "PEAR.php"; + +define("PEAR_REGISTRY_ERROR_LOCK", -2); /** * Administration class used to maintain the installed package database. */ -class PEAR_Registry +class PEAR_Registry extends PEAR { // {{{ properties - var $statedir; + /** Directory where registry files are stored. + * @var string + */ + var $statedir = ''; + + /** File where the file map is stored + * @var string + */ + var $filemap = ''; + + /** Name of file used for locking the registry + * @var string + */ + var $lockfile = ''; + + /** File descriptor used during locking + * @var resource + */ + var $lock_fp = null; + + /** Mode used during locking + * @var int + */ + var $lock_mode = 0; // XXX UNUSED // }}} // {{{ PEAR_Registry + /** + * PEAR_Registry constructor. + * + * @param string (optional) PEAR install directory (for .php files) + * + * @access public + */ function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR) { - $this->statedir = $pear_install_dir . "/.registry"; + parent::PEAR(); + $ds = DIRECTORY_SEPARATOR; + $this->statedir = $pear_install_dir.$ds.".registry"; + $this->filemap = $pear_install_dir.$ds.".filemap"; + $this->lockfile = $pear_install_dir.$ds.".lock"; + if (!file_exists($this->filemap)) { + $this->_rebuildFileMap(); + } + } + + // }}} + // {{{ _PEAR_Registry + + /** + * PEAR_Registry destructor. Makes sure no locks are forgotten. + * + * @access private + */ + function _PEAR_Registry() + { + parent::_PEAR(); + if (is_resource($this->lock_fp)) { + $this->_unlock(); + } } // }}} // {{{ _assertStateDir() + /** + * Make sure the directory where we keep registry files exists. + * + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ function _assertStateDir() { if (!@is_dir($this->statedir)) { - System::mkdir("-p {$this->statedir}"); + return System::mkdir("-p {$this->statedir}"); } + return true; } // }}} // {{{ _packageFileName() + /** + * Get the name of the file where data for a given package is stored. + * + * @param string package name + * + * @return string registry file name + * + * @access public + */ function _packageFileName($package) { return "{$this->statedir}/{$package}.reg"; @@ -80,39 +154,83 @@ class PEAR_Registry } // }}} + // {{{ _rebuildFileMap() - // {{{ packageExists() - - function packageExists($package) + function _rebuildFileMap() { - return file_exists($this->_packageFileName($package)); + $packages = $this->listPackages(); + $files = array(); + foreach ($packages as $package) { + $version = $this->packageInfo($package, "version"); + $filelist = $this->packageInfo($package, "filelist"); + if (!is_array($filelist)) { + continue; + } + foreach ($filelist as $name => $attrs) { + if (isset($attrs['role']) && $attrs['role'] != 'php') { + continue; + } + if (isset($attrs['baseinstalldir'])) { + $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; + } else { + $file = $name; + } + $file = preg_replace(',^/+,', '', $file); + $files[$file] = $package; + } + } + $this->_assertStateDir(); + $fp = @fopen($this->filemap, "w"); + if (!$fp) { + return false; + } + fwrite($fp, serialize($files)); + fclose($fp); + return true; } // }}} - // {{{ addPackage() + // {{{ _lock() - function addPackage($package, $info) + function _lock($mode = LOCK_EX) { - if ($this->packageExists($package)) { - return false; + if ($mode != LOCK_UN && is_resource($this->lock_fp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; } - $fp = $this->_openPackageFile($package, "w"); - if ($fp === null) { - return false; + $this->lock_fp = @fopen($this->lockfile, "w"); + if (!is_resource($this->lock_fp)) { + return null; } - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - return true; + return (int)flock($this->lock_fp, $mode); } // }}} - // {{{ packageInfo() + // {{{ _unlock() - function packageInfo($package = null, $key = null) + function _unlock() + { + $ret = $this->_lock(LOCK_UN); + $this->lock_fp = null; + return $ret; + } + + // }}} + // {{{ _packageExists() + + function _packageExists($package) + { + return file_exists($this->_packageFileName($package)); + } + + // }}} + // {{{ _packageInfo() + + function _packageInfo($package = null, $key = null) { if ($package === null) { - return array_map(array($this, "packageInfo"), - $this->listPackages()); + return array_map(array($this, "_packageInfo"), + $this->_listPackages()); } $fp = $this->_openPackageFile($package, "r"); if ($fp === null) { @@ -130,13 +248,100 @@ class PEAR_Registry return null; } + // }}} + // {{{ _listPackages() + + function _listPackages() + { + $pkglist = array(); + $dp = @opendir($this->statedir); + if (!$dp) { + return $pkglist; + } + while ($ent = readdir($dp)) { + if ($ent{0} == "." || substr($ent, -4) != ".reg") { + continue; + } + $pkglist[] = substr($ent, 0, -4); + } + return $pkglist; + } + + // }}} + + // {{{ packageExists() + + function packageExists($package) + { + if (!$this->_lock(LOCK_SH)) { + return $this->raiseError("could not acquire shared lock", PEAR_REGISTRY_ERROR_LOCK); + } + $ret = $this->_packageExists($package); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ packageInfo() + + function packageInfo($package = null, $key = null) + { + if (!$this->_lock(LOCK_SH)) { + return $this->raiseError("could not acquire shared lock", PEAR_REGISTRY_ERROR_LOCK); + } + $ret = $this->_packageInfo($package, $key); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ listPackages() + + function listPackages() + { + if (!$this->_lock(LOCK_SH)) { + return $this->raiseError("could not acquire shared lock", PEAR_REGISTRY_ERROR_LOCK); + } + $ret = $this->_listPackages(); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ addPackage() + + function addPackage($package, $info) + { + if ($this->packageExists($package)) { + return false; + } + if (!$this->_lock(LOCK_EX)) { + return $this->raiseError("could not acquire exclusive lock", PEAR_REGISTRY_ERROR_LOCK); + } + $fp = $this->_openPackageFile($package, "w"); + if ($fp === null) { + $this->_unlock(); + return false; + } + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_unlock(); + return true; + } + // }}} // {{{ deletePackage() function deletePackage($package) { + if (!$this->_lock(LOCK_EX)) { + return $this->raiseError("could not acquire exclusive lock", PEAR_REGISTRY_ERROR_LOCK); + } $file = $this->_packageFileName($package); - return @unlink($file); + $ret = @unlink($file); + $this->_rebuildFileMap(); + $this->_unlock(); + return $ret; } // }}} @@ -148,8 +353,15 @@ class PEAR_Registry if (empty($oldinfo)) { return false; } + if (!$this->_lock(LOCK_EX)) { + return $this->raiseError("could not acquire exclusive lock", PEAR_REGISTRY_ERROR_LOCK); + } + if (!file_exists($this->filemap)) { + $this->_rebuildFileMap(); + } $fp = $this->_openPackageFile($package, "w"); if ($fp === null) { + $this->_unlock(); return false; } if ($merge) { @@ -158,26 +370,11 @@ class PEAR_Registry fwrite($fp, serialize($info)); } $this->_closePackageFile($fp); - return true; - } - - // }}} - // {{{ listPackages() - - function listPackages() - { - $pkglist = array(); - $dp = @opendir($this->statedir); - if (!$dp) { - return $pkglist; + if (isset($info['filelist'])) { + $this->_rebuildFileMap(); } - while ($ent = readdir($dp)) { - if ($ent{0} == "." || substr($ent, -4) != ".reg") { - continue; - } - $pkglist[] = substr($ent, 0, -4); - } - return $pkglist; + $this->_unlock(); + return true; } // }}}