mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
2.5x- 3x faster copyFile on osx (#16883)
This commit is contained in:
@@ -121,6 +121,10 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior.
|
||||
|
||||
- `typetraits.distinctBase` now is identity instead of error for non distinct types.
|
||||
|
||||
- `os.copyFile` is now 2.5x faster on OSX, by using `copyfile` from `copyfile.h`;
|
||||
use `-d:nimLegacyCopyFile` for OSX < 10.5.
|
||||
|
||||
|
||||
## Compiler changes
|
||||
|
||||
- Added `--declaredlocs` to show symbol declaration location in messages.
|
||||
|
||||
@@ -1634,6 +1634,24 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
|
||||
var res2 = setFileAttributesA(filename, res)
|
||||
if res2 == - 1'i32: raiseOSError(osLastError(), $(filename, permissions))
|
||||
|
||||
const hasCCopyfile = defined(osx) and not defined(nimLegacyCopyFile)
|
||||
# xxx instead of `nimLegacyCopyFile`, support something like: `when osxVersion >= (10, 5)`
|
||||
|
||||
when hasCCopyfile:
|
||||
# `copyfile` API available since osx 10.5.
|
||||
{.push nodecl, header: "<copyfile.h>".}
|
||||
type
|
||||
copyfile_state_t {.nodecl.} = pointer
|
||||
copyfile_flags_t = cint
|
||||
proc copyfile_state_alloc(): copyfile_state_t
|
||||
proc copyfile_state_free(state: copyfile_state_t): cint
|
||||
proc c_copyfile(src, dst: cstring, state: copyfile_state_t, flags: copyfile_flags_t): cint {.importc: "copyfile".}
|
||||
# replace with `let` pending bootstrap >= 1.4.0
|
||||
var
|
||||
COPYFILE_DATA {.nodecl.}: copyfile_flags_t
|
||||
COPYFILE_XATTR {.nodecl.}: copyfile_flags_t
|
||||
{.pop.}
|
||||
|
||||
proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
tags: [ReadIOEffect, WriteIOEffect], noWeirdTarget.} =
|
||||
## Copies a file from `source` to `dest`, where `dest.parentDir` must exist.
|
||||
@@ -1653,6 +1671,9 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
##
|
||||
## If `dest` already exists, the file attributes
|
||||
## will be preserved and the content overwritten.
|
||||
##
|
||||
## On OSX, `copyfile` C api will be used (available since OSX 10.5) unless
|
||||
## `-d:nimLegacyCopyFile` is used.
|
||||
##
|
||||
## See also:
|
||||
## * `copyDir proc <#copyDir,string,string>`_
|
||||
@@ -1668,6 +1689,16 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
if copyFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError(), $(source, dest))
|
||||
else:
|
||||
if copyFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError(), $(source, dest))
|
||||
elif hasCCopyfile:
|
||||
let state = copyfile_state_alloc()
|
||||
# xxx `COPYFILE_STAT` could be used for one-shot `copyFileWithPermissions`.
|
||||
let status = c_copyfile(source.cstring, dest.cstring, state, COPYFILE_DATA)
|
||||
if status != 0:
|
||||
let err = osLastError()
|
||||
discard copyfile_state_free(state)
|
||||
raiseOSError(err, $(source, dest))
|
||||
let status2 = copyfile_state_free(state)
|
||||
if status2 != 0: raiseOSError(osLastError(), $(source, dest))
|
||||
else:
|
||||
# generic version of copyFile which works for any platform:
|
||||
const bufSize = 8000 # better for memory manager
|
||||
|
||||
@@ -40,20 +40,25 @@ block fileOperations:
|
||||
doAssertRaises(OSError): copyFile(dname/"nonexistant.txt", dname/"nonexistant.txt")
|
||||
let fname = "D20201009T112235"
|
||||
let fname2 = "D20201009T112235.2"
|
||||
writeFile(dname/fname, "foo")
|
||||
let str = "foo1\0foo2\nfoo3\0"
|
||||
let file = dname/fname
|
||||
let file2 = dname/fname2
|
||||
writeFile(file, str)
|
||||
doAssert readFile(file) == str
|
||||
let sub = "sub"
|
||||
doAssertRaises(OSError): copyFile(dname/fname, dname/sub/fname2)
|
||||
doAssertRaises(OSError): copyFileToDir(dname/fname, dname/sub)
|
||||
doAssertRaises(ValueError): copyFileToDir(dname/fname, "")
|
||||
copyFile(dname/fname, dname/fname2)
|
||||
doAssert fileExists(dname/fname2)
|
||||
doAssertRaises(OSError): copyFile(file, dname/sub/fname2)
|
||||
doAssertRaises(OSError): copyFileToDir(file, dname/sub)
|
||||
doAssertRaises(ValueError): copyFileToDir(file, "")
|
||||
copyFile(file, file2)
|
||||
doAssert fileExists(file2)
|
||||
doAssert readFile(file2) == str
|
||||
createDir(dname/sub)
|
||||
copyFileToDir(dname/fname, dname/sub)
|
||||
copyFileToDir(file, dname/sub)
|
||||
doAssert fileExists(dname/sub/fname)
|
||||
removeDir(dname/sub)
|
||||
doAssert not dirExists(dname/sub)
|
||||
removeFile(dname/fname)
|
||||
removeFile(dname/fname2)
|
||||
removeFile(file)
|
||||
removeFile(file2)
|
||||
|
||||
# Test creating files and dirs
|
||||
for dir in dirs:
|
||||
|
||||
Reference in New Issue
Block a user