diff --git a/changelogs/fragments/dd-put-empty-files.yaml b/changelogs/fragments/dd-put-empty-files.yaml new file mode 100644 index 0000000000..eaa4406be2 --- /dev/null +++ b/changelogs/fragments/dd-put-empty-files.yaml @@ -0,0 +1,7 @@ +bugfixes: +- docker connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) +- chroot connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) +- jail connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) +- kubectl connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) +- libvirt_lxc connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) +- zone connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) diff --git a/lib/ansible/plugins/connection/chroot.py b/lib/ansible/plugins/connection/chroot.py index abf0d178a3..faaf691040 100644 --- a/lib/ansible/plugins/connection/chroot.py +++ b/lib/ansible/plugins/connection/chroot.py @@ -148,8 +148,12 @@ class Connection(ConnectionBase): out_path = shlex_quote(self._prefix_login_path(out_path)) try: with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' try: - p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file) + p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file) except OSError: raise AnsibleError("chroot connection requires dd command in the chroot") try: diff --git a/lib/ansible/plugins/connection/docker.py b/lib/ansible/plugins/connection/docker.py index 706f735e0b..76859a7183 100644 --- a/lib/ansible/plugins/connection/docker.py +++ b/lib/ansible/plugins/connection/docker.py @@ -246,9 +246,13 @@ class Connection(ConnectionBase): # running containers, so we use docker exec to implement this # Although docker version 1.8 and later provide support, the # owner and group of the files are always set to root - args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s" % (out_path, BUFSIZE)]) - args = [to_bytes(i, errors='surrogate_or_strict') for i in args] with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' + args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s%s" % (out_path, BUFSIZE, count)]) + args = [to_bytes(i, errors='surrogate_or_strict') for i in args] try: p = subprocess.Popen(args, stdin=in_file, stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/lib/ansible/plugins/connection/jail.py b/lib/ansible/plugins/connection/jail.py index 6d1a051cc3..8d9018ae93 100644 --- a/lib/ansible/plugins/connection/jail.py +++ b/lib/ansible/plugins/connection/jail.py @@ -158,8 +158,12 @@ class Connection(ConnectionBase): out_path = shlex_quote(self._prefix_login_path(out_path)) try: with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' try: - p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file) + p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file) except OSError: raise AnsibleError("jail connection requires dd command in the jail") try: diff --git a/lib/ansible/plugins/connection/kubectl.py b/lib/ansible/plugins/connection/kubectl.py index ed42638028..063d38d437 100644 --- a/lib/ansible/plugins/connection/kubectl.py +++ b/lib/ansible/plugins/connection/kubectl.py @@ -300,9 +300,13 @@ class Connection(ConnectionBase): out_path = shlex_quote(out_path) # kubectl doesn't have native support for copying files into # running containers, so we use kubectl exec to implement this - args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s" % (out_path, BUFSIZE)]) - args = [to_bytes(i, errors='surrogate_or_strict') for i in args] with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' + args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s%s" % (out_path, BUFSIZE, count)]) + args = [to_bytes(i, errors='surrogate_or_strict') for i in args] try: p = subprocess.Popen(args, stdin=in_file, stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/lib/ansible/plugins/connection/libvirt_lxc.py b/lib/ansible/plugins/connection/libvirt_lxc.py index c731e71ad1..10057b9cec 100644 --- a/lib/ansible/plugins/connection/libvirt_lxc.py +++ b/lib/ansible/plugins/connection/libvirt_lxc.py @@ -138,8 +138,12 @@ class Connection(ConnectionBase): out_path = shlex_quote(self._prefix_login_path(out_path)) try: with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' try: - p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file) + p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file) except OSError: raise AnsibleError("chroot connection requires dd command in the chroot") try: diff --git a/lib/ansible/plugins/connection/zone.py b/lib/ansible/plugins/connection/zone.py index f05d753090..15ed4417a9 100644 --- a/lib/ansible/plugins/connection/zone.py +++ b/lib/ansible/plugins/connection/zone.py @@ -157,8 +157,12 @@ class Connection(ConnectionBase): out_path = shlex_quote(self._prefix_login_path(out_path)) try: with open(in_path, 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' try: - p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file) + p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file) except OSError: raise AnsibleError("jail connection requires dd command in the jail") try: