@@ -1598,10 +1598,11 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission],
1598
1598
noWeirdTarget .} =
1599
1599
# # Sets the file permissions for `filename`.
1600
1600
# #
1601
- # # If `` followSymlinks` ` set to true (default) and ``filename`` points to a
1601
+ # # If `followSymlinks` set to true (default) and ``filename`` points to a
1602
1602
# # symlink, permissions are set to the file symlink points to.
1603
- # # ``followSymlinks`` set to false do not affect on Windows and some POSIX
1604
- # # systems (including Linux) which do not have ``lchmod`` available.
1603
+ # # `followSymlinks` set to false is a noop on Windows and some POSIX
1604
+ # # systems (including Linux) on which `lchmod` is either unavailable or always
1605
+ # # fails, given that symlinks permissions there are not observed.
1605
1606
# #
1606
1607
# # `OSError` is raised in case of an error.
1607
1608
# # On Windows, only the ``readonly`` flag is changed, depending on
@@ -1625,7 +1626,7 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission],
1625
1626
if fpOthersExec in permissions: p = p or S_IXOTH .Mode
1626
1627
1627
1628
if not followSymlinks and filename.symlinkExists:
1628
- when hasLchmod :
1629
+ when declared (lchmod) :
1629
1630
if lchmod (filename, cast [Mode ](p)) != 0 :
1630
1631
raiseOSError (osLastError (), $ (filename, permissions))
1631
1632
else :
@@ -1653,16 +1654,16 @@ proc createSymlink*(src, dest: string) {.noWeirdTarget.} =
1653
1654
# #
1654
1655
# # **Warning**:
1655
1656
# # Some OS's (such as Microsoft Windows) restrict the creation
1656
- # # of symlinks to root users (administrators).
1657
+ # # of symlinks to root users (administrators) or users with developper mode enabled .
1657
1658
# #
1658
1659
# # See also:
1659
1660
# # * `createHardlink proc <#createHardlink,string,string>`_
1660
1661
# # * `expandSymlink proc <#expandSymlink,string>`_
1661
1662
1662
1663
when defined (Windows ):
1663
- # 2 is the SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE. This allows
1664
- # anyone with developer mode on to create a link
1665
- let flag = dirExists (src).int32 or 2
1664
+ const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 2
1665
+ # allows anyone with developer mode on to create a link
1666
+ let flag = dirExists (src).int32 or SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
1666
1667
when useWinUnicode:
1667
1668
var wSrc = newWideCString (src)
1668
1669
var wDst = newWideCString (dest)
@@ -1678,7 +1679,7 @@ proc createSymlink*(src, dest: string) {.noWeirdTarget.} =
1678
1679
proc expandSymlink * (symlinkPath: string ): string {.noWeirdTarget .} =
1679
1680
# # Returns a string representing the path to which the symbolic link points.
1680
1681
# #
1681
- # # On Windows this is a noop, `` symlinkPath` ` is simply returned.
1682
+ # # On Windows this is a noop, `symlinkPath` is simply returned.
1682
1683
# #
1683
1684
# # See also:
1684
1685
# # * `createSymlink proc <#createSymlink,string,string>`_
@@ -1761,16 +1762,27 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
1761
1762
if isSymlink and cfSymlinkIgnore in options:
1762
1763
return
1763
1764
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
+
1764
1776
let dwCopyFlags = if cfSymlinkAsIs in options: COPY_FILE_COPY_SYMLINK else : 0 'i32
1765
1777
var pbCancel = 0 'i32
1766
1778
when useWinUnicode:
1767
1779
let s = newWideCString (source)
1768
1780
let d = newWideCString (dest)
1769
1781
if copyFileExW (s, d, nil , nil , addr pbCancel, dwCopyFlags) == 0 'i32 :
1770
- raiseOSError ( osLastError (), $ (source, dest, options) )
1782
+ handleOSError ( )
1771
1783
else :
1772
1784
if copyFileExA (source, dest, nil , nil , addr pbCancel, dwCopyFlags) == 0 'i32 :
1773
- raiseOSError ( osLastError (), $ (source, dest, options) )
1785
+ handleOSError ( )
1774
1786
elif hasCCopyfile:
1775
1787
let state = copyfile_state_alloc ()
1776
1788
# xxx `COPYFILE_STAT` could be used for one-shot `copyFileWithPermissions`.
0 commit comments