On Sat, Jan 22, 2011 at 10:28:33PM +0100, Pavel Sanda wrote:

> Enrico Forestieri wrote:
> > On Sat, Jan 22, 2011 at 01:53:40AM +0100, Pavel Sanda wrote:
> > 
> > > this patch should help at least for symlinks.
> > 
> > Why not restricting the workaround to the case where the file actually
> > is stored on an ext4 file system?
> 
> in principle i'm all for it. i would just rename the method to
> isOnTheDamnedExt4().

If you want to pursue that approach, I attach here a small C program that
could be used for writing a isOnTheDamnedExt4() method.
It turned out that this is quite platform dependent. I tried to address all
supported platforms (linux, mac, cygwin), plus solaris and the *BSD variants.
I am sure that there are other *nix flavors out there that do things
still differently, but the fact that isOnTheDamnedExt4() returns false
for them should not be a big problem.
Of course, the hardcoded defines (now tied to particular platforms) should
be replaced by proper configure checks, but that would be easily achieved.
The code should go in the support/os_*.cpp files, and for Win32 the method
would simply return false.
I tested the program on linux, solaris, and cygwin. I cannot test it
neither on Mac, nor on the various *BSD variants, so someone else should
confirm that it is OK also on those platforms.

-- 
Enrico
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <unistd.h>

#if defined(__linux__) || defined(__CYGWIN__)
# define HAVE_GETMNTENT1
#elif defined(__svr4__)
# define HAVE_GETMNTENT2
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
# define HAVE_GETMNTINFO
# if defined(__NetBSD__)
#  define HAVE_STRUCT_STATVFS_F_FSTYPENAME
#  include <sys/statvfs.h>
# endif
#endif

#ifdef HAVE_GETMNTENT1
# include <mntent.h>
# if !defined(MOUNTED)
#  if defined(_PATH_MOUNTED)
#   define MOUNTED _PATH_MOUNTED
#  endif
#  if defined(MNT_MNTTAB)
#   define MOUNTED MNT_MNTTAB
#  endif
#  if defined(MNTTABNAME)
#   define MOUNTED MNTTABNAME
#  endif
# endif
#endif

#ifdef HAVE_GETMNTENT2
# include <sys/mnttab.h>
# if !defined(MOUNTED)
#  define MOUNTED MNTTAB
# endif
#endif

#ifdef HAVE_GETMNTINFO
# include <sys/param.h>
# include <sys/ucred.h>
# include <sys/mount.h>
#endif

int main(int ac, char **av)
{
    char fstype[128];
    char rpath[PATH_MAX + 1];
    FILE *mtab;
    size_t rlen;
    size_t mlen;

    if (ac != 2) {
        printf("Usage: %s <path>\n", av[0]);
        return 0;
    }

    if (!realpath(av[1], rpath)) {
        printf("realpath() failed on %s\n", av[1]);
        exit(1);
    }

    rlen = strlen(rpath);
    fstype[0] = '\0';
    mlen = 0;

#if defined(HAVE_GETMNTENT1)
    {
        struct mntent *me;
        mtab = setmntent(MOUNTED, "r");
        while ((me = getmntent(mtab))) {
            size_t len = strlen(me->mnt_dir);
            if (mlen <= len && len <= rlen
                && (len == 1 || ((len == rlen || rpath[len] == '/')
                                 && strncmp(me->mnt_dir, rpath, len) == 0))) {
                strncpy(fstype, me->mnt_type, sizeof(fstype));
                fstype[sizeof(fstype) - 1] = '\0';
                mlen = len;
            }
        }
        endmntent(mtab);
    }
#elif defined(HAVE_GETMNTENT2)
    mtab = fopen(MOUNTED, "r");
    if (mtab) {
        struct mnttab me;
        int ret;
        while ((ret = getmntent(mtab, &me)) == 0) {
            size_t len = strlen(me.mnt_mountp);
            if (mlen <= len && len <= rlen
                && (len == 1 || ((len == rlen || rpath[len] == '/')
                                 && strncmp(me.mnt_mountp, rpath, len) == 0))) {
                strncpy(fstype, me.mnt_fstype, sizeof(fstype));
                fstype[sizeof(fstype) - 1] = '\0';
                mlen = len;
            }
        }
        fclose(mtab);
    }
#elif defined(HAVE_GETMNTINFO)
    {
# ifdef HAVE_STRUCT_STATVFS_F_FSTYPENAME
        struct statvfs *me;
# else
        struct statfs *me;
# endif
        int numentries = getmntinfo(&me, MNT_NOWAIT);
        for (; numentries > 0; --numentries, ++me) {
            size_t len = strlen(me->f_mntonname);
            if (mlen <= len && len <= rlen
                && (len == 1 || ((len == rlen || rpath[len] == '/')
                                 && strncmp(me->f_mntonname, rpath, len) == 
0))) {
                strncpy(fstype, me->f_fstypename, sizeof(fstype));
                fstype[sizeof(fstype) - 1] = '\0';
                mlen = len;
            }
        }
    }
#endif

    if (fstype[0])
        printf("fs type: %s\n", fstype);
    else
        printf("Cannot determine fs type!\n");

    return 0;
}

Reply via email to