diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2021-02-01 17:38:17 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-01 17:38:17 -0800 |
commit | 917f12ae5251f678f82c9806d027b33f75ce0b68 (patch) | |
tree | 3d52b92e40ab15989fdb01039fa681c601b8f9ef /lib/pure | |
parent | fa9dc31899e483ecfa81264dbda5065192d23ab6 (diff) | |
download | Nim-917f12ae5251f678f82c9806d027b33f75ce0b68.tar.gz |
2.5x- 3x faster copyFile on osx (#16883)
Diffstat (limited to 'lib/pure')
-rw-r--r-- | lib/pure/os.nim | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 002085d97..d642e5242 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -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 |