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; }