2

I need to change permission on a single file in a tar.gz archive without extracting it, but I was unable to find any way to achieve it either on man pages or by google search.

More detailed scenario:

We start on a Linux machine with three files:

[root@localhost tar-test]# ls -l
total 0
-rw-r--r--. 1 root root 0 Nov 17 14:41 a.txt
-rw-rw-r--. 1 root root 0 Nov 17 14:41 b.txt
-rw-r--r--. 1 root root 0 Nov 17 14:41 c.txt

Then we create tar.gz archive:

tar cvzf test.tar.gz a.txt b.txt c.txt

Then, test.tar.gz is sent to my Windows machine. Now I need to change permissions of a.txt file without extracting the whole archive. I have access to MinGW, but not to a full Linux machine (virtual or physical). I also don't want to extract the whole archive. It can be assumed, that I know both name and location of the file in the archive.

The solution is restricted to command line tools, since I intend to script it later on.

4
  • Just out of curiosity, couldn't you change the file permission on linux before you compress it?
    – Cas
    Nov 17, 2016 at 14:05
  • Long story short, I have no control over Linux part of the process. Nov 17, 2016 at 14:20
  • Have you tried extracting the single file, updating its permissions and updating the archive? Not that this will necessarily be any faster or disc-intensive than extracting the full archive. The problem with zipped files is that changing a single bit will completely change the archive from the point where the change is encoded. The best you could hope to do is to gunzip the uncompressed .tar file, patch that and gzip it again, but you'll need to find the detailed tar format in order to patch the correct check-sums.
    – AFH
    Nov 17, 2016 at 15:24
  • Yes, I've tried that, but since it is extracted onto Windows-controlled storage, all information about permissions is lost and invoking chmod doesn't change anything. I hoped that there is some combination of options in tar which would allow me to solve the problem, and it's just that I missed it during my search. Nov 17, 2016 at 19:49

1 Answer 1

0

I was just faced with the same question and came up with this using Python:

import os, tarfile


def chmod_in_targz(archivepath:str, files_to_change:list[str], new_mode:int):
    os.rename(archivepath, f"{archivepath}.orig")
    with tarfile.open(f"{archivepath}.orig", "r:gz") as source:
        with tarfile.open(archivepath, "w:gz") as target:
            for entry in source.getmembers():
                if entry.path in files_to_change:
                    entry.mode = new_mode # <-- HERE WE CHANGE THE PERMISSION
                target.addfile(entry, source.extractfile(entry))

    os.remove(f"{archivepath}.orig")


cwd = os.path.dirname(__file__)

chmod_in_targz("test.tar.gz", ["a.txt"], 0o666)

Running this will:

  1. rename test.tar.gz to test.tar.gz.orig
  2. create a new test.tar.gz based on the content of test.tar.gz.orig but with fixed file permissions
  3. delete test.tar.gz.orig

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .