Sindbad~EG File Manager
<?php
/*
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2007 Bharat Mediratta
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
GalleryCoreApi::requireOnce('modules/core/classes/GalleryLockSystem.class');
/**
* Flock() based locking. This is fairly efficient, but it will not work on NFS and is known to be
* unreliable on some operating systems including some flavors of the 2.4 Linux kernel.
* @package GalleryCore
* @subpackage Classes
* @author Bharat Mediratta <bharat@menalto.com>
* @author Alan Harder <alan.harder@sun.com>
* @version $Revision: 15799 $
*/
class FlockLockSystem extends GalleryLockSystem {
/**
* Reference counts for every lock we're holding so that if we've got a file doubly read locked
* we don't try to delete it until all read locks are released.
* @todo When we get rid of double read locks, we can delete this.
* @var array
* @access private
*/
var $_references;
/**
* @see GalleryLockSystem::_acquireLock
*/
function _acquireLock($ids, $timeout, $lockType) {
global $gallery;
$platform =& $gallery->getPlatform();
$cutoffTime = time() + $timeout;
/* Get a file handle (which is actually a lock handle) for all the files first */
$notLocked = array();
foreach ($ids as $id) {
$lockFile = $this->_getLockFile($id);
$fd = $platform->fopen($lockFile, 'wb+');
if ($fd) {
$notLocked[$id] = array($fd, $lockFile);
} else {
/* Close the files that we already opened successfully and return an error */
foreach ($notLocked as $lockInfo) {
list ($fd, $lockFile) = $lockInfo;
$platform->fclose($fd);
/*
* Delete the lock files even if others are locking it too (releaseLock calls
* are too often forgotten in error handling)
*/
if ($platform->file_exists($lockFile)) {
@$platform->unlink($lockFile);
}
}
return array(GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__,
$lockFile), null);
}
}
/* Move them from notLocked -> locked as we acquire the lock */
$locked = array();
$wouldBlock = null;
$flockType = ($lockType == LOCK_READ) ? LOCK_SH : LOCK_EX;
while (!empty($notLocked)) {
$tmp = $notLocked;
$notLocked = array();
foreach ($tmp as $id => $lockInfo) {
list ($fd, $lockFile) = $lockInfo;
/* Check if we can lock */
$flockReturned = $platform->flock($fd, $flockType | LOCK_NB, $wouldBlock);
if ($flockReturned && !$wouldBlock) {
$locked[$id] = $lockInfo;
/* Keep track of the number of locks there are for this object */
if (isset($this->_references[$lockFile])) {
$this->_references[$lockFile]++;
} else {
$this->_references[$lockFile] = 1;
}
} else {
/* Remember that it's not locked and keep going */
$notLocked[$id] = $lockInfo;
}
}
if (!empty($notLocked)) {
if (time() > $cutoffTime) {
/* Couldn't get the locks in time, release the ones that we have and return */
foreach (array_merge($locked, $notLocked) as $lockInfo) {
$this->_closeLockFile($lockInfo);
}
return array(GalleryCoreApi::error(ERROR_LOCK_TIMEOUT, __FILE__, __LINE__,
array_reduce($notLocked,
create_function('$v,$w', 'return empty($v) ? $w[1] : "$v $w[1]";'))),
null);
}
/* Wait a second and try any unacquired locks again */
$gallery->debug('Waiting for a lock');
sleep(1);
}
}
$lockId = crc32(microtime());
$this->_locks[$lockId] = array('lockId' => $lockId, 'type' => $lockType, 'ids' => $locked);
return array(null, $lockId);
}
/**
* @see GalleryLockSystem::_releaseLocksNow
*/
function _releaseLocksNow($locks) {
global $gallery;
$gallery->guaranteeTimeLimit(count($locks) + 5);
/* Release all locks by closing the files */
foreach ($locks as $lock) {
foreach ($lock['ids'] as $lockInfo) {
$this->_closeLockFile($lockInfo);
}
}
return null;
}
/**
* @see GalleryLockSystem::refreshLocks
*/
function refreshLocks($freshUntil) {
global $gallery;
$platform =& $gallery->getPlatform();
/* Flush one byte to each lock file to update its timestamp */
foreach ($this->_locks as $lockId => $lock) {
foreach ($lock['ids'] as $lockInfo) {
list ($fd, $lockFile) = $lockInfo;
$count = $platform->fwrite($fd, '.');
if ($count == 0) {
return GalleryCoreApi::error(ERROR_STORAGE_FAILURE, __FILE__, __LINE__,
$lockFile);
}
$platform->fflush($fd);
}
}
return null;
}
/**
* Return the lock file for a given object id.
* @param int $id the input id
* @return string the complete path to the lock file
* @access private
*/
function _getLockFile($id) {
global $gallery;
return $gallery->getConfig('data.gallery.locks') . (int)$id;
}
/**
* Close file for this lock and remove file if there are no more references.
* @param array $lockInfo lockInfo
* @access private
*/
function _closeLockFile($lockInfo) {
global $gallery;
$platform =& $gallery->getPlatform();
list ($fd, $lockFile) = $lockInfo;
$platform->fclose($fd);
if ($platform->file_exists($lockFile)) {
$this->_references[$lockFile]--;
if ($this->_references[$lockFile] == 0) {
$platform->unlink($lockFile);
}
}
}
/**
* @see GalleryLockSystem::_removeObjectsFromLock
*/
function _removeObjectsFromLock(&$lock, $ids) {
foreach ($ids as $id) {
$this->_closeLockFile($lock['ids'][$id]);
unset($lock['ids'][$id]);
}
return null;
}
/**
* @see GalleryLockSystem::_newLockId
*/
function _newLockId() {
return array(null, crc32(microtime()));
}
}
?>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists