Sample Header Ad - 728x90

The zip format's external file attribute

39 votes
1 answer
17326 views
This is a slightly exotic question, but there doesn't seem to be much information on the net about this. I just added [an answer to a question about the zip format's external file attribute](https://stackoverflow.com/questions/434641/how-do-i-set-permissions-attributes-on-a-file-in-a-zip-file-using-pythons-zipf/6297838#6297838) . As you can see from my answer, I conclude that only the second byte (of 4 bytes) is actually used for Unix. Apparently this contains enough information when unzipping to deduce whether the object is a file or a directory, and also has space for other permission and attribute information. My question is, how does this map to the usual Unix permissions? Do the usual Unix permissions (e.g. below) that ls gives fit into exactly one byte, and if so, can someone describe the layout or give a reference, please?
$ ls -la
total 36
drwxr-xr-x   3 faheem faheem  4096 Jun 10 01:11 .
drwxrwxrwt 136 root   root   28672 Jun 10 01:07 ..
-rw-r--r--   1 faheem faheem     0 Jun 10 01:07 a
drwxr-xr-x   2 faheem faheem  4096 Jun 10 01:07 b
lrwxrwxrwx   1 faheem faheem     1 Jun 10 01:11 c -> b
Let me make this more concrete by asking a specific question. Per the [Trac patch](http://trac.edgewall.org/attachment/ticket/8919/ZipDownload.patch) quoted in my answer above, you can create a zip file with the snippet of Python below. The 040755 << 16L value corresponds to the creation of an empty directory with the permissions drwxr-xr-x. (I tested it). I recognize 0755 corresponds to the rwxr-xr-x pattern, but what about the 04, and how does the whole value correspond to a byte? I also recognize << 16L corresponds to a bitwise left shift of 16 places, which would make it end up as the second from top byte.
def makezip1():
    import zipfile
    z = zipfile.ZipFile("foo.zip", mode = 'w')
    zfi = zipfile.ZipInfo("foo/empty/")
    zfi.external_attr = 040755 << 16L # permissions drwxr-xr-x
    z.writestr(zfi, "")
    print z.namelist()
    z.close()
EDIT: On rereading this, I think that my conclusion that the Unix permissions only correspond to one byte may be incorrect, but I'll let the above stand for the present, since I'm not sure what the correct answer is. EDIT2: I was indeed incorrect about the Unix values only corresponding to 1 byte. As @Random832 explained, it uses both of the top two bytes. Per @Random832's answer, we can construct the desired 040755 value from the tables he gives below. Namely:
0040000 # __S_IFDIR

+     0400 #   S_IRUSR
+     0200 #   S_IWUSR
+     0100 #   S_IXUSR

+     0040 #   S_IRGRP
           #   S_IWGRP skipped
+     0010 #   S_IXGRP

+     0004 #   S_IROTH
           #   S_IWOTH skipped
+     0001 #   S_IXOTH

==   40755
The addition here is in [base 8](http://en.wikipedia.org/wiki/Octal) .
Asked by Faheem Mitha (36008 rep)
Jun 9, 2011, 07:52 PM
Last activity: Nov 14, 2024, 04:56 AM