Fix cannot create Windows directory in root (#20311)
* Fix cannot create Windows directory in root
Fixes #20306, a regression bug with `createDir` caused by
`23e0160af2`.
The issue is that, if the path consists only of a drive and a single
directory (e.g. "Y:\nimcache2" in the original issue), then no
directories will be created. This works fine if there are multiple
directories (e.g. "Y:\nimcache2\test").
In the case of "Y:\nimcache2", `omitNext` in `createDir` is `false` on
the last condition in `createDir`. This means that the "nimcache2"
directory will not be created, and no exception will be raised.
Fixed by refactoring to use `parentDirs` iterator instead of iterating
over the string characters. Motivation is reduced code complexity.
Will not test the specific "C:\test" `createDir` case, since there is no
standard Windows drive with write permissions in the root. Creating a
custom drive-mapping to Windows Temp is a non-option. That could mess
up some users running the test.
Added `parentDirs` tests since they are lacking on for POSIX paths.
* Fix `createDir("")` causing error
The change to `createDir` caused `createDir("")` to raise an error,
where it previously didn't. Fixed so `createDir("")` does not fail, and
added test case.
This commit is contained in:
parent
088487f652
commit
68f92af17c
2 changed files with 26 additions and 20 deletions
|
|
@ -2553,25 +2553,14 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1",
|
||||||
## * `copyDir proc`_
|
## * `copyDir proc`_
|
||||||
## * `copyDirWithPermissions proc`_
|
## * `copyDirWithPermissions proc`_
|
||||||
## * `moveDir proc`_
|
## * `moveDir proc`_
|
||||||
var omitNext = false
|
if dir == "":
|
||||||
when doslikeFileSystem:
|
return
|
||||||
var start = 1
|
var omitNext = isAbsolute(dir)
|
||||||
if isAbsolute(dir):
|
for p in parentDirs(dir, fromRoot=true):
|
||||||
omitNext = true
|
|
||||||
start = dir.splitDrive.drive.len + 1
|
|
||||||
else:
|
|
||||||
let start = 1
|
|
||||||
for i in start.. dir.len-1:
|
|
||||||
if dir[i] in {DirSep, AltSep}:
|
|
||||||
if omitNext:
|
if omitNext:
|
||||||
omitNext = false
|
omitNext = false
|
||||||
else:
|
else:
|
||||||
discard existsOrCreateDir(substr(dir, 0, i-1))
|
discard existsOrCreateDir(p)
|
||||||
|
|
||||||
# The loop does not create the dir itself if it doesn't end in separator
|
|
||||||
if dir.len > 0 and not omitNext and
|
|
||||||
dir[^1] notin {DirSep, AltSep}:
|
|
||||||
discard existsOrCreateDir(dir)
|
|
||||||
|
|
||||||
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
|
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} =
|
tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} =
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,9 @@ block fileOperations:
|
||||||
doAssert fileExists("../dest/a/file.txt")
|
doAssert fileExists("../dest/a/file.txt")
|
||||||
removeDir("../dest")
|
removeDir("../dest")
|
||||||
|
|
||||||
|
# createDir should not fail if `dir` is empty
|
||||||
|
createDir("")
|
||||||
|
|
||||||
# Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`,
|
# Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`,
|
||||||
# `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`.
|
# `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`.
|
||||||
block:
|
block:
|
||||||
|
|
@ -712,8 +715,10 @@ block: # isAdmin
|
||||||
# In Azure on POSIX tests run as a normal user
|
# In Azure on POSIX tests run as a normal user
|
||||||
if isAzure and defined(posix): doAssert not isAdmin()
|
if isAzure and defined(posix): doAssert not isAdmin()
|
||||||
|
|
||||||
|
import std/sequtils
|
||||||
|
|
||||||
when doslikeFileSystem:
|
when doslikeFileSystem:
|
||||||
import std/[sequtils, private/ntpath]
|
import std/private/ntpath
|
||||||
|
|
||||||
block: # Bug #19103 UNC paths
|
block: # Bug #19103 UNC paths
|
||||||
|
|
||||||
|
|
@ -775,3 +780,15 @@ when doslikeFileSystem:
|
||||||
doAssert splitFile("//?/c:") == ("//?/c:", "", "")
|
doAssert splitFile("//?/c:") == ("//?/c:", "", "")
|
||||||
doAssert splitFile("//?/c:/Users") == ("//?/c:", "Users", "")
|
doAssert splitFile("//?/c:/Users") == ("//?/c:", "Users", "")
|
||||||
doAssert splitFile(r"\\localhost\c$\test.txt") == (r"\\localhost\c$", "test", ".txt")
|
doAssert splitFile(r"\\localhost\c$\test.txt") == (r"\\localhost\c$", "test", ".txt")
|
||||||
|
|
||||||
|
else:
|
||||||
|
block: # parentDirs
|
||||||
|
doAssert parentDirs("/home", fromRoot=true).toSeq == @["/", "/home"]
|
||||||
|
doAssert parentDirs("/home", fromRoot=false).toSeq == @["/home", "/"]
|
||||||
|
doAssert parentDirs("home", fromRoot=true).toSeq == @["home"]
|
||||||
|
doAssert parentDirs("home", fromRoot=false).toSeq == @["home"]
|
||||||
|
|
||||||
|
doAssert parentDirs("/home/user", fromRoot=true).toSeq == @["/", "/home/", "/home/user"]
|
||||||
|
doAssert parentDirs("/home/user", fromRoot=false).toSeq == @["/home/user", "/home", "/"]
|
||||||
|
doAssert parentDirs("home/user", fromRoot=true).toSeq == @["home/", "home/user"]
|
||||||
|
doAssert parentDirs("home/user", fromRoot=false).toSeq == @["home/user", "home"]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue