El atributo de archivo externo del formato zip


25

Esta es una pregunta un poco exótica, pero no parece haber mucha información en la red sobre esto. Acabo de agregar una respuesta a una pregunta sobre el atributo de archivo externo del formato zip . Como puede ver en mi respuesta, concluyo que solo el segundo byte (de 4 bytes) se usa realmente para Unix. Aparentemente, esto contiene suficiente información al descomprimir para deducir si el objeto es un archivo o un directorio, y también tiene espacio para otros permisos e información de atributos. Mi pregunta es, ¿cómo se asigna esto a los permisos habituales de Unix? ¿Los permisos habituales de Unix (p. Ej., A continuación) se lsajustan exactamente a un byte y, de ser así, ¿alguien puede describir el diseño o dar una referencia, por favor?

$ 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

Permítanme hacer esto más concreto haciendo una pregunta específica. Según el parche de Trac citado en mi respuesta anterior, puede crear un archivo zip con el fragmento de Python a continuación.

El 040755 << 16Lvalor corresponde a la creación de un directorio vacío con los permisos drwxr-xr-x. (Lo probé). Reconozco que 0755corresponde al rwxr-xr-xpatrón, pero ¿qué pasa con el 04, y cómo corresponde el valor completo a un byte? También reconozco que << 16Lcorresponde a un desplazamiento a la izquierda bit a bit de 16 lugares, lo que lo haría terminar como el segundo desde el byte superior.

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()

EDITAR: Al releer esto, creo que mi conclusión de que los permisos de Unix solo corresponden a un byte puede ser incorrecta, pero dejaré que lo anterior represente el presente, ya que no estoy seguro de cuál es la respuesta correcta.

EDIT2: De hecho, era incorrecto acerca de los valores de Unix que solo corresponden a 1 byte. Como explicó @ Random832, utiliza los dos primeros bytes. Según la respuesta de @ Random832, podemos construir el 040755valor deseado a partir de las tablas que da a continuación. A saber:

__S_IFDIR + S_IRUSR + S_IWUSR + S_IXUSR + S_IRGRP + S_IXGRP + S_IROTH + S_IXOTH
0040000   + 0400    + 0200    + 0100    + 0040    + 0010    + 0004    + 0001
= 40755 

La adición aquí está en la base 8 .


No sé nada acerca de los permisos zip, pero sé que los permisos unix tradicionales usan 12 bits, que son más de un byte. Tal vez zip no se moleste con setxid y pegajoso, pero eso todavía deja 9 (rwx × ugo).
Gilles 'SO- deja de ser malvado'

Respuestas:


30

0040000es el valor tradicional de S_IFDIR, el indicador de tipo de archivo que representa un directorio. El tipo utiliza los 4 bits superiores del valor de 16 bits st_mode , 0100000es el valor de los archivos normales.

Los 16 bits altos de los atributos del archivo externo parecen usarse para permisos específicos del sistema operativo. Los valores de Unix son los mismos que en las implementaciones de Unix tradicionales. Otros sistemas operativos usan otros valores. Información sobre los formatos utilizados en una variedad de sistemas operativos diferentes se puede encontrar en el código postal Info-fuente ( descarga o, por ejemplo en debian apt-get source [zip or unzip]) - archivos relevantes son zipinfo.cen unzip, y los archivos específicos de la plataforma en zip.

Estos se definen convencionalmente en octal (base 8); esto se representa en C y python prefijando el número con a 0.

Todos estos valores se pueden encontrar en <sys/stat.h>- enlace a la versión 4.4BSD . Estos no están en el estándar POSIX (que define macros de prueba en su lugar); pero se originan en AT&T Unix y BSD. (en GNU libc / Linux, los valores en sí mismos se definen como __S_IFDIRetc. bits/stat.h, aunque el encabezado del núcleo podría ser más fácil de leer: los valores son todos prácticamente iguales en todas partes).

