Fix: d_type validity is not guaranteed on all nfs versions
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Thu, 17 Mar 2016 18:56:02 +0000 (14:56 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 4 Apr 2016 15:26:19 +0000 (11:26 -0400)
When using lttng-crash on files mounted on a nfs mount the d_type from
the dirent struct is not necessarily set and results in a DT_UNKNOWN
d_type.

stat() provides the valid information on an nfs mount.

Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/bin/lttng-crash/lttng-crash.c

index 13d136da96e845e8c78e23870caa507b7e708f3e..65fca36ae264c2e25f7d0437840a4a8f194f67b7 100644 (file)
@@ -965,6 +965,7 @@ int extract_trace_recursive(const char *output_path,
        DIR *dir;
        int dir_fd, ret = 0, closeret;
        struct dirent *entry;
+       size_t path_len;
        int has_warning = 0;
 
        /* Open directory */
@@ -973,6 +974,9 @@ int extract_trace_recursive(const char *output_path,
                PERROR("Cannot open '%s' path", input_path);
                return -1;
        }
+
+       path_len = strlen(input_path);
+
        dir_fd = dirfd(dir);
        if (dir_fd < 0) {
                PERROR("dirfd");
@@ -980,13 +984,34 @@ int extract_trace_recursive(const char *output_path,
        }
 
        while ((entry = readdir(dir))) {
+               struct stat st;
+               size_t name_len;
+               char filename[PATH_MAX];
+
                if (!strcmp(entry->d_name, ".")
                                || !strcmp(entry->d_name, "..")) {
                        continue;
                }
-               switch (entry->d_type) {
-               case DT_DIR:
-               {
+
+               name_len = strlen(entry->d_name);
+               if (path_len + name_len + 2 > sizeof(filename)) {
+                       ERR("Failed to remove file: path name too long (%s/%s)",
+                               input_path, entry->d_name);
+                       continue;
+               }
+
+               if (snprintf(filename, sizeof(filename), "%s/%s",
+                               input_path, entry->d_name) < 0) {
+                       ERR("Failed to format path.");
+                       continue;
+               }
+
+               if (stat(filename, &st)) {
+                       PERROR("stat");
+                       continue;
+               }
+
+               if (S_ISDIR(st.st_mode)) {
                        char output_subpath[PATH_MAX];
                        char input_subpath[PATH_MAX];
 
@@ -1018,10 +1043,7 @@ int extract_trace_recursive(const char *output_path,
                        if (ret) {
                                has_warning = 1;
                        }
-                       break;
-               }
-               case DT_REG:
-               case DT_LNK:
+               } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
                        if (!strcmp(entry->d_name, "metadata")) {
                                ret = extract_one_trace(output_path,
                                        input_path);
@@ -1031,9 +1053,7 @@ int extract_trace_recursive(const char *output_path,
                                        has_warning = 1;
                                }
                        }
-                       /* Ignore other files */
-                       break;
-               default:
+               } else {
                        has_warning = 1;
                        goto end;
                }
@@ -1051,6 +1071,7 @@ int delete_dir_recursive(const char *path)
 {
        DIR *dir;
        int dir_fd, ret = 0, closeret;
+       size_t path_len;
        struct dirent *entry;
 
        /* Open trace directory */
@@ -1060,6 +1081,9 @@ int delete_dir_recursive(const char *path)
                ret = -errno;
                goto end;
        }
+
+       path_len = strlen(path);
+
        dir_fd = dirfd(dir);
        if (dir_fd < 0) {
                PERROR("dirfd");
@@ -1068,13 +1092,34 @@ int delete_dir_recursive(const char *path)
        }
 
        while ((entry = readdir(dir))) {
+               struct stat st;
+               size_t name_len;
+               char filename[PATH_MAX];
+
                if (!strcmp(entry->d_name, ".")
                                || !strcmp(entry->d_name, "..")) {
                        continue;
                }
-               switch (entry->d_type) {
-               case DT_DIR:
-               {
+
+               name_len = strlen(entry->d_name);
+               if (path_len + name_len + 2 > sizeof(filename)) {
+                       ERR("Failed to remove file: path name too long (%s/%s)",
+                               path, entry->d_name);
+                       continue;
+               }
+
+               if (snprintf(filename, sizeof(filename), "%s/%s",
+                               path, entry->d_name) < 0) {
+                       ERR("Failed to format path.");
+                       continue;
+               }
+
+               if (stat(filename, &st)) {
+                       PERROR("stat");
+                       continue;
+               }
+
+               if (S_ISDIR(st.st_mode)) {
                        char *subpath = zmalloc(PATH_MAX);
 
                        if (!subpath) {
@@ -1095,16 +1140,13 @@ int delete_dir_recursive(const char *path)
                                /* Error occured, abort traversal. */
                                goto end;
                        }
-                       break;
-               }
-               case DT_REG:
+               } else if (S_ISREG(st.st_mode)) {
                        ret = unlinkat(dir_fd, entry->d_name, 0);
                        if (ret) {
                                PERROR("Unlinking '%s'", entry->d_name);
                                goto end;
                        }
-                       break;
-               default:
+               } else {
                        ret = -EINVAL;
                        goto end;
                }
This page took 0.028768 seconds and 5 git commands to generate.