perlfilesystemsxs

How do I get f_type from statfs?


I need to get f_type from statfs. I tried patching Filesys::Df:

---
 Df.pm       | 6 +++---
 Makefile.PL | 7 +------
 XS_statfs   | 1 +
 3 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/Df.pm b/Df.pm
index b24bd9c..986082a 100644
--- a/Df.pm
+++ b/Df.pm
@@ -28,7 +28,7 @@ my %fs = ();
    ($block_size) ||
        ($block_size = 1024);

-   my ($frsize, $blocks, $bfree, $bavail, $files, $ffree, $favail);
+   my ($frsize, $blocks, $bfree, $bavail, $files, $ffree, $favail, $ftype);

    #### If open filehandle call fstatvfs or fstatfs
    if(defined(fileno($dir))) {
@@ -36,7 +36,7 @@ my %fs = ();
    }

    else {
-       ($frsize, $blocks, $bfree, $bavail, $files, $ffree, $favail) = _df($dir);
+       ($frsize, $blocks, $bfree, $bavail, $files, $ffree, $favail, $ftype) = _df($dir);
    }


@@ -199,7 +199,7 @@ my %fs = ();
         #        $fs{user_files}  = undef;
         #}

-
+    $fs{type} = $ftype;
    return(\%fs);
 }

diff --git a/Makefile.PL b/Makefile.PL
index 6a89ec4..e91cbb3 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -21,12 +21,7 @@ if($Config{osname} =~ /^MSWin/i) {
    die "You might try Filesys::DfPortable instead.\n";
 }

-#### Check for the existance of statvfs
-if(check_statvfs()) {
-   ####$define .= "-DDF_STATVFS ";
-   copy_xs("XS_statvfs", $xs_file);
-   print "Building with statvfs ....\n";
-}
+# force statfs

 #### Check for the existance of statfs
 elsif(check_statfs()) {
diff --git a/XS_statfs b/XS_statfs
index 856c646..ef801c3 100644
--- a/XS_statfs
+++ b/XS_statfs
@@ -45,6 +45,7 @@ _df(dir)
        PUSHs(sv_2mortal(newSVnv((double)st.f_ffree)));
        /* No favail */
        PUSHs(sv_2mortal(newSVnv((double)st.f_ffree)));
+       PUSHs(sv_2mortal(newSVnv((double)st.f_type)));
    }

    else {
-- 
2.21.0

followed by

perl Makefile.PL ; make ; perl -Mblib -MFilesys::Df=df -E'say df("/")->{type}'

but that crashes

panic: XSUB Filesys::Df::_df (Df.c) failed to extend arg stack: base=11d3b10, sp=11d3b50, hwm=11d3b48

How do I solve this problem?


Solution

  • Unlike XPUSH*, PUSH* doesn't ensure there's enough room on the stack.

    PUSHs

    Push an SV onto the stack. The stack must have room for this element. Does not handle 'set' magic. Does not use TARG. See also PUSHmortal, XPUSHs, and XPUSHmortal.

    void PUSHs(SV* sv)
    

    To ensure there's enough space for the additional value being returned, simply replace

    EXTEND(sp, 7)
    

    with

    EXTEND(sp, 8)
    

    EXTEND

    Used to extend the argument stack for an XSUB's return values. Once used, guarantees that there is room for at least nitems to be pushed onto the stack.

    void EXTEND(SP, SSize_t nitems)
    

    Tip:

    PUSHs(sv_2mortal(newSVnv((double)st.f_type)));
    

    should be

    PUSHs(sv_2mortal(newSVnv((NV)st.f_type)));
    

    That can be shortened to

    mPUSHs(newSVnv((NV)st.f_type));
    

    And that can be shortened to

    mPUSHn((NV)st.f_type);
    

    I realize you're creating a minimal patch and that you're striving for consistency, but this could benefit you and other readers in other situations.