En C pour travailler avec les path y a une macro sympa: MAXPATHLEN. En faite,
y a aussi PATH_MAX et comme j'ai jamais trouvé la profonde différence entre
les deux, j'ai demandé à google. Dans mes recherches, je voulais aussi
savoir si la valeur de MAXPATHLEN (ou PATH_MAX) représente la
taille réelle du chemin le plus long, ou la taille du
buffer contenant le chemin le plus long (la différence entre les deux est
que le buffer a besoin d'un slot supplémentaire pour le '\0').
J'ai finalement dérivé (sur le web, on dérive. en tout cas moi souvent.) sur un combat mené par GNU contre ces macros, qui reflète une guerre plus globale de GNU contre les limites arbitraires.
C'est la façon dont tu t'en sert
Mais bon, c'est Hurd qui a la plus grosse quand même
Donc j'atteris ici, une idée de projet de gsoc, la guerre ouverte
contre MAXPATHLEN et PATH_MAX. En résumé, POSIX n'exige pas la présence
des macros PATH_MAX et MAXPATHLEN, et hurd ne les définit pas. Ça argumente
à coup de lien vers un blog post qui explique que de toute manière t'arrives à
créer des path plus grand que MAXPATHLEN.
insane what?
Malgré les yeux qui piquent à cause du code C++ qu'on trouve sur le blog post en question, on en tire une conclusion intéressante, finalement pas très surprenante:
c'est la dèche.
ugly
POSIX n'exige pas que l'OS définisse MAXPATHLEN et/ou PATH_MAX, mais le
prototype de getcwd(3) utilise implicitement une limite:
char * getcwd(char *buf, size_t size);
Tel que défini par POSIX, pour utiliser getcwd(3) sans MAXPATHLEN il faut
faire un loop bien moche, une sorte de brute force de ton programme VS ton OS,
voilà un petit exemple:
size_t s = 1024; /* or 42, or whatever */ char *path = NULL; do { s *= 2; path = realloc(path, s); if (path == NULL) break; /* errno is set to ENOMEM */ if (getcwd(path, s) == NULL) { if (errno == ERANGE) { /* expected, we will retry with a larger buffer. */ continue; } else { /* unexpected, some error from getcwd(3). */ free(path); path = NULL; } } } while (/*CONSTCOND*/0); /* * here we have either path == NULL and errno set, or path is the resolved path * returned by getcwd(3). */
ugly ugly
Mieux (ou pire, je sais pas) realpath(3) est inutilisable sans MAXPATHLEN.
char * realpath(const char *file_name, char *resolved_name);
Le prototype ici demande que l'on connaisse la taille de resolved_name
avant, au risque d'un joli buffer overflow.
Comment qu'il faut faire alors?
1. rend ton code moche
T'utilises des extensions. POSIX défini pas ce qui se passe quand tu donne
NULL à realpath(3) et getcwd(3) (pour resolved_name et respectivement
buf), et plusieurs libc (FreeBSD et glibc pour realpath(3), FreeBSD,
OpenBSD, NetBSD et glibc pour getcwd(3)) en profitent pour faire en sorte que
la fonction retourne un buffer mallocé de la taille apropriée. glibc défini
aussi des extensions GNUish, que ma maman m'a défendu de nommer ici. Bien
évidement le tout protégé par de immondes #ifdef pour pas faire n'importe
quoi n'importe où.
2. bloat ton projet
Tu réécris la moitié de la libc (pendant la pause de midi, feignasse).
3. oublie la portabilité
T'utilises MAXPATHLEN ou PATH_MAX, et pis bon ba, ton code FAIL sous
GNU/Hurd.
bave break™, parce que tu l'as mérité
Dans la guideline de porting Hurd on trouve sous la rubrique dédiée à
MAXPATHLEN et PATH_MAX des liens vers deux patch (dont un
de pulse-audio) avec des loop ultra moche comme celui de l'exemple de
getcwd(3) (mais en encore plus moche, prépares les mouchoirs). Le comble,
c'est qu'ils servent d'exemple pour fixer les projets qui pas-compilent sous
Hurd parce qu'ils usent de MAXPATHLEN ou PATH_MAX.
Ce qui fait quand même sourire c'est qu'ils disent que c'est la faute des
méchants programmeurs (i.e. toi et moi) qui écrivent MAXPATHLEN et
PATH_MAX, qui "violent" POSIX, et que nul par ils reconnaissent que
POSIX est incohérent sur le sujet.
come to the dark side, we have MAXPATHLEN
Après toutes ces lectures et browsage de code, les questions qui m'ont plongé
dans cet histoire sont toujours en suspend. Selon le manuel de realpath(3)
sous debian:
[…] In 4.4BSD and Solaris the limit on the pathname length is MAXPATHLEN (found in <sys/param.h>). SUSv2 prescribes PATH_MAX and NAME_MAX, as found in <limits.h> or provided by the pathconf(3) function. […]
Finalement dans la pratique on dirait que soit les deux sont définies, soit aucune, donc fais-toi plaiz et choisis celle que tu trouves la plus sexy.
Concernant la taille, on trouve 50% du code qui utilise path[MAXPATHLEN + 1]
mais j'ai pas vu de tel chose dans la doc, donc je pense que simplement
path[MAXPATHLEN] suffit.
Your makros works really good wothout any problems!
I was searching for this script! Thanks a lot for publishing it here
I completely agree with you in such points!