Proposer une amélioration de commentaire

Le commentaire à poster est au format «docblock» (de phpDoc) qui peut être enrichi de tags spécifiques pour SPIP.
Fichier
ecrire/inc/nfslock.php
Fonction
spip_nfslock

    Nom ou pseudo de l'auteur de la proposition

Code original

/**
 * Crée un verrou pour NFS
 *
 * (Excerpts from Chuck's notes:
 *   this becomes complex, due to our dear friend, the NFS mounted mail spool.
 *   the netbsd code didn't do this properly, as far as I could tell.
 *
 *   - you can't trust exclusive creating opens over NFS, the protocol
 *   just doesn't support it.   so to do a lock you have to create
 *   a tmp file and then try and hard link it to your lock file.
 *   - to detect a stale lock file you have to see how old it is, but
 *   you can't use time(0) because that is the time on the local system
 *   and the file gets the times of the NFS server.  when is a lock
 *   file stale?  people seem to like 120 or 300 seconds.)
 *
 * NB: It is _critical_ that nfslock()ed files be unlocked by nfsunlock().
 * Simply unlinking the lock file is a good way to trash someone else's lock
 * file. All it takes is for the process doing the unlink to get hung for
 * a few minutes when it doesn't expect it. Meanwhile, its lock expires and
 * a second process forces the lock and creates its own. Then the first
 * process comes along and kills the second process' lock while it's still
 * valid.
 *
 * Security considerations:
 * If we're root, be very careful to see that the temp file we opened is
 * what we think it is. The problem is that we could lose a race with
 * someone who takes our tmp file and replaces it with, say, a hard
 * link to /etc/passwd. Then, if the first lock attempt fails, we'll
 * write a char to the file (see 4. below); this would truncate the
 * passwd file. So we make sure that the link count is 1. We don't really
 * care about any other screwing around since we don't write anything
 * sensitive to the lock file, nor do we change its owner or mode. If
 * someone beats us on a race and replaces our temp file with anything
 * else, it's no big deal- the file may get truncated, but there's no
 * possible security breach. ...Actually the possibility of the race
 * ever happening, given the random name of the file, is virtually nil.
 *
 * args: path = path to directory of lock file (/net/u/1/a/alexis/.mailspool)
 *       namelock = file name of lock file (alexis.lock)
 *   max_age = age of lockfile, in seconds, after which the lock is stale.
 *    stale locks are always broken. Defaults to DEFAULT_LOCKTIME
 *    if zero. Panix mail locks go stale at 300 seconds, the default.
 *       notify = 1 if we should tell stdout that we're sleeping on a lock
 *
 * Returns the time that the lock was created on the other system. This is
 * important for nfsunlock(). If the lock already exists, returns NFSL_LOCKED.
 * If there is some other failure, return NFSL_SYSF. If NFSL_LOCKED is
 * returned, errno is also set to EEXIST. If we're root and the link count
 * on the tmp file is wrong, return NFSL_SECV.
 *
 * Mods of 7/13/95: Change a bit of code to re-stat the lockfile after
 * closing it. This is to work around a bug in SunOS that appears to to affect
 * some SunOS 4.1.3 machines (but not all). The bug is that close() updates
 * the stat st_ctime field for that file. So use lstat on fullpath instead
 * of fstat on tmpfd. This alteration applies to both nfslock and nfslock1.
 *
 * Mod of 5/4/95: Change printf's to fprintf(stderr... in nfslock and nfslock1.
 *
 * Mods of 4/29/95: Fix freeing memory before use if a stat fails. Remove
 * code that forbids running as root; instead, if root, check link count on
 * tmp file after opening it.
 *
 * Mods of 4/27/95: Return the create time instead of the lockfile's fd, which
 * is useless. Added new routines nfsunlock(), nfslock_test(), nfslock_renew().
 *
 * Mods of 1/8/95: Eliminate some security checks since this code never
 * runs as root. In particular, we completely eliminate the safeopen
 * routine. But add one check: if we _are_ root, fail immediately.
 *
 * Change arguments: take a path and a filename. Don't assume a global or
 * macro pointing to a mailspool.
 *
 * Add notify argument; if 1, tell user when we're waiting for a lock.
 *
 * Add max_age argument and DEFAULT_LOCKTIME.
 *
 * Change comments drastically.
 *
 * @author Chuck Cranor <chuck@maria.wustl.edu> (original author)
 * @author Alexis Rosen <alexis@panix.com> (rewritter)
 * @author Cedric Morin <cedric@yterium.com> (rewritter for php&SPIP)
 *
 * @param string $fichier Chemin du fichier
 * @param int $max_age Age maximum du verrou
 * @return int|bool Timestamp du verrou, false si erreur
 */
