]> granicus.if.org Git - php/commitdiff
* added file locking
authorStig Bakken <ssb@php.net>
Mon, 11 Mar 2002 15:13:19 +0000 (15:13 +0000)
committerStig Bakken <ssb@php.net>
Mon, 11 Mar 2002 15:13:19 +0000 (15:13 +0000)
* added file name to package map

pear/PEAR/Registry.php

index d22623e06de6182f364987cdddaf66e9a92a395b..7bb9b9b47d08f2cbc9567fc013fa32146acccade 100644 (file)
 // $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;
     }
 
     // }}}