From 6b159fdb034336241a5375f7300106e049b33e5d Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Wed, 2 May 2018 14:38:25 -0700 Subject: [PATCH] Fix for file module with recursive permission setting and broken symlinks There was a traceback when setting permissions on a directory tree when there were broken symlinks inside of the tree and follow=true. chmod -R ignores broken symlinks inside of the tree so we've fixed the file module to do the same. Fixes #39456 --- .../fragments/file-nonexitent-link-recurse.yaml | 5 +++++ lib/ansible/modules/files/file.py | 17 ++++++++++++----- test/integration/targets/file/tasks/main.yml | 3 +++ 3 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 changelogs/fragments/file-nonexitent-link-recurse.yaml diff --git a/changelogs/fragments/file-nonexitent-link-recurse.yaml b/changelogs/fragments/file-nonexitent-link-recurse.yaml new file mode 100644 index 0000000000..f1183d6fbf --- /dev/null +++ b/changelogs/fragments/file-nonexitent-link-recurse.yaml @@ -0,0 +1,5 @@ +--- +bugfixes: + - file module - Fix error when recursively assigning permissions and + a symlink to a nonexistent file is present in the directory tree + (https://github.com/ansible/ansible/issues/39456) diff --git a/lib/ansible/modules/files/file.py b/lib/ansible/modules/files/file.py index 608ab83a61..25d612405e 100644 --- a/lib/ansible/modules/files/file.py +++ b/lib/ansible/modules/files/file.py @@ -161,16 +161,23 @@ def recursive_set_attributes(module, b_path, follow, file_args): tmp_file_args['path'] = to_native(b_fsname, errors='surrogate_or_strict') changed |= module.set_fs_attributes_if_different(tmp_file_args, changed, expand=False) else: + # Change perms on the link tmp_file_args = file_args.copy() tmp_file_args['path'] = to_native(b_fsname, errors='surrogate_or_strict') changed |= module.set_fs_attributes_if_different(tmp_file_args, changed, expand=False) + if follow: b_fsname = os.path.join(b_root, os.readlink(b_fsname)) - if os.path.isdir(b_fsname): - changed |= recursive_set_attributes(module, b_fsname, follow, file_args) - tmp_file_args = file_args.copy() - tmp_file_args['path'] = to_native(b_fsname, errors='surrogate_or_strict') - changed |= module.set_fs_attributes_if_different(tmp_file_args, changed, expand=False) + # The link target could be nonexistent + if os.path.exists(b_fsname): + if os.path.isdir(b_fsname): + # Link is a directory so change perms on the directory's contents + changed |= recursive_set_attributes(module, b_fsname, follow, file_args) + + # Change perms on the file pointed to by the link + tmp_file_args = file_args.copy() + tmp_file_args['path'] = to_native(b_fsname, errors='surrogate_or_strict') + changed |= module.set_fs_attributes_if_different(tmp_file_args, changed, expand=False) return changed diff --git a/test/integration/targets/file/tasks/main.yml b/test/integration/targets/file/tasks/main.yml index 4db6637e74..4ce5db20b1 100644 --- a/test/integration/targets/file/tasks/main.yml +++ b/test/integration/targets/file/tasks/main.yml @@ -636,6 +636,9 @@ - name: create a symlink to the directory file: path={{output_dir}}/test_follow_rec/test_link_dir state=link src="../test_follow_rec_target_dir" +- name: create a symlink to a nonexistent file + file: path={{output_dir}}/test_follow_rec/nonexistent state=link src=does_not_exist force=True + - name: try to change permissions without following symlinks file: path={{output_dir}}/test_follow_rec follow=False mode="a-x" recurse=True