function spip_nfslock($fichier, $max_age = 0) {
	$tries = 0;
 
	if (!$max_age) {
		$max_age = _DEFAULT_LOCKTIME;
	}
	$lock_file = _DIR_TMP . _NAME_LOCK . '-' . substr(md5($fichier), 0, 8);
 
 
	/*
	 * 1. create a tmp file with a psuedo random file name. we also make
	 *    tpath which is a buffer to store the full pathname of the tmp file.
	 */
 
	$id = creer_uniqid();
	$tpath = _DIR_TMP . "slock.$id";
	$tmpfd = @fopen($tpath, 'w'); // hum, le 'x' necessite php4,3,2 ...
	if (!$tmpfd) {  /* open failed */
		@fclose($tmpfd);
		spip_unlink($tpath);
 
		return false; //NFSL_SYSF
	}
 
	/*
	 * 2. make fullpath, a buffer for the full pathname of the lock file.
	 *    then start looping trying to lock it
	 */
 
	while ($tries < 10) {
		/*
		 * 3. link tmp file to lock file.  if it goes, we win and we clean
		 *    up and return the st_ctime of the lock file.
		 */
 
		if (link($tpath, $lock_file) == 1) {
			spip_unlink($tpath); /* got it! */
			@fclose($tmpfd);
			if (($our_tmp = lstat($lock_file)) == false) {  /* stat failed... shouldn't happen */
				spip_unlink($lock_file);
 
				return false; // (NFSL_SYSF);
			}
 
			return ($our_tmp['ctime']);
		}
 
		/*
		 * 4. the lock failed.  check for a stale lock file, being mindful
		 *    of NFS and the fact the time is set from the NFS server.  we
		 *    do a write on the tmp file to update its time to the server's
		 *    idea of "now."
		 */
 
		$old_stat = lstat($lock_file);
		if (@fputs($tmpfd, 'zz', 2) != 2 || !$our_tmp = fstat($tmpfd)) {
			break;
		} /* something bogus is going on */
 
 
		if ($old_stat != false && (($old_stat['ctime'] + $max_age) < $our_tmp['ctime'])) {
			spip_unlink($lock_file); /* break the stale lock */
			$tries++;
			/* It is CRITICAL that we sleep after breaking
			 * the lock. Otherwise, we could race with
			 * another process and unlink it's newly-
			 * created file.
			 */
			sleep(1 + rand(0, 4));
			continue;
		}
 
		/*
		 * 5. try again
		 */
 
		$tries++;
		sleep(1 + rand(0, 4));
	}
 
	/*
	 * 6. give up, failure.
	 */
 
	spip_unlink($tpath);
	@fclose($tmpfd);
 
	return false; //(NFSL_LOCKED);
}

Le commentaire au format « docblock » peut être complété des éléments suivants sécifiques
à SPIP.

Sur un entête de fichier :

  • @package SPIP\Core\x (pour un fichier du core, x dépendant du fichier)
  • @package SPIP\Nom\x (pour un fichier de plugin, Nom étant le nom du plugin)

Sur un entête de fonction :

  • @pipeline x : indique que la fonction est une utilisation d’un pipeline
  • @pipeline_appel x : indique que la fonction appelle le pipeline indiqué
  • @balise : indique que la fonction est une compilation de balise
  • @filtre : indique un |filtre
  • @critere : indique que la fonction est une compilaiton de critère
  • @boucle : indique que la fonction est une compilaiton de boucle
Vous inscrire sur ce site

L’espace privé de ce site est ouvert aux visiteurs, après inscription. Une fois enregistré, vous pourrez consulter les articles en cours de rédaction, proposer des articles et participer à tous les forums.

Identifiants personnels

Indiquez ici votre nom et votre adresse email. Votre identifiant personnel vous parviendra rapidement, par courrier électronique.