lalahop

La magie des liens sous Windows Vista/7

Table des matières

Les liens, dans les systèmes de gestion de fichiers j'entends, tout le monde connait. Pourtant, nous allons quand même revenir sur deux cas, sous Windows, dans lesquels ils peuvent s'avérer utiles : avec Squid et avec Daemon Tools/Y.A.S.U. Pour aborder cet article, je vous conseille de savoir la différence qu'il y a entre un lien symbolique et un hard link (lien matériel en français).

Cas pratique n°1 : Squid

Pour télécharger une version de Squid pour Windows (et en même temps avoir les instructions d'installation 😀 ), je vous conseille ce site : Acme Consulting - Squid 2.7 for Windows. Suivons les instructions ensembles :

Extract the binary archive in the desired directory (default c:\squid)

Hum ... Je sais pas pour vous mais moi j'aime bien que mes programmes soient bien rangés. Ainsi je vais mettre Squid dans "C:\Program Files (x86)\Squid".

Copy and rename the follwing files:

Rien de compliqué ici ... Je vous attends pour passer à la suite 🙂

Edit the squid.conf and change if needed the c:/squid path (use path with '/' char, NOT '\')

Ça ne sert à rien de suivre cette consigne puisque, comme préciser plus bas sur le site :

Paths with spaces (like C:\Programs Files\Squid) are NOT supported by Squid

Continuons :

Manually create ALL the directories specified in squid.conf, except the contents of the cache directory

En fait, il n'y a qu'un seul dossier à créer : /var/cache. Mais au cas où cela changerai à l'avenir, je vous conseille de lire le fichier de configuration. Ce fichier contient beaucoup de commentaires. Qu'à cela ne tienne : voici un script PHP fait il y quelques années par Dodo et que je viens d'améliorer, qui affiche les lignes du fichier de configuration qui ne sont ni commentées ni vides :

<?php
	$fichierDeConfiguration = fopen('squid.conf', 'r');

	while ($ligne = fgets($fichierDeConfiguration))
	{
		if (($ligne[0] != '#') AND (bin2hex($ligne[0]) != '0a'))
		{
			$tableau[] = $ligne;
		}
	}

	foreach($tableau as $ligneOK)
	{
		echo $ligneOK . '<br /><br />';
	}

	fclose($fichierDeConfiguration);
?>

Ce script est sans prétention. Oui, nous aurions pu utiliser une regex pour chercher tous les répertoires mentionnés dans le fichier de configuration puis exclure les répertoires commentés. Mais nous avons fait autrement 😀

squid -i [-f configfile] [-n servicename] (installs the servicename Squid service using the configfile configuration file, default configfile is "c:/squid/etc/squid.conf", default servicename is "Squid")

Rien de spécial ici.

squid -z [-f configfile] (creates the cache directories)

C'est là que commence les ennuis puisque nous obtenons un joli message :

FATAL: MIME Config Table c:/squid/etc/mime.conf: (2) No such file or directory
Squid Cache (Version 2.7.STABLE8): Terminated abnormally.
CPU Usage: 0.016 seconds = 0.000 user + 0.016 sys
Maximum Resident Size: 5732 KB
Page faults with physical i/o: 1523

abnormal program termination

Squid cherche le fichier mime.conf dans C:\Squid. Si nous modifions la variable mime_table dans le fichier de configuration, Squid la refusera car elle contiendra des espaces. En attendant, nous ne pouvons pas lancer Squid.

La solution est de créer un lien réel de C:\Squid vers C:\Program Files (x86)\Squid (dans la terminologie Windows/NTFS, on appelle cela une jonction de répertoire) :

c:\>mklink /D /H /J Squid "C:\Program Files (x86)\Squid"
Jonction créée pour Squid <<===>> C:\Program Files (x86)\Squid

Ce coup-là, Squid fonctionne :

2010/08/17 17:41:07| Creating Swap Directories

La fin de l'installation, à savoir la création d'un service, ne pose pas de problèmes particuliers. Je vous laisse donc continuer tout seul.

Nous avons donc bien rangé notre programme dans le répertoire prévu à cet effet. Seul un lien traine dans C:\ .

Cas pratique n°2 : Daemon Tools et Y.A.S.U.

Avant de commencer, je rappelle à tous les bien-pensants que Y.A.S.U. n'est pas utilisable que dans des activités illégales 😉 . Il peut par exemple servir à contourner les protections Securom et Safedisc dans le cas où l'on utilise des mini-images afin de ne pas avoir à insérer le CD/DVD dans le lecteur à chaque fois que l'on souhaite jouer, dans le but de préserver la durée de vie du CD/DVD original du jeu et de notre lecteur CD/DVD.

Depuis les versions postérieurs à la version 4.30 de Daemon Tools, Y.A.S.U. ne semble plus fonctionner en mettant un message "Unable to locate the file "daemon.exe" or "dtpro.exe". Please copy "YASU.exe" to your DAEMON Tools Lite/Pro directory, then run the application again."

La première solution est de renommer le fichier DTLite.exe en daemon.exe. Je sais pas ce que vous en pensez, mais cette solution manque de piment 😉 .

La deuxième solution est de créer un lien. Mais plutôt que de le faire depuis l'interface graphique, faisons le depuis la ligne de commande :

C:\Program Files (x86)\DAEMON Tools Lite>mklink daemon.exe DTLite.exe
Lien symbolique créé pour daemon.exe <<===>> DTLite.exe

ÉDIT du 14/05/2011 à 17h20 : Pour créer un lien réel sous XP, il faut utiliser la commande fsutil. Ainsi, pour l'exemple précédent, il suffit de faire :

C:\Program Files (x86)\DAEMON Tools Lite>fsutil hardlink create daemon.exe DTLite.exe

Mise au point à propos des destructeurs

La programmation orientée objet introduit le concept de destructeur. Pour résumer, il s'agit d'une unique méthode de classe (dans le sens où une classe peut implémenter plusieurs constructeurs mais un seul destructeur) qui est exécutée lors de la destruction d'un objet de la classe afin de récupérer les ressources, mémoire notamment, empruntées lors de la création de l'objet.

Sur le net, on peut parfois lire qu'il ne sert à rien d'écrire soit-même le code du destructeur ou qu'il faut écrire le destructeur que lorsque l'on utilise des pointeurs. Parfois, c'est encore pire : on peut lire qu'un destructeur ne sert à rien. Faisons une petite mise au point.

La première chose à savoir est que l'on n'a pas besoin de destructeur dans les langages de programmation (Java, PHP, etc. ) qui implémentent un système de ramasse-miettes (en anglais, juste pour épater les filles : garbage collector) car la libération de la mémoire est alors automatique. Certains vont dire : dans ce cas, à quoi sert la méthode java.lang.object.finalize() en Java ?

La réponse est simple : d'une part, la méthode finalize() ne détruit pas l'objet : elle permet au programmeur de réaliser une action avant la destruction à proprement parlé de l'objet par le ramasse-miettes. D'autre part, elle n'est pas à utiliser, même pour fermer un descripteur de fichier car Java ne peut ni garantir que cette méthode sera bien exécutée ni quand elle le sera. De plus cela ruine la portabilité de l'application, ce qui est un peu dommage vu que c'est un des principaux objectifs de Java. Ce n'est pas moi qui le dit mais Joshua Bloch dans son livre "Effective Java: Programming Language Guide". Vu les antécédents de cette personne dans le domaine Java, on peut, peut-être, lui faire confiance.

Prenons un exemple rapide : réaliser un close() sur un objet de la classe FileOuputStream à l'intérieur d'une méthode finalize() redéfinie est une mauvaise méthode en plus d'être inutile. Le close() doit être fait dans le bloc finally (vous savez : try ... catch ... finally) qui suit le try dans lequel vous avez ouvert le fichier. Plus précisément, elle doit être faite dans un bloc try ... catch à l'intérieur d'un bloc finally car cette méthode peut soulever une exception de type IOException.

Pour lever tout ambiguïté concernant mes propos :
En PHP, la méthode magique __destruct permet de personnaliser le processus de destruction d'un objet (exemple : supprimer une ligne dans une table de la base de donnée lors de la destruction d'une instance d'une classe donnée). Néanmoins, PHP implémente un mécanisme de libération automatique de la mémoire. Avant PHP 5.3, il était basé sur un compteur de référence : dès qu'une variable n'est plus référencée, elle est supprimée. Depuis PHP 5.3, le mécanisme a été amélioré et on obtient un garbage collector qui, en plus de faire la même chose que le mécanisme du compteur de référence, permet d'éviter les problèmes liés aux références circulaires. C'est pour cela que je pense que, comme en Java, il n'est pas nécessaire de redéfinir un destructeur sauf à vouloir personnaliser la destruction d'un objet comme évoqué précédemment.

Ensuite, pour les langages orientés objet sans ramasse-miettes (C++ par exemple) :

- Pour tout ce qui est allocation statique (int, double, array, objet) à l'intérieur d'une classe et qui sera donc stocké sur la pile, vous n'avez pas besoin d'un destructeur. Même avec un pointeur (un tableau est un pointeur), tout sera supprimé automatiquement par le destructeur par défaut. C'est pour ça qu'il est faux de dire qu'il faut écrire soit-même le code du destructeur dès que l'on utilise un pointeur. Le must c'est que même les appels récursifs sont pris en compte. Par exemple : Soit une classe A qui créer un objet de classe B qui elle même créer un tableau. Le tableau sera bel et bien supprimé.

- Pour tout ce qui est allocation dynamique (utilisation de l'opérateur new ou malloc) à l'intérieur d'une classe et qui sera donc stocké sur le tas, il est impératif d'écrire soit-même le code du destructeur. C'est pour ça qu'il est faux de dire qu'un destructeur ne sert à rien ou qu'il ne faut jamais le re-implémenter.

Pour résumer :

  • Langage objet avec ramasse-miettes : pas de destructeur à implémenter
  • Langage objet sans ramasse-miettes :
    • utilisation de l'allocation statique à l'intérieur d'une classe : pas besoin de redéfinir le destructeur par défaut.
    • utilisation de l'allocation dynamique à l'intérieur d'une classe : il faut redéfinir le destructeur par défaut (mais aussi le constructeur de recopie et l'opérateur d'affectation pour bien faire ;)).

ÉDIT du 28/10/2011 à 14h : Et si vous avez un doute sur la libération de la mémoire, vous pouvez utiliser Valgrind. Je l'ai utilisé uniquement sur du C et du C++ mais, d’après le grand Web, il fonctionne aussi avec du Python. Fin de l'édit.