Here's a solution worth at _least_ $20.00. (What a whore I am :)

list_dir() returns a list of arrays which contain this information about
the directory entries:

1. Full pathname
2. File type (DIR, REG, LNK, CHR, BLK, FIFO, SOCK, or ???)
3. Device number
4. Inode number
5. Owner's UID
6. Owner's GID
7. Size of the file
8. Access time
9. Modification time
10. Change time
11. Can _this script_ read this file?
12. Can _this script_ write to this file?
13. Can _this script_ execute this file?

If you want more information about the file, just stick it in the array
from the C section.

Here's an example usage:

----8<----
use Inline C;
use Data::Dumper;
my @list = list_dir('/');
print Dumper \@list;
__END__
__C__
... see attached script
---->8----

Here's the first few lines of output, edited for brevity:

----8<----
$VAR1 = [
          [
            '/lost+found', 'DIR', 2050, 11, 2, 0, 0, 16384,
            992343723, 967726697, 967726697,
            1, 0, 1
          ],
          [
            '/var', 'DIR', 2053, 2, 20, 0, 0, 1024,
            992343723, 967753497, 967753497,
            1, 0, 1
          ],
          [
            '/proc', 'DIR', 1, 1, 83, 0, 0, 0,
            992010074, 992010074, 992010074,
            1, 0, 1
          ],
---->8----

Later,
Neil

use Inline C;
use Data::Dumper;

my $path = shift || '/';
$path .= "/" unless substr($path, -1) eq '/';
my @list = list_dir($path);

print Dumper \@list;

__END__
__C__

/* All code made up -- distribute freely */
static void _perm(AV *l, struct stat *s) {
    uid_t uid, gid;
    SV *can_r, *can_w, *can_x;

    uid = getuid();
    gid = getgid();

    if (uid == s->st_uid) {
        can_r = newSViv( (s->st_mode & S_IRUSR) ? 1 : 0);
        can_w = newSViv( (s->st_mode & S_IWUSR) ? 1 : 0);
        can_x = newSViv( (s->st_mode & S_IXUSR) ? 1 : 0);
    }
    else if (gid == s->st_gid) {
        can_r = newSViv( (s->st_mode & S_IRGRP) ? 1 : 0);
        can_w = newSViv( (s->st_mode & S_IWGRP) ? 1 : 0);
        can_x = newSViv( (s->st_mode & S_IXGRP) ? 1 : 0);
    }
    else {
        can_r = newSViv( (s->st_mode & S_IROTH) ? 1 : 0);
        can_w = newSViv( (s->st_mode & S_IWOTH) ? 1 : 0);
        can_x = newSViv( (s->st_mode & S_IXOTH) ? 1 : 0);
    }
    av_push(l, can_r);
    av_push(l, can_w);
    av_push(l, can_x);
}

/* pre-condition: path has a trailing slash */
void list_dir(char *path) {
    DIR *dir;
    struct dirent *entry;
    struct stat stat_buf;
    SV *fullname = sv_2mortal(newSVpv("", 0));
    Inline_Stack_Vars;

    if (path==NULL)
      return;
    if ((dir = opendir(path)) == NULL)
      croak("%s: %s\n", path, strerror(errno));

    Inline_Stack_Reset;
    while ((entry = readdir(dir)) != NULL) {
        AV *s_info;

        /* skip current directory & parent directory */
        if (strcmp(entry->d_name, ".")  == 0 ||
            strcmp(entry->d_name, "..") == 0)
          continue;

        /* save the full pathname (extra slashes are ignored in Linux) */
        sv_setpvf(fullname, "%s%s", path, entry->d_name);

        /* stat the file (without following symlinks) */
        if (lstat(SvPV(fullname, PL_na), &stat_buf)) {
            warn("%s: %s\n", SvPV(fullname, PL_na), strerror(errno));
            continue;
        }

        /* Build some info about it:
           [ NAME, TYPE, DEV, INODE, NLINK, UID, GID, SIZE, 
             ATIME, MTIME, CTIME, R, W, X ]
         */
        s_info = newAV();
        av_push(s_info, newSVsv(fullname));
        av_push(s_info, newSVpv((S_ISLNK(stat_buf.st_mode) ? "LNK" :
                                 S_ISREG(stat_buf.st_mode) ? "REG" : 
                                 S_ISDIR(stat_buf.st_mode) ? "DIR" : 
                                 S_ISCHR(stat_buf.st_mode) ? "CHR" :
                                 S_ISBLK(stat_buf.st_mode) ? "BLK" :
                                 S_ISFIFO(stat_buf.st_mode) ? "FIFO" :
                                 S_ISSOCK(stat_buf.st_mode) ? "SOCK" : "???"),
                                0));
        av_push(s_info, newSViv(stat_buf.st_dev));
        av_push(s_info, newSViv(stat_buf.st_ino));
        av_push(s_info, newSViv(stat_buf.st_nlink));
        av_push(s_info, newSViv(stat_buf.st_uid));
        av_push(s_info, newSViv(stat_buf.st_gid));
        av_push(s_info, newSViv(stat_buf.st_size));
        av_push(s_info, newSViv(stat_buf.st_atime));
        av_push(s_info, newSViv(stat_buf.st_mtime));
        av_push(s_info, newSViv(stat_buf.st_ctime));
        _perm(s_info, &stat_buf);

        /* Return the info */
        Inline_Stack_Push(newRV_noinc((SV*)s_info));
    }
    Inline_Stack_Done;
}

Reply via email to