Skip to content

Commit

Permalink
update follow_symlinks functionality in win_file to match file module
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasmhughes authored and Megan Wilhite committed Oct 2, 2023
1 parent acc4edb commit 6e64117
Showing 1 changed file with 50 additions and 40 deletions.
90 changes: 50 additions & 40 deletions salt/modules/win_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ def gid_to_group(gid):
salt '*' file.gid_to_group S-1-5-21-626487655-2533044672-482107328-1010
"""
func_name = "{}.gid_to_group".format(__virtualname__)
func_name = f"{__virtualname__}.gid_to_group"
if __opts__.get("fun", "") == func_name:
log.info(
"The function %s should not be used on Windows systems; "
Expand Down Expand Up @@ -294,7 +294,7 @@ def group_to_gid(group):
salt '*' file.group_to_gid administrators
"""
func_name = "{}.group_to_gid".format(__virtualname__)
func_name = f"{__virtualname__}.group_to_gid"
if __opts__.get("fun", "") == func_name:
log.info(
"The function %s should not be used on Windows systems; "
Expand Down Expand Up @@ -336,7 +336,7 @@ def get_pgid(path, follow_symlinks=True):
salt '*' file.get_pgid c:\\temp\\test.txt
"""
if not os.path.exists(path):
raise CommandExecutionError("Path not found: {}".format(path))
raise CommandExecutionError(f"Path not found: {path}")

# Under Windows, if the path is a symlink, the user that owns the symlink is
# returned, not the user that owns the file/directory the symlink is
Expand Down Expand Up @@ -420,7 +420,7 @@ def get_gid(path, follow_symlinks=True):
salt '*' file.get_gid c:\\temp\\test.txt
"""
func_name = "{}.get_gid".format(__virtualname__)
func_name = f"{__virtualname__}.get_gid"
if __opts__.get("fun", "") == func_name:
log.info(
"The function %s should not be used on Windows systems; "
Expand Down Expand Up @@ -467,7 +467,7 @@ def get_group(path, follow_symlinks=True):
salt '*' file.get_group c:\\temp\\test.txt
"""
func_name = "{}.get_group".format(__virtualname__)
func_name = f"{__virtualname__}.get_group"
if __opts__.get("fun", "") == func_name:
log.info(
"The function %s should not be used on Windows systems; "
Expand Down Expand Up @@ -548,7 +548,7 @@ def get_uid(path, follow_symlinks=True):
salt '*' file.get_uid c:\\temp\\test.txt follow_symlinks=False
"""
if not os.path.exists(path):
raise CommandExecutionError("Path not found: {}".format(path))
raise CommandExecutionError(f"Path not found: {path}")

# Under Windows, if the path is a symlink, the user that owns the symlink is
# returned, not the user that owns the file/directory the symlink is
Expand Down Expand Up @@ -587,7 +587,7 @@ def get_user(path, follow_symlinks=True):
salt '*' file.get_user c:\\temp\\test.txt follow_symlinks=False
"""
if not os.path.exists(path):
raise CommandExecutionError("Path not found: {}".format(path))
raise CommandExecutionError(f"Path not found: {path}")

# Under Windows, if the path is a symlink, the user that owns the symlink is
# returned, not the user that owns the file/directory the symlink is
Expand Down Expand Up @@ -620,9 +620,9 @@ def get_mode(path):
salt '*' file.get_mode /etc/passwd
"""
if not os.path.exists(path):
raise CommandExecutionError("Path not found: {}".format(path))
raise CommandExecutionError(f"Path not found: {path}")

func_name = "{}.get_mode".format(__virtualname__)
func_name = f"{__virtualname__}.get_mode"
if __opts__.get("fun", "") == func_name:
log.info(
"The function %s should not be used on Windows systems; "
Expand Down Expand Up @@ -671,7 +671,7 @@ def lchown(path, user, group=None, pgroup=None):
salt '*' file.lchown c:\\temp\\test.txt myusername "pgroup='None'"
"""
if group:
func_name = "{}.lchown".format(__virtualname__)
func_name = f"{__virtualname__}.lchown"
if __opts__.get("fun", "") == func_name:
log.info(
"The group parameter has no effect when using %s on "
Expand Down Expand Up @@ -720,7 +720,7 @@ def chown(path, user, group=None, pgroup=None, follow_symlinks=True):
"""
# the group parameter is not used; only provided for API compatibility
if group is not None:
func_name = "{}.chown".format(__virtualname__)
func_name = f"{__virtualname__}.chown"
if __opts__.get("fun", "") == func_name:
log.info(
"The group parameter has no effect when using %s on "
Expand All @@ -733,7 +733,7 @@ def chown(path, user, group=None, pgroup=None, follow_symlinks=True):
path = _resolve_symlink(path)

if not os.path.exists(path):
raise CommandExecutionError("Path not found: {}".format(path))
raise CommandExecutionError(f"Path not found: {path}")

__utils__["dacl.set_owner"](path, user)
if pgroup:
Expand Down Expand Up @@ -804,7 +804,7 @@ def chgrp(path, group):
salt '*' file.chpgrp c:\\temp\\test.txt administrators
"""
func_name = "{}.chgrp".format(__virtualname__)
func_name = f"{__virtualname__}.chgrp"
if __opts__.get("fun", "") == func_name:
log.info(
"The function %s should not be used on Windows systems; see "
Expand Down Expand Up @@ -850,7 +850,7 @@ def stats(path, hash_type="sha256", follow_symlinks=True):
# This is to mirror the behavior of file.py. `check_file_meta` expects an
# empty dictionary when the file does not exist
if not os.path.exists(path):
raise CommandExecutionError("Path not found: {}".format(path))
raise CommandExecutionError(f"Path not found: {path}")

if follow_symlinks and sys.getwindowsversion().major >= 6:
path = _resolve_symlink(path)
Expand Down Expand Up @@ -953,13 +953,13 @@ def _get_version_type(file_type, file_subtype):

if ret_type == "Driver":
if file_subtype in driver_subtypes:
ret_type = "{} Driver".format(driver_subtypes[file_subtype])
ret_type = f"{driver_subtypes[file_subtype]} Driver"
if ret_type == "Font":
if file_subtype in font_subtypes:
ret_type = "{} Font".format(font_subtypes[file_subtype])
ret_type = f"{font_subtypes[file_subtype]} Font"
if ret_type == "Virtual Device":
# The Virtual Device Identifier
ret_type = "Virtual Device: {}".format(file_subtype)
ret_type = f"Virtual Device: {file_subtype}"
return ret_type


Expand Down Expand Up @@ -1028,9 +1028,9 @@ def version(path):
"""
# Input validation
if not os.path.exists(path):
raise CommandExecutionError("File not found: {}".format(path))
raise CommandExecutionError(f"File not found: {path}")
if os.path.isdir(path):
raise CommandExecutionError("Not a file: {}".format(path))
raise CommandExecutionError(f"Not a file: {path}")
return _get_version(path)


Expand Down Expand Up @@ -1068,9 +1068,9 @@ def version_details(path):
"""
# Input validation
if not os.path.exists(path):
raise CommandExecutionError("File not found: {}".format(path))
raise CommandExecutionError(f"File not found: {path}")
if os.path.isdir(path):
raise CommandExecutionError("Not a file: {}".format(path))
raise CommandExecutionError(f"Not a file: {path}")

ret = {}
try:
Expand Down Expand Up @@ -1146,7 +1146,7 @@ def get_attributes(path):
salt '*' file.get_attributes c:\\temp\\a.txt
"""
if not os.path.exists(path):
raise CommandExecutionError("Path not found: {}".format(path))
raise CommandExecutionError(f"Path not found: {path}")

# set up dictionary for attribute values
attributes = {}
Expand Down Expand Up @@ -1228,7 +1228,7 @@ def set_attributes(
salt '*' file.set_attributes c:\\temp\\a.txt readonly=True hidden=True
"""
if not os.path.exists(path):
raise CommandExecutionError("Path not found: {}".format(path))
raise CommandExecutionError(f"Path not found: {path}")

if normal:
if archive or hidden or notIndexed or readonly or system or temporary:
Expand Down Expand Up @@ -1297,7 +1297,7 @@ def set_mode(path, mode):
salt '*' file.set_mode /etc/passwd 0644
"""
func_name = "{}.set_mode".format(__virtualname__)
func_name = f"{__virtualname__}.set_mode"
if __opts__.get("fun", "") == func_name:
log.info(
"The function %s should not be used on Windows systems; "
Expand Down Expand Up @@ -1333,11 +1333,11 @@ def remove(path, force=False):
path = os.path.expanduser(path)

if not os.path.isabs(path):
raise SaltInvocationError("File path must be absolute: {}".format(path))
raise SaltInvocationError(f"File path must be absolute: {path}")

# Does the file/folder exists
if not os.path.exists(path) and not is_link(path):
raise CommandExecutionError("Path not found: {}".format(path))
raise CommandExecutionError(f"Path not found: {path}")

# Remove ReadOnly Attribute
if force:
Expand All @@ -1354,7 +1354,7 @@ def remove(path, force=False):
os.rmdir(path)
else:
for name in os.listdir(path):
item = "{}\\{}".format(path, name)
item = f"{path}\\{name}"
# If its a normal directory, recurse to remove it's contents
remove(item, force)

Expand All @@ -1364,12 +1364,12 @@ def remove(path, force=False):
if force:
# Reset attributes to the original if delete fails.
win32api.SetFileAttributes(path, file_attributes)
raise CommandExecutionError("Could not remove '{}': {}".format(path, exc))
raise CommandExecutionError(f"Could not remove '{path}': {exc}")

return True


def symlink(src, link, force=False, atomic=False):
def symlink(src, link, force=False, atomic=False, follow_symlinks=True):
"""
Create a symbolic link to a file
Expand All @@ -1394,6 +1394,11 @@ def symlink(src, link, force=False, atomic=False):
Use atomic file operations to create the symlink
.. versionadded:: 3006.0
follow_symlinks (bool):
If set to ``False``, use ``os.path.lexists()`` for existence checks
instead of ``os.path.exists()``.
.. versionadded:: 3007.0
Returns:
bool: ``True`` if successful, otherwise raises ``CommandExecutionError``
Expand All @@ -1412,7 +1417,12 @@ def symlink(src, link, force=False, atomic=False):
)

if not os.path.isabs(link):
raise SaltInvocationError("Link path must be absolute: {}".format(link))
raise SaltInvocationError(f"Link path must be absolute: {link}")

if follow_symlinks:
exists = os.path.exists
else:
exists = os.path.lexists

if os.path.islink(link):
try:
Expand All @@ -1425,11 +1435,11 @@ def symlink(src, link, force=False, atomic=False):
pass

if not force and not atomic:
msg = "Found existing symlink: {}".format(link)
msg = f"Found existing symlink: {link}"
raise CommandExecutionError(msg)

if os.path.exists(link) and not force and not atomic:
msg = "Existing path is not a symlink: {}".format(link)
if exists(link) and not force and not atomic:
msg = f"Existing path is not a symlink: {link}"
raise CommandExecutionError(msg)

# ensure paths are using the right slashes
Expand All @@ -1443,7 +1453,7 @@ def symlink(src, link, force=False, atomic=False):
th = win32security.OpenProcessToken(win32api.GetCurrentProcess(), desired_access)
salt.platform.win.elevate_token(th)

if (os.path.islink(link) or os.path.exists(link)) and force and not atomic:
if (os.path.islink(link) or exists(link)) and force and not atomic:
os.unlink(link)
elif atomic:
link_dir = os.path.dirname(link)
Expand All @@ -1464,14 +1474,14 @@ def symlink(src, link, force=False, atomic=False):
return True
except win32file.error:
os.remove(temp_link)
raise CommandExecutionError("Could not create '{}'".format(link))
raise CommandExecutionError(f"Could not create '{link}'")

try:
win32file.CreateSymbolicLink(link, src, int(is_dir))
return True
except win32file.error as exc:
raise CommandExecutionError(
"Could not create '{}' - [{}] {}".format(link, exc.winerror, exc.strerror)
f"Could not create '{link}' - [{exc.winerror}] {exc.strerror}"
)


Expand Down Expand Up @@ -1581,7 +1591,7 @@ def mkdir(
# Make sure the drive is valid
drive = os.path.splitdrive(path)[0]
if not os.path.isdir(drive):
raise CommandExecutionError("Drive {} is not mapped".format(drive))
raise CommandExecutionError(f"Drive {drive} is not mapped")

path = os.path.expanduser(path)
path = os.path.expandvars(path)
Expand Down Expand Up @@ -1698,12 +1708,12 @@ def makedirs_(

if os.path.isdir(dirname):
# There's nothing for us to do
msg = "Directory '{}' already exists".format(dirname)
msg = f"Directory '{dirname}' already exists"
log.debug(msg)
return msg

if os.path.exists(dirname):
msg = "The path '{}' already exists and is not a directory".format(dirname)
msg = f"The path '{dirname}' already exists and is not a directory"
log.debug(msg)
return msg

Expand Down Expand Up @@ -1912,7 +1922,7 @@ def check_perms(
salt '*' file.check_perms C:\\Temp\\ {} Administrators "{'jsnuffy': {'perms': ['read_attributes', 'read_ea'], 'applies_to': 'files_only'}}"
"""
if not os.path.exists(path):
raise CommandExecutionError("Path not found: {}".format(path))
raise CommandExecutionError(f"Path not found: {path}")

path = os.path.expanduser(path)

Expand Down

0 comments on commit 6e64117

Please sign in to comment.