- Вопрос или проблема
- Ответ или решение
- Внешный атрибут файла в формате ZIP: Подробный анализ
- Что такое внешний атрибут файла в формате ZIP?
- Соотношение внешнего атрибута и прав доступа Unix
- Разделение битов в внешнем атрибуте
- Как Python помогает в создании ZIP-файлов
- Программное представление статуса файла
- Заключение
Вопрос или проблема
Это слегка экзотичный вопрос, но в сети, похоже, не так много информации на эту тему. Я только что добавил ответ на вопрос о внешнем атрибуте файла формата zip. Как видно из моего ответа, я пришел к выводу, что только второй байт (из 4 байтов) на самом деле используется для Unix. Похоже, что этого достаточно, когда распаковываешь файл, чтобы определить, является ли объект файлом или директорией, и также есть место для другой информации о разрешениях и атрибутах. Мой вопрос в том, как это соотносится с обычными Unix-разрешениями? Указывают ли обычные Unix-разрешения (например, ниже), которые выводит ls
, ровно на один байт, и если да, может кто-нибудь описать структуру или дать ссылку, пожалуйста?
$ 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
Позвольте мне сделать это более конкретным, задав конкретный вопрос. В соответствии с патчем Trac, который я привел в своем ответе выше, вы можете создать zip-файл с помощью следующего фрагмента Python.
Значение 040755 << 16L
соответствует созданию пустой директории с разрешениями drwxr-xr-x
. (Я это проверил). Я понимаю, что 0755
соответствует шаблону rwxr-xr-x
, но что насчет 04
, и как все значение соотносится с байтом? Я также понимаю, что << 16L
соответствует побитовому сдвигу влево на 16 позиций, который делает его вторым байтом сверху.
def makezip1():
import zipfile
z = zipfile.ZipFile("foo.zip", mode="w")
zfi = zipfile.ZipInfo("foo/empty/")
zfi.external_attr = 040755 << 16L # разрешения drwxr-xr-x
z.writestr(zfi, "")
print z.namelist()
z.close()
ИЗМЕНЕНИЕ: Перечитав это, я думаю, что мой вывод о том, что разрешения Unix соответствуют только одному байту, может быть неправильным, но я оставлю вышеуказанное на данный момент, так как не уверен, каков правильный ответ.
ИЗМЕНЕНИЕ2: Я действительно ошибался относительно значений Unix, которые соответствуют только 1 байту. Как объяснил @Random832, используются оба верхних байта. Согласно ответу @Random832, мы можем конструировать нужное значение 040755
из таблиц, которые он приводит ниже. А именно:
0040000 # __S_IFDIR
+ 0400 # S_IRUSR
+ 0200 # S_IWUSR
+ 0100 # S_IXUSR
+ 0040 # S_IRGRP
# S_IWGRP пропущен
+ 0010 # S_IXGRP
+ 0004 # S_IROTH
# S_IWOTH пропущен
+ 0001 # S_IXOTH
== 40755
Сложение здесь в восьмеричной системе.
0040000
— это традиционное значение S_IFDIR
, флага типа файла, представляющего директорию. Тип использует верхние 4 бита из 16-битного значения st_mode
, 0100000
— это значение для обычных файлов.
Высокие 16 бит внешних атрибутов файлов, похоже, используются для специфичных для ОС разрешений. Значения Unix такие же, как и на традиционных реализациях Unix. Другие ОС используют другие значения. Информацию о форматах, используемых в различных ОС, можно найти в исходном коде Info-ZIP (скачать или, например, в Debian apt-get source [zip or unzip]
) — соответствующие файлы это zipinfo.c
в unzip
, и платформозависимые файлы в zip
.
Эти значения обычно определяются в восьмеричной (основание 8); это представлено в C и python путем добавления к числу префикса 0
.
Эти значения можно найти в <sys/stat.h>
– ссылка на версию 4.4BSD. Эти значения не входят в стандарт POSIX (который вместо этого определяет тестовые макросы); но происходят из AT&T Unix и BSD. (в GNU libc / Linux сами значения определяются как __S_IFDIR
и т.д. в bits/stat.h
, хотя заголовок ядра может быть легче читать – значения везде абсолютно одинаковы.)
#define S_IFIFO 0010000 /* именованный канал (fifo) */
#define S_IFCHR 0020000 /* символьный специальный */
#define S_IFDIR 0040000 /* директория */
#define S_IFBLK 0060000 /* блочный специальный */
#define S_IFREG 0100000 /* обычный */
#define S_IFLNK 0120000 /* символическая ссылка */
#define S_IFSOCK 0140000 /* сокет */
И, конечно, остальные 12 бит для разрешений и битов setuid/setgid/стикер, такие же как для chmod:
#define S_ISUID 0004000 /* устанавливает идентификатор пользователя при выполнении */
#define S_ISGID 0002000 /* устанавливает идентификатор группы при выполнении */
#define S_ISTXT 0001000 /* бит стиля */
#define S_IRWXU 0000700 /* маска RWX для владельца */
#define S_IRUSR 0000400 /* R для владельца */
#define S_IWUSR 0000200 /* W для владельца */
#define S_IXUSR 0000100 /* X для владельца */
#define S_IRWXG 0000070 /* маска RWX для группы */
#define S_IRGRP 0000040 /* R для группы */
#define S_IWGRP 0000020 /* W для группы */
#define S_IXGRP 0000010 /* X для группы */
#define S_IRWXO 0000007 /* маска RWX для остальных */
#define S_IROTH 0000004 /* R для остальных */
#define S_IWOTH 0000002 /* W для остальных */
#define S_IXOTH 0000001 /* X для остальных */
#define S_ISVTX 0001000 /* сохранить измененный текст даже после использования */
Как историческая заметка, причина, по которой 0100000
соответствует обычным файлам, а не 0, заключается в том, что в очень ранних версиях Unix 0 использовалось для «маленьких» файлов (которые не использовали косвенные блоки в файловой системе), и верхний бит флага режима устанавливался для «больших» файлов, которые использовали бы косвенные блоки. Другие два типа, использующие этот бит, были добавлены в более поздние производные ОС Unix, после изменения файловой системы.
Таким образом, подводя итог, общая структура поля расширенных атрибутов для Unix выглядит так:
TTTTsstrwxrwxrwx0000000000ADVSHR
^^^^____________________________ тип файла, как объяснено выше
^^^_________________________ setuid, setgid, стирка
^^^^^^^^^________________ разрешения
^^^^^^^^________ Это "нижний средний байт", который упоминается в вашем сообщении
^^^^^^^^ биты атрибута DOS
Ответ или решение
Внешный атрибут файла в формате ZIP: Подробный анализ
Формат ZIP стал стандартом в сфере архивирования данных благодаря своей способности эффективно сжимать и организовывать файлы. Одной из ключевых особенностей этого формата является наличие внешнего атрибута файла, который предоставляет информацию о свойствах файлов и каталогов. В этом ответе нас интересует, как внешний атрибут ZIP-файлов соотносится с привычными правами доступа Unix и как они представлены в двоичном формате.
Что такое внешний атрибут файла в формате ZIP?
Внешний атрибут файла в ZIP представляет собой 32-битное целое число, где старшие 16 бит используются для определения операционной системы и её специфических атрибутов, а младшие 16 бит — для определения Unix-пермишин. Эти значения позволяют извлекать категории (файлы, каталоги) и их разрешения при распаковке zip-архивов.
Как было показано в вопросе, первый разряд старшего байта указывает на тип файла (например, каталог или обычный файл), а остальные биты представляют собой права доступа.
Соотношение внешнего атрибута и прав доступа Unix
В Unix права доступа задаются в виде трех групп разрешений: для владельца файла, для группы и для остальных пользователей. Каждая из этих групп имеет три разрешения: чтение (r), запись (w) и выполнение (x). В восьмеричной системе это представляется как три бита на каждое разрешение, что приводит к следующему формату:
- 4 (r) — разрешение на чтение
- 2 (w) — разрешение на запись
- 1 (x) — разрешение на выполнение
Таким образом, для прав доступа rwxr-xr-x
вы получаете следующее представление в восьмеричном формате:
- Владельцы: rwx = 4 + 2 + 1 = 7
- Группа: r-x = 4 + 0 + 1 = 5
- Остальные: r-x = 4 + 0 + 1 = 5
Объединяя это, вы получаете 0755
в восьмеричном представлении.
Разделение битов в внешнем атрибуте
Внешний атрибут файла задаётся следующим образом:
TTTTsstrwxrwxrwx0000000000ADVSHR
Где:
TTTT
— тип файла (например, 0x4000 для каталога).s
— установка битов setuid и setgid.trwxrwxrwx
— права доступа (чтение, запись, выполнение для владельца, группы и остальных).- Остальные биты могут использоваться для специфических атрибутов (например, sticky bit).
Общий вид представлен следующим образом:
- Данные о типе файла: 4 верхних бита
- Биты прав доступа: 12 следующих битов
- Специфические атрибуты: оставшиеся 16 бит.
Как Python помогает в создании ZIP-файлов
Для создания ZIP-файла с правильными правами можно воспользоваться библиотекой zipfile в Python. Как указано в вашем примере кода:
zfi.external_attr = 040755 << 16L
Это указывает, что мы хотим установить права доступа для каталога drwxr-xr-x
, где 040755
соответствует правам, а << 16L
означает, что эти права должны занимать 16 старших битов.
Программное представление статуса файла
Используя подход, изложенный выше, восстановление прав доступа для вывода ls в Unix происходит следующим образом:
Для drwxr-xr-x
:
- 0040000 (директория) + 00755 (права доступа) = 040755
Таким образом, создается впередсмотрящий и протестированный ZIP-файлы с точно заданными атрибутами и правами доступа.
Заключение
Внешний атрибут файла в формате ZIP играет важную роль в управлении правами доступа и отображении информации о файлах и каталогах. Применение стандартных Unix-пермишин в сочетании с форматом ZIP дает разработчикам мощный инструмент для работы с файлами. Понимание структуры и атрибутов, зафиксированных в ZIP, является основополагающим для работы с архивами на уровне системы и значительно расширяет возможности взаимодействия с файлами в разных операционных системах.