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 <sitsofe@yahoo.com>
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++;
*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;
}
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;
}