#define S_IFIFO  0010000  /* named pipe (fifo) */
#define S_IFCHR  0020000  /* character special */
#define S_IFDIR  0040000  /* directory */
#define S_IFBLK  0060000  /* block special */
#define S_IFREG  0100000  /* regular */
#define S_IFLNK  0120000  /* symbolic link */
#define S_IFSOCK 0140000  /* socket */

Y, por supuesto, los otros 12 bits son para los permisos y setuid / setgid / sticky bits, lo mismo que para chmod:

#define S_ISUID 0004000 /* set user id on execution */
#define S_ISGID 0002000 /* set group id on execution */
#define S_ISTXT 0001000 /* sticky bit */
#define S_IRWXU 0000700 /* RWX mask for owner */
#define S_IRUSR 0000400 /* R for owner */
#define S_IWUSR 0000200 /* W for owner */
#define S_IXUSR 0000100 /* X for owner */
#define S_IRWXG 0000070 /* RWX mask for group */
#define S_IRGRP 0000040 /* R for group */
#define S_IWGRP 0000020 /* W for group */
#define S_IXGRP 0000010 /* X for group */
#define S_IRWXO 0000007 /* RWX mask for other */
#define S_IROTH 0000004 /* R for other */
#define S_IWOTH 0000002 /* W for other */
#define S_IXOTH 0000001 /* X for other */
#define S_ISVTX 0001000 /* save swapped text even after use */

Como nota histórica, la razón 0100000es para archivos regulares en lugar de 0 es que en versiones muy tempranas de Unix, 0 era para archivos 'pequeños' (estos no usaban bloques indirectos en el sistema de archivos) y el bit alto del indicador de modo era configurado para archivos 'grandes' que usarían bloques indirectos. Los otros dos tipos que usan este bit se agregaron en sistemas operativos derivados de Unix posteriores, después de que el sistema de archivos hubiera cambiado.

Entonces, para concluir, el diseño general del campo de atributos extendidos para Unix es

TTTTsstrwxrwxrwx0000000000ADVSHR
^^^^____________________________ file type as explained above
    ^^^_________________________ setuid, setgid, sticky
       ^^^^^^^^^________________ permissions
                ^^^^^^^^________ This is the "lower-middle byte" your post mentions
                        ^^^^^^^^ DOS attribute bits

@ Random832: Wow, eso es impresionantemente completo y completo. ¿Puedes explicar también cómo 040755 << 16Lse construye el valor ? Específicamente, ¿qué representación / base está usando (creo que posiblemente Octal ), y lo más importante, ¿cómo sabe el lenguaje (el intérprete de Python en este caso) cuál es la representación? Hmm, tal vez el tipo se declara en el código C. Además, ¿de qué archivo obtiene los valores de "tipo de archivo"? Agregar algunos enlaces / referencias sería útil.
Faheem Mitha

@ Random832: veo que zipinfo.cestá en la fuente para descomprimir en Debian . Alternativamente, uno puede usar el más conveniente apt-get source unzip. Puede agregar eso a su respuesta, o usar una fuente no corriente. Por lo general, cito a Debian porque tengo fe en que estarán a largo plazo. :-)
Faheem Mitha

@ Random832: Ok, creo que veo cómo funciona esto. Simplemente sumas todos los valores de las cosas que se establecen en la base 8 según tu tabla, y obtienes el número 040755. Vale la pena mencionar a las personas que no saben o han olvidado. Por supuesto, eso todavía deja la pregunta de cómo sabe que es la base 8, pero tal vez el tipo se declare como base 8.
Faheem Mitha

Es base 8 porque comienza con un 0. Lo
aclararé

@Random: Gracias por la aclaración. No estaba al tanto de la convención principal 0. El stat.harchivo en Linux (supongo que el archivo correcto es /usr/include/sys/stat.h) no contiene la definición de estas constantes de una manera tan clara como el archivo al que se vinculó. ¿Están escondidos en otro lugar? Veo que usaste el término test macros, pero no estoy seguro de lo que eso significa.
Faheem Mitha
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.