Skip to content

[patch] automatic device finding on Mac and Linux #27

@RJVB

Description

@RJVB

Currently hfsinspect will find the device a file is on automatically only on BSD. The author seems to have missed the fact that Apple's Darwin is a BSD variant, and indeed the code works just fine there (on 10.9 at least). Fortunately, because for me the manual specification didn't work.

Linux doesn't have a single syscall that returns the required information, but one can parse the output from df -h.

Here's a patch (corrected):

diff --git a/src/hfsinspect.c b/src/hfsinspect.c
index fb380bf..019724a 100644
--- a/src/hfsinspect.c
+++ b/src/hfsinspect.c
@@ -14,6 +14,9 @@
 #if defined(BSD)
     #include <sys/mount.h>     //statfs
 #endif
+#ifdef __linux__
+    #include <ctype.h>
+#endif
 
 #include "logging/logging.h"   // console printing routines
 #include "volumes/volumes.h"
@@ -69,13 +72,13 @@ char* deviceAtPath(char* path)
 
 bool resolveDeviceAndPath(char* path_in, char* device_out, char* path_out)
 {
-#if defined(__BSD__)
     char* path = realpath(path_in, NULL);
     if (path == NULL) {
         die(1, path_in);
         return false;
     }
 
+#if defined(__BSD__) || defined(__APPLE__)
     struct statfs stats;
     int           result = statfs(path_in, &stats);
     if (result < 0) {
@@ -110,6 +113,60 @@ bool resolveDeviceAndPath(char* path_in, char* device_out, char* path_out)
     debug("Path out: %s", path_out);
 
     return true;
+#elif defined(__linux__)
+    bool ret = false;
+    char *command = NULL;
+    int comlen = asprintf(&command, "df -h \"%s\" | tail --lines=1", path_in);
+    FILE *fp = comlen > 0 ? popen(command, "r") : NULL;
+    if (fp) {
+        char buf[PATH_MAX * 3], *s = buf;
+        if (fgets(buf, sizeof(buf), fp) == buf) {
+            char *d = device_out;
+            s = buf;
+            while (*s && !isspace(*s)) {
+                *d++ = *s++;
+            }
+            if (isspace(*s)) {
+                *d = '\0';
+            } else {
+                warning("%s: failure reading mount device from \"%s\"", __FUNCTION__, buf);
+                device_out[0] = '\0';
+            }
+            s = strstr(buf, "% /");
+            if (s) {
+                char* mountPoint = &s[2];
+                size_t len = strlen(mountPoint);
+                if (len > 0 && mountPoint[len-1] == '\n') {
+                    mountPoint[len-1] = '\0';
+                    len -= 1;
+                }
+                if (strncmp(mountPoint, "/", PATH_MAX) != 0) {
+                    // Remove mount point from path name (rather blindly, yes)
+                    d = &path[len];
+                    (void)strlcpy(path_out, &path[len], PATH_MAX);
+                } else {
+                    (void)strlcpy(path_out, path, PATH_MAX);
+                }
+                free(path);
+                ret = true;
+            } else {
+                warning("%s: failure reading mountPoint from \"%s\"", __FUNCTION__, buf);
+                path_out[0] = '\0';
+            }
+        } else {
+            perror(command);
+        }
+        pclose(fp);
+        debug("Path in: %s", path_in);
+        debug("Device out: %s", device_out);
+        debug("Path out: %s", path_out);
+    } else {
+        perror(command ? command : path_in);
+    }
+    if (comlen) {
+        free(command);
+    }
+    return ret;
 #else
     warning("%s: not supported on this platform", __FUNCTION__);
     return false;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions