[lttng-dev] [PATCH lttng-tools 1/2] Fix: d_type validity is not guaranteed on all nfs versions

Jonathan Rajotte jonathan.rajotte-julien at efficios.com
Fri Mar 18 17:20:48 UTC 2016


When using lttng-crash on files mounted on a nfs mount the d_type from the dirent
struct is not necessarily set and result in DT_UNKNOWN d_type.

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

Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien at efficios.com>
---
 src/bin/lttng-crash/lttng-crash.c | 80 +++++++++++++++++++++++++++++----------
 1 file changed, 61 insertions(+), 19 deletions(-)

diff --git a/src/bin/lttng-crash/lttng-crash.c b/src/bin/lttng-crash/lttng-crash.c
index 653e4d0..8eddbd9 100644
--- a/src/bin/lttng-crash/lttng-crash.c
+++ b/src/bin/lttng-crash/lttng-crash.c
@@ -976,6 +976,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 */
@@ -984,6 +985,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");
@@ -991,13 +995,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];
 
@@ -1029,22 +1054,17 @@ 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);
 				if (ret) {
 					WARN("Error extracting trace '%s', continuing anyway.",
 						input_path);
-					has_warning = 1;
+					has_warning = 2;
 				}
 			}
-			/* Ignore other files */
-			break;
-		default:
+		} else {
 			has_warning = 1;
 			goto end;
 		}
@@ -1062,6 +1082,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 */
@@ -1071,6 +1092,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");
@@ -1079,13 +1103,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) {
@@ -1106,16 +1151,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;
 		}
-- 
2.7.0



More information about the lttng-dev mailing list