@@ -1725,8 +1725,9 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
17251725 noWeirdTarget .} =
17261726 # # Copies a file from `source` to `dest`, where `dest.parentDir` must exist.
17271727 # #
1728- # # `options` specify the way file is copied; by default, if `source` is a
1729- # # symlink, copies the file symlink points to.
1728+ # # On non-Windows OSes, `options` specify the way file is copied; by default,
1729+ # # if `source` is a symlink, copies the file symlink points to. `options` is
1730+ # # ignored on Windows: symlinks are skipped.
17301731 # #
17311732 # # If this fails, `OSError` is raised.
17321733 # #
@@ -1759,73 +1760,64 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
17591760 doAssert card (copyFlagSymlink * options) == 1 , " There should be exactly " &
17601761 " one cfSymlink* in options"
17611762 let isSymlink = source.symlinkExists
1762- if isSymlink and cfSymlinkIgnore in options:
1763+ if isSymlink and ( cfSymlinkIgnore in options or defined (windows)) :
17631764 return
17641765 when defined (Windows ):
1765- proc handleOSError =
1766- const ERROR_PRIVILEGE_NOT_HELD = 1314
1767- let errCode = osLastError ()
1768- let context = $ (source, dest, options)
1769- if isSymlink and errCode.int32 == ERROR_PRIVILEGE_NOT_HELD :
1770- stderr.write (" Failed copy the symlink: error " & $ errCode & " : " &
1771- osErrorMsg (errCode) & " Additional info: " & context &
1772- " \n " )
1773- else :
1774- raiseOSError (errCode, context)
1775-
1776- let dwCopyFlags = if cfSymlinkAsIs in options: COPY_FILE_COPY_SYMLINK else : 0 'i32
1777- var pbCancel = 0 'i32
17781766 when useWinUnicode:
17791767 let s = newWideCString (source)
17801768 let d = newWideCString (dest)
1781- if copyFileExW (s, d, nil , nil , addr pbCancel, dwCopyFlags ) == 0 'i32 :
1782- handleOSError ( )
1769+ if copyFileW (s, d, 0 'i32 ) == 0 'i32 :
1770+ raiseOSError ( osLastError (), $ (source, dest) )
17831771 else :
1784- if copyFileExA (source, dest, nil , nil , addr pbCancel, dwCopyFlags) == 0 'i32 :
1785- handleOSError ()
1786- elif hasCCopyfile:
1787- let state = copyfile_state_alloc ()
1788- # xxx `COPYFILE_STAT` could be used for one-shot `copyFileWithPermissions`.
1789- let status = c_copyfile (source.cstring , dest.cstring , state, COPYFILE_DATA )
1790- if status != 0 :
1791- let err = osLastError ()
1792- discard copyfile_state_free (state)
1793- raiseOSError (err, $ (source, dest))
1794- let status2 = copyfile_state_free (state)
1795- if status2 != 0 : raiseOSError (osLastError (), $ (source, dest))
1772+ if copyFileA (source, dest, 0 'i32 ) == 0 'i32 :
1773+ raiseOSError (osLastError (), $ (source, dest))
17961774 else :
17971775 if isSymlink and cfSymlinkAsIs in options:
17981776 createSymlink (expandSymlink (source), dest)
17991777 else :
1800- # generic version of copyFile which works for any platform:
1801- const bufSize = 8000 # better for memory manager
1802- var d, s: File
1803- if not open (s, source): raiseOSError (osLastError (), source)
1804- if not open (d, dest, fmWrite):
1778+ when hasCCopyfile:
1779+ let state = copyfile_state_alloc ()
1780+ # xxx `COPYFILE_STAT` could be used for one-shot
1781+ # `copyFileWithPermissions`.
1782+ let status = c_copyfile (source.cstring , dest.cstring , state,
1783+ COPYFILE_DATA )
1784+ if status != 0 :
1785+ let err = osLastError ()
1786+ discard copyfile_state_free (state)
1787+ raiseOSError (err, $ (source, dest))
1788+ let status2 = copyfile_state_free (state)
1789+ if status2 != 0 : raiseOSError (osLastError (), $ (source, dest))
1790+ else :
1791+ # generic version of copyFile which works for any platform:
1792+ const bufSize = 8000 # better for memory manager
1793+ var d, s: File
1794+ if not open (s, source):raiseOSError (osLastError (), source)
1795+ if not open (d, dest, fmWrite):
1796+ close (s)
1797+ raiseOSError (osLastError (), dest)
1798+ var buf = alloc (bufSize)
1799+ while true :
1800+ var bytesread = readBuffer (s, buf, bufSize)
1801+ if bytesread > 0 :
1802+ var byteswritten = writeBuffer (d, buf, bytesread)
1803+ if bytesread != byteswritten:
1804+ dealloc (buf)
1805+ close (s)
1806+ close (d)
1807+ raiseOSError (osLastError (), dest)
1808+ if bytesread != bufSize: break
1809+ dealloc (buf)
18051810 close (s)
1806- raiseOSError (osLastError (), dest)
1807- var buf = alloc (bufSize)
1808- while true :
1809- var bytesread = readBuffer (s, buf, bufSize)
1810- if bytesread > 0 :
1811- var byteswritten = writeBuffer (d, buf, bytesread)
1812- if bytesread != byteswritten:
1813- dealloc (buf)
1814- close (s)
1815- close (d)
1816- raiseOSError (osLastError (), dest)
1817- if bytesread != bufSize: break
1818- dealloc (buf)
1819- close (s)
1820- flushFile (d)
1821- close (d)
1811+ flushFile (d)
1812+ close (d)
18221813
18231814proc copyFileToDir * (source, dir: string , options = {cfSymlinkFollow})
18241815 {.noWeirdTarget , since : (1 ,3 ,7 ).} =
18251816 # # Copies a file `source` into directory `dir`, which must exist.
18261817 # #
1827- # # `options` specify the way file is copied; by default, if `source` is a
1828- # # symlink, copies the file symlink points to.
1818+ # # On non-Windows OSes, `options` specify the way file is copied; by default,
1819+ # # if `source` is a symlink, copies the file symlink points to. `options` is
1820+ # # ignored on Windows: symlinks are skipped.
18291821 # #
18301822 # # See also:
18311823 # # * `CopyFlag enum <#CopyFlag>`_
@@ -2460,7 +2452,8 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
24602452 tags : [ReadDirEffect , WriteIOEffect , ReadIOEffect ], benign , noWeirdTarget .} =
24612453 # # Copies a directory from `source` to `dest`.
24622454 # #
2463- # # Symlinks are copied as symlinks.
2455+ # # On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
2456+ # # are skipped.
24642457 # #
24652458 # # If this fails, `OSError` is raised.
24662459 # #
@@ -2491,8 +2484,8 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
24912484proc moveDir * (source, dest: string ) {.tags : [ReadIOEffect , WriteIOEffect ], noWeirdTarget .} =
24922485 # # Moves a directory from `source` to `dest`.
24932486 # #
2494- # # Symlinks are not followed: if `source` contains symlinks, they itself are
2495- # # moved, not theirs target.
2487+ # # Symlinks are not followed: if `source` contains symlinks, they themself are
2488+ # # moved, not their target.
24962489 # #
24972490 # # If this fails, `OSError` is raised.
24982491 # #
@@ -2536,8 +2529,9 @@ proc copyFileWithPermissions*(source, dest: string,
25362529 options = {cfSymlinkFollow}) {.noWeirdTarget .} =
25372530 # # Copies a file from `source` to `dest` preserving file permissions.
25382531 # #
2539- # # `options` specify the way file is copied; by default, if `source` is a
2540- # # symlink, copies the file symlink points to.
2532+ # # On non-Windows OSes, `options` specify the way file is copied; by default,
2533+ # # if `source` is a symlink, copies the file symlink points to. `options` is
2534+ # # ignored on Windows: symlinks are skipped.
25412535 # #
25422536 # # This is a wrapper proc around `copyFile <#copyFile,string,string>`_,
25432537 # # `getFilePermissions <#getFilePermissions,string>`_ and
@@ -2576,7 +2570,8 @@ proc copyDirWithPermissions*(source, dest: string,
25762570 benign , noWeirdTarget .} =
25772571 # # Copies a directory from `source` to `dest` preserving file permissions.
25782572 # #
2579- # # Symlinks are copied as symlinks.
2573+ # # On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
2574+ # # are skipped.
25802575 # #
25812576 # # If this fails, `OSError` is raised. This is a wrapper proc around `copyDir
25822577 # # <#copyDir,string,string>`_ and `copyFileWithPermissions
0 commit comments