Pourquoi glob lstat correspond-il aux entrées?

En regardant le comportement dans cette question , j’ai été surpris de voir que perl lstat() s chaque chemin correspondant à un motif de glob:

 $ mkdir dir $ touch dir/{foo,bar,baz}.txt $ strace -e trace=lstat perl -E 'say $^V; ' v5.10.1 lstat("dir/baz.txt", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0 lstat("dir/bar.txt", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0 

Je vois le même comportement sur mon système Linux avec glob(pattern) et , et avec les versions ultérieures de perl.

J’espérais que la globulation opendirait simplement / readdir sous le capot, et qu’il ne serait pas nécessaire d’inspecter les chemins d’access réels qu’il cherchait.

Quel est le but de cet lstat ? Est-ce que cela affecte le retour de glob () s?

Ce comportement étrange a déjà été remarqué sur PerlMonks . Il s’avère que glob appelle lstat pour prendre en charge son indicateur GLOB_MARK , ce qui a pour effet que:

Chaque chemin d’access correspondant à un modèle a une barre oblique ajoutée.

Pour savoir si une entrée de répertoire fait référence à un sous-répertoire, vous devez le configurer. Ceci est apparemment fait même quand le drapeau n’est pas donné.

Je me demandais la même chose – “Quel est le but de cette lstat? Est-ce que cela affecte le retour de glob () s?”

Dans bsd_glob.c glob2 (), j’ai remarqué un appel à g_stat dans une twig if qui nécessitait que l’indicateur GLOB_MARK soit défini. J’ai également remarqué un appel à g_lstat juste avant que cela ne soit protégé par un contrôle de drapeau. Les deux sont dans une twig if pour quand la fin du pattern est atteinte. Si je supprime ces 2 lignes dans la fonction glob2 dans perl-5.12.4 / ext / File-Glob / bsd_glob.c

 - if (g_lstat(pathbuf, &sb, pglob)) - return(0); 

le seul test perl (make test) qui échoue est le test 5 dans ext / File-Glob / t / basic.t avec:

 not ok 5 # Failed test at ../ext/File-Glob/t/basic.t line 92. # Structures begin differing at: # $got->[0] = 'asdfasdf' # $expected->[0] = Does not exist 

Test 5 en t / basic.t est

 # check nonexistent checks # should return an empty list # XXX since errfunc is NULL on win32, this test is not valid there @a = bsd_glob("asdfasdf", 0); SKIP: { skip $^O, 1 if $^O eq 'MSWin32' || $^O eq 'NetWare'; is_deeply(\@a, []); } 

Si je remplace les 2 lignes supprimées par:

 + if (!((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR)))){ + if (g_lstat(pathbuf, &sb, pglob)) + return(0); + } 

Je ne vois aucune défaillance de “make test” pour perl-5.12.4 sur linux x86_64 (RHEL6.3 2.6.32-358.11.1.el6.x86_64) et en utilisant:

 strace -fe trace=lstat perl -e 'use File::Glob q{:glob}; print scalar bsd_glob(q{/var/log/*},GLOB_NOCHECK)' 

Je ne vois plus les appels lstat pour chaque fichier dans le répertoire. Je ne veux pas suggérer que les tests perl pour glob (File-Glob) sont complets (ils ne le sont pas), ou qu’un tel changement ne va pas casser un comportement existant (cela semble probable). Autant que je puisse dire, le code avec cet appel (g_l) stat existait dans original-bsd / lib / libc / gen / glob.c il y a 24 ans en 1990.

Regarde aussi:

  • Chapitre 6. Analyse comparative Perl de “Mastering Perl” Par Brian D foy, Randal L. Schwartz contient une section sur la comparaison du code où le code utilisant glob () et opendir () est comparé.
  • “futurs globs (était” UNIX mindset … “)” dans comp.unix.wizards de Dick Dunn en 1991.
  • Usenet newsgroup mod.sources “Routine de bibliothèque (glob)” de Guido van Rossum en juillet 1986 – Je ne vois aucune référence à “stat” dans ce code.