Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re: readdir() on a sysopen() handle?

by afoken (Chancellor)
on Aug 20, 2017 at 13:05 UTC ( [id://1197699]=note: print w/replies, xml ) Need Help??


in reply to readdir() on a sysopen() handle?

Looking through several linux man pages, it looks like you normally should use opendir, readdir or scandir, and closedir from C. Those functions are specified by POSIX and are portable. But the glibc also offers fdopendir that converts a plain integer file descriptor to a DIR *. So in C, something like this should work:

/* UNTESTED! */ DIR * d opendir_nofollow(const char * pathname) { int fd = open(pathname, O_DIRECTORY | O_NOFOLLOW); if (fd == -1) { return NULL; } return fdopendir(fd); }

Converting that to a perl directory handle will very likely require a little bit of XS code. Perhaps Inline::C might be helpful. You definitively want to have a look at the perl sources, the part that implements the opendir function, to see how to correctly create a directory handle.

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Replies are listed 'Best First'.
Re^2: readdir() on a sysopen() handle?
by haukex (Archbishop) on Aug 20, 2017 at 14:25 UTC

    As you wrote this I was actually fiddling with exactly that :-) The relevant Perl source appears to be pp_open_dir in pp_sys.c, which uses the IoDIRP macro, which apparently accesses the DIR * xiou_dirp slot of struct xpvio, but I can't seem to find any more documentation on it.

    Disclaimer: I am not an XS expert, I can't guarantee that the following is entirely correct! I got some of this from the Inline::C::Cookbook, a bit of research in perlapi, and a bit of fiddling...

    myreaddir does all of the work of opening and reading the directory in C, returning a Perl list, while _xs_myfdopendir with the Perl wrapper myfdopendir attempts to be a custom opendir.

    use warnings; use strict; use Inline C => <<'END_OF_C'; void myreaddir(SV* sv_dirn) { Inline_Stack_Vars; Inline_Stack_Reset; int fd = open( SvPVx(sv_dirn, PL_na), O_RDONLY|O_DIRECTORY|O_NOFOLLOW); if (fd<0) Inline_Stack_Return(0); DIR* dir = fdopendir(fd); if (dir==NULL) Inline_Stack_Return(0); struct dirent *dp; while ( (dp=readdir(dir)) != NULL ) Inline_Stack_Push(sv_2mortal( newSVpvf("%s", dp->d_name) )); if( closedir(dir)!=0 ) Inline_Stack_Return(0); Inline_Stack_Done; } int _xs_myfdopendir(SV* sv_dirn, SV* sv_hnd) { int fd = open( SvPVx(sv_dirn, PL_na), O_RDONLY|O_DIRECTORY|O_NOFOLLOW); if (fd<0) return 0; DIR* dir = fdopendir(fd); if (dir==NULL) return 0; IoDIRP(sv_2io(sv_hnd)) = dir; return 1; } END_OF_C use Symbol qw/geniosym/; use File::Spec; sub myfdopendir { return unless _xs_myfdopendir( $_[0]//File::Spec->curdir, my $dh=geniosym ); return $dh; } use Data::Dump; my @x = myreaddir('/tmp') or die $!; dd @x; my $dh = myfdopendir('/tmp') or die $!; dd readdir $dh; closedir $dh or die $!;

    Update: A couple of Perl modules that use XS to read directories, in particular the first one's readdir_hashref looks like it could be modified fairly simply: ReadDir, IO-Dirent, PerlIO-Util

       or die $! is wrong in my @x = myreaddir('/tmp') or die $!; because an empty list doesn't necessarily denote an error.

        Yes, that's a very good point, thanks. At least on Linux (and probably Windows), I believe even empty directories should return the list ('..', '.'), but your point that the error checking is lacking is still correct. Anyway, myfdopendir is probably better in that respect, I was just less sure on whether I got code for the Perl internals right on that one.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1197699]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (7)
As of 2024-04-16 10:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found