diff --git a/ecrire/inc_flock.php3 b/ecrire/inc_flock.php3 new file mode 100644 index 0000000000000000000000000000000000000000..f389c111633c070a7904c4759b57c9d7a6c6bdb9 --- /dev/null +++ b/ecrire/inc_flock.php3 @@ -0,0 +1,222 @@ +<?php + +// +// Ce fichier ne sera execute qu'une fois +if (defined("_ECRIRE_INC_FLOCK")) return; +define("_ECRIRE_INC_FLOCK", "1"); + +// flock() marche dans ce repertoire <=> j'ai le droit de flock() sur ce fichier +if (LOCK_UN!=3) { + define ('LOCK_SH', 1); + define ('LOCK_EX', 2); + define ('LOCK_UN', 3); + define ('LOCK_NB', 4); +} + +function test_flock ($fichier, $fp=false) { + static $flock = array(); + global $flag_flock; + if (!$flag_flock) + return false; + + preg_match('|(.*)/([^/]*)$|', $fichier, $match); + $dir = $match[1]; + if ($dir == '') + return false; // a la racine on ne fait que lire + + // premier appel pour ce $dir ? + if (!isset($flock[$dir])) { + // si un fichier d'etat flock est la et pas trop vieux -- id est: + // pas recopie depuis une autre installation ! -- c'est ok. + if (@file_exists("$dir/.flock_ok") + AND (filemtime("$dir/.flock_ok") > time() - 3600)) + $flock[$dir] = true; + else if (@file_exists("$dir/.flock_naze") + AND (filemtime("$dir/.flock_naze") > time() - 3600)) + $flock[$dir] = false; + + else { + // pas d'infos de flock, on va tester + $fichiertest = $dir.'/' + .substr(uniqid(@getmypid(), true),-6).".tmp"; + if ($fp = @fopen($fichiertest, 'w')) { + if (@flock($fp, LOCK_SH)) { + @flock($fp, LOCK_UN); + $flock[$dir] = true; + @touch("$dir/.flock_ok"); + @unlink("$dir/.flock_naze"); + spip_log("test $dir: flock ok"); + } else { + $flock[$dir] = false; + @touch("$dir/.flock_naze"); + @unlink("$dir/.flock_ok"); + spip_log("test $dir: flock naze"); + } + @unlink($fichiertest); + } else { + spip_log("test $dir: echec du test sur $fichiertest !"); + @touch("$dir/.flock_naze"); + @unlink("$dir/.flock_ok"); + } + } + } + + return $flock[$dir]; +} + +// Si flock ne marche pas dans ce repertoire ou chez cet hebergeur, +// on renvoie OK pour ne pas bloquer +function spip_flock($filehandle, $mode, $fichier) { + if (!test_flock($fichier)) + return true; + + $r = flock($filehandle, $mode); + + // demande de verrou ==> risque de sleep ==> forcer la relecture de l'etat + if ($mode == LOCK_EX) + clearstatcache(); + + return $r; +} + +function spip_file_get_contents ($fichier) { + + if (substr($fichier, -3) != '.gz') { + if (function_exists('file_get_contents') + AND $GLOBALS['os_serveur'] !='windows') # windows retourne '' + return @file_get_contents ($fichier); + else + return join('', @file($fichier)); + } else + return join('', @gzfile($fichier)); + +} + +// options = array( +// 'phpcheck' => 'oui' # verifier qu'on a bien du php +// dezippe automatiquement les fichiers .gz +function lire_fichier ($fichier, &$contenu, $options=false) { + $contenu = ''; + if (!@file_exists($fichier)) + return false; + + #spip_timer('lire_fichier'); + + if ($fl = @fopen($fichier, 'r')) { + + // verrou lecture + while (!spip_flock($fl, LOCK_SH, $fichier)); + + // a-t-il ete supprime par le locker ? + if (!@file_exists($fichier)) { + @fclose($fl); + return false; + } + + // lire le fichier + $contenu = spip_file_get_contents($fichier); + + // liberer le verrou + spip_flock($fl, LOCK_UN, $fichier); + @fclose($fl); + + // Verifications + $ok = true; + if ($options['phpcheck'] == 'oui') + $ok &= (ereg("[?]>\n?$", $contenu)); + + #spip_log("$fread $fichier ".spip_timer('lire_fichier')); + if (!$ok) + spip_log("echec lecture $fichier"); + + return $ok; + } +} + + +// +// Ecrire un fichier de maniere un peu sure +// +// zippe les fichiers .gz +function ecrire_fichier ($fichier, $contenu) { + + // Ne rien faire si on est en preview ou si une erreur + // grave s'est presentee (compilation du squelette, MySQL, etc) + if ($GLOBALS['var_preview'] OR defined('spip_erreur_fatale')) + return; + + $gzip = (substr($fichier, -3) == '.gz'); + + if ($gzip) { + $fopen = gzopen; + $fputs = gzputs; + $fclose = gzclose; + } else { + $fopen = fopen; + $fputs = fputs; + $fclose = fclose; + } + + #spip_timer('ecrire_fichier'); + + // verrouiller le fichier destination + if ($flock = test_flock($fichier)) { + if ($fp = @fopen($fichier, 'a')) + while (!spip_flock($fp, LOCK_EX, $fichier)); + else + return false; + } + + // ecrire les donnees, compressees le cas echeant + // (on ouvre un nouveau pointeur sur le fichier, ce qui a l'avantage + // de le recreer si le locker qui nous precede l'avait supprime...) + if ($fo = @$fopen($fichier, 'w')) + $s = @$fputs($fo, $contenu, $a = strlen($contenu)); + else + return false; + + $ok = ($s == $a); + if (!$ok) + spip_log("echec ecriture fichier $fichier"); + + #spip_log("$fputs $fichier ".spip_timer('ecrire_fichier')); + + // fermer le fichier + @fclose($fo); + + // liberer le verrou + if ($flock) { + spip_flock($fp, LOCK_UN, $fichier); + @fclose($fp); + } + + return $ok; +} + +// +// Supprimer le fichier de maniere sympa (flock) +// +function supprimer_fichier($fichier) { + if (!@file_exists($fichier)) + return; + + // verrouiller le fichier destination + if ($flock = test_flock($fichier)) { + if ($fp = @fopen($fichier, 'a')) + while (!spip_flock($fp, LOCK_EX, $fichier)); + else + return; + } + + // supprimer + @unlink($fichier); + + // liberer le verrou + if ($flock) { + spip_flock($fp, LOCK_UN, $fichier); + @fclose($fp); + } + +} + +?> diff --git a/ecrire/inc_version.php3 b/ecrire/inc_version.php3 index 2817a17c8d4346d7b43b33dc095cc8bfa0de81fb..892307a2e0481f4b8c783dfca9609d7cba07c86f 100644 --- a/ecrire/inc_version.php3 +++ b/ecrire/inc_version.php3 @@ -807,197 +807,9 @@ function quote_amp ($url) { // -// Lire un fichier de maniere un peu sure +// Module de lecture/ecriture/suppression de fichiers utilisant flock() // - - -// flock() marche dans ce repertoire <=> j'ai le droit de flock() sur ce fichier -if (LOCK_UN!=3) { - define ('LOCK_SH', 1); - define ('LOCK_EX', 2); - define ('LOCK_UN', 3); - define ('LOCK_NB', 4); -} -function test_flock ($fichier, $fp=false) { - static $flock = array(); - global $flag_flock, $os_serveur; - if (!$flag_flock - OR $os_serveur == 'windows') // sous win rename() plante avec fopen() - return false; - - preg_match('|(.*)/([^/]*)$|', $fichier, $match); - $dir = $match[1]; - if (!$dir) $dir = '.'; - - // premier appel pour ce $dir ? - if (!isset($flock[$dir])) { - // si on me passe un pointeur, je teste et j'ecris le resultat - if ($fp) { - if (@flock($fp, LOCK_SH)) { - @flock($fp, LOCK_UN); - @touch("$dir/.flock_ok"); - } else - @unlink("$dir/.flock_ok"); - } - // si le fichier est la et pas trop vieux -- id est: - // pas recopie depuis une autre installation ! -- c'est ok. - $flock[$dir] = (@file_exists("$dir/.flock_ok") - AND (filemtime("$dir/.flock_ok") > time() - 3600)); - } - - return $flock[$dir]; -} - -// Si flock ne marche pas dans ce repertoire ou chez cet hebergeur, -// on renvoie OK pour ne pas bloquer -function spip_flock($filehandle, $mode, $fichier) { - if (!test_flock($fichier)) - return true; - - $r = flock($filehandle, $mode); - - // demande de verrou ==> risque de sleep ==> forcer la relecture de l'etat - if ($mode == LOCK_EX) - clearstatcache(); - - return $r; -} - -function spip_file_get_contents ($fichier) { - global $os_serveur; - - if (substr($fichier, -3) != '.gz') { - if (function_exists('file_get_contents') - AND $os_serveur !='windows') # windows retourne '' - return @file_get_contents ($fichier); - else - return join('', file($fichier)); - } else - return join('', gzfile($fichier)); - -} - -// options = array( -// 'phpcheck' => 'oui' # verifier qu'on a bien du php -// dezippe automatiquement les fichiers .gz -function lire_fichier ($fichier, &$contenu, $options=false) { - $contenu = ''; - if (!@file_exists($fichier)) - return false; - - #spip_timer('lire_fichier'); - - if ($fl = @fopen($fichier, 'r')) { - - // verrou lecture - while (!spip_flock($fl, LOCK_SH, $fichier)); - - // lire le fichier - $contenu = spip_file_get_contents($fichier); - - // liberer le verrou - spip_flock($fl, LOCK_UN, $fichier); - @fclose($fl); - - // Verifications - $ok = true; - if ($options['phpcheck'] == 'oui') - $ok &= (ereg("[?]>\n?$", $contenu)); - - #spip_log("$fread $fichier ".spip_timer('lire_fichier')); - if (!$ok) - spip_log("echec lecture $fichier"); - - return $ok; - } -} - - -// -// Ecrire un fichier de maniere un peu sure -// -// zippe les fichiers .gz -function ecrire_fichier ($fichier, $contenu) { - global $os_serveur; - - // Ne rien faire si on est en preview ou si une erreur - // grave s'est presentee (compilation du squelette, MySQL, etc) - if ($GLOBALS['var_preview'] OR defined('spip_erreur_fatale')) - return; - - // Ecriture dans un fichier temporaire - // dans le repertoire destination - preg_match('|(.*)/([^/]*)$|', $fichier, $match); - $dir = $match[1]; - $fichiertmp = $dir.'/' - .uniqid(substr(md5($fichier),0,6).'-'.@getmypid()).".tmp"; - - $gzip = (substr($fichier, -3) == '.gz'); - - if ($gzip) { - $fopen = gzopen; - $fputs = gzputs; - $fclose = gzclose; - } else { - $fopen = fopen; - $fputs = fputs; - $fclose = fclose; - } - - #spip_timer('ecrire_fichier'); - - if ($ft = @$fopen($fichiertmp, 'wb')) { - // on en profite pour tester flock() - $flock = test_flock($fichiertmp, $ft); - $s = @$fputs($ft, $contenu, $a = strlen($contenu)); - @$fclose($ft); - $ok = ($s == $a); - } - - if ($ok) { - // ouvrir et obtenir un verrou sur le fichier destination - if ($flock AND $fp = @fopen($fichier, 'a')) - while (!spip_flock($fp, LOCK_EX, $fichier)); - - // recopier le temporaire - if ($os_serveur == 'windows') @unlink("./".$fichier); - $ok = @rename("./".$fichiertmp, "./".$fichier); - - // liberer le verrou - if ($flock AND $fp) { - spip_flock($fp, LOCK_UN, $fichier); - @fclose($fp); - } - } - - - // en cas d'echec effacer le temporaire - if (!$ok) { - spip_log("echec ecriture fichier $fichier"); - @unlink($fichiertmp); - } - - #spip_log("$fputs $fichier ".spip_timer('ecrire_fichier')); - - return $ok; -} - -// -// Supprimer un fichier en attendant d'abord de le spip_flock -// -function supprimer_fichier ($fichier) { - if (!@file_exists($fichier)) - return false; - - if (test_flock($fichier)) - if ($fl = @fopen($fichier, 'r')) { - while(!spip_flock($fl, LOCK_EX, $fichier)); - spip_flock($fl, LOCK_UN, $fichier); - @fclose($fl); - } - - @unlink($fichier); -} +include_ecrire('inc_flock.php3'); //