From 7273058c66b82508c5935f8c59c382db225383ae Mon Sep 17 00:00:00 2001 From: Sitsofe Wheeler Date: Sun, 1 Mar 2020 18:27:19 +0000 Subject: [PATCH] filesetup: fix win raw disk access and improve dir creation failure msg The commit df18600fd06258b96ae6f6b530ecdff541c2a82d ("filesetup: fix directory creation issues") broke Windows raw/physical disk access because Windows doesn't consider a path that only consists of a namespace (such as the device namespace "\\.\" - see https://docs.microsoft.com/en-gb/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#namespaces for information on Windows' namespaces) to exist as a directory(!). Workaround the issue for raw devices by explicitly considering the device namespace subcomponent to always be valid. Further, intermediate path components in UNC paths or paths starting with a namespace might also not "exist" so introduce backwards scanning for the longest pre-existing directory to sidestep this. The function doing this is made available for non-windows platforms so a similar code path is used everywhere. Tests done: Windows: > ./fio.exe --name=dtest --thread --size=16k --rw=write ` --filename 'fio.tmp' > ./fio.exe --name=dtest --thread --size=16k --rw=write ` --filename '\\?\C\:\Windows\Temp\fio\fio.tmp' > Clear-Disk 1 -RemoveData -Confirm:$false # Destroys partition data! > ./fio.exe --name=dtest --thread --size=16k --rw=write ` --filename '\\.\PhysicalDrive1' > ./fio.exe --name=dtest --thread --size=16k --rw=write ` --filename '\fio.tmp' > ./fio.exe --name=dtest --thread --size=16k --rw=write ` --filename '\\LOCALHOST\Users\User\fio\fio.tmp' macOS: $ rm -rf /tmp/fio $ ./fio --name=dtest --size=16k --filename /tmp/fio/fio.tmp \ --rw=write Finally, change the directory creation error message to give a human error message rather than just an errno. Fixes: https://github.com/axboe/fio/issues/916 Signed-off-by: Sitsofe Wheeler --- filesetup.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++--- os/os-windows.h | 6 +++++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/filesetup.c b/filesetup.c index b45a5826..8a4091fc 100644 --- a/filesetup.c +++ b/filesetup.c @@ -913,15 +913,61 @@ uint64_t get_start_offset(struct thread_data *td, struct fio_file *f) return offset; } +/* + * Find longest path component that exists and return its length + */ +int longest_existing_path(char *path) { + char buf[PATH_MAX]; + bool done; + char *buf_pos; + int offset; +#ifdef WIN32 + DWORD dwAttr; +#else + struct stat sb; +#endif + + sprintf(buf, "%s", path); + done = false; + while (!done) { + buf_pos = strrchr(buf, FIO_OS_PATH_SEPARATOR); + if (!buf_pos) { + done = true; + offset = 0; + break; + } + + *(buf_pos + 1) = '\0'; + +#ifdef WIN32 + dwAttr = GetFileAttributesA(buf); + if (dwAttr != INVALID_FILE_ATTRIBUTES) { + done = true; + } +#else + if (stat(buf, &sb) == 0) + done = true; +#endif + if (done) + offset = buf_pos - buf; + else + *buf_pos = '\0'; + } + + return offset; +} + static bool create_work_dirs(struct thread_data *td, const char *fname) { char path[PATH_MAX]; char *start, *end; + int offset; snprintf(path, PATH_MAX, "%s", fname); start = path; - end = start; + offset = longest_existing_path(path); + end = start + offset; while ((end = strchr(end, FIO_OS_PATH_SEPARATOR)) != NULL) { if (end == start) { end++; @@ -930,8 +976,8 @@ static bool create_work_dirs(struct thread_data *td, const char *fname) *end = '\0'; errno = 0; if (fio_mkdir(path, 0700) && errno != EEXIST) { - log_err("fio: failed to create dir (%s): %d\n", - start, errno); + log_err("fio: failed to create dir (%s): %s\n", + start, strerror(errno)); return false; } *end = FIO_OS_PATH_SEPARATOR; diff --git a/os/os-windows.h b/os/os-windows.h index 6d48ffe8..fa2955f9 100644 --- a/os/os-windows.h +++ b/os/os-windows.h @@ -203,7 +203,11 @@ static inline int fio_mkdir(const char *path, mode_t mode) { } if (CreateDirectoryA(path, NULL) == 0) { - log_err("CreateDirectoryA = %d\n", GetLastError()); + /* Ignore errors if path is a device namespace */ + if (strcmp(path, "\\\\.") == 0) { + errno = EEXIST; + return -1; + } errno = win_to_posix_error(GetLastError()); return -1; } -- 2.25.1