Owner + group хранятся в inode
Каждый файл в Linux имеет ровно одного owner (UID) и ровно одну group (GID). Эти два числа лежат прямо в inode рядом с правами. Когда ls -l показывает:
$ ls -l report.csv
-rw-r--r-- 1 levo levo 1024 May 13 12:34 report.csv
Третий и четвёртый столбцы — это owner и group. Здесь оба равны levo. Это типичная конфигурация: файл создаётся пользователем levo, primary GID этого user — тоже levo (на современной Ubuntu каждому юзеру даётся своя группа того же имени, это называется UPG — User Private Group scheme).
Когда kernel проверяет доступ к файлу:
- Если
process.euid == file.uid-> проверка поowner-битам - Иначе если
file.gidесть в group-list процесса -> проверка поgroup-битам - Иначе -> проверка по
other-битам
То есть order matters: если ты owner, тебе сразу применяются owner-биты, даже если они строже, чем group или other. Это часто удивляет: можно создать файл с правами 0066, и owner не сможет его прочитать, хотя другие могут.
chown: меняем owner
$ chown NEW_OWNER file
$ chown NEW_OWNER:NEW_GROUP file
$ chown :NEW_GROUP file # только group
$ chown -R NEW_OWNER:NEW_GROUP dir/
Менять owner может только root. Это политика безопасности: иначе ты мог бы создать файл с какими угодно правами и “подарить” его другому пользователю, чтобы обойти его quota или вызвать атаку через quota-исчерпание.
# Под обычным юзером:
$ chown root:root myfile.txt
chown: changing ownership of 'myfile.txt': Operation not permitted
# Под sudo:
$ sudo chown postgres:postgres /var/lib/postgresql/16/main/pg_hba.conf
$ ls -l /var/lib/postgresql/16/main/pg_hba.conf
-rw------- 1 postgres postgres 4823 May 13 12:34 pg_hba.conf
Двоеточие vs точка
Разделитель user/group — :. Раньше (на BSD-системах и в очень старом Linux) поддерживалась точка chown user.group, но это устарело и может работать неправильно если в имени user есть .. Всегда :.
$ chown levo:data team_report.csv # [x] канон
$ chown levo.data team_report.csv # ВНИМАНИЕ: устарело, может сломаться
chgrp: меняем только group
chgrp group file — частный случай chown без смены owner. Эквивалент chown :group file. Обычный пользователь может менять group файла на любую, в которой он сам состоит:
$ groups
levo sudo docker
# Я в группе docker — могу присвоить эту группу файлу
$ chgrp docker myfile.txt # [x] работает
# Я не в группе postgres — не могу
$ chgrp postgres myfile.txt
chgrp: changing group of 'myfile.txt': Operation not permitted
Рекурсия: chown -R
Самый частый DE-сценарий: после tar -xf или cp от root всё стало root-owned, и приложение не может писать в свои директории.
# Восстановили бэкап под root
$ sudo tar -xzf airflow-backup.tar.gz -C /opt
$ ls -l /opt/airflow/
drwxr-xr-x 3 root root 4096 May 13 logs/
drwxr-xr-x 2 root root 4096 May 13 dags/
# Чтобы airflow смог писать логи:
$ sudo chown -R airflow:airflow /opt/airflow
$ ls -l /opt/airflow/
drwxr-xr-x 3 airflow airflow 4096 May 13 logs/
drwxr-xr-x 2 airflow airflow 4096 May 13 dags/
-R рекурсивно проходит по дереву, изменяя owner на каждом файле и директории. Symlinks по умолчанию не следует — меняет owner самой ссылки. Флаг -h явно работает только на симлинках, -L следует по ним.
—reference: скопировать ownership с другого файла
$ sudo chown --reference=template.json new_file.json
# Возьмёт owner+group из template.json
Удобно когда восстанавливаешь один файл из бэкапа и нужно повторить ownership соседа.
—from: меняем только у тех файлов, где сейчас определённый owner
$ sudo chown -R --from=root airflow:airflow /opt/airflow
# Изменит owner только у файлов, которые СЕЙЧАС root.
# Файлы, уже принадлежащие airflow, не тронуты.
Полезно для частичной миграции — когда часть файлов уже правильная, и трогать их не хочется.
DE-сценарии: когда меняют ownership
В работе DE chown срабатывает регулярно — почти всегда после операций под root.
Под капотом: чем отличается user-mode и kernel-mode
Команда chown levo:data file.csv приводит к syscall:
chown("file.csv", 1000, 100); // (path, uid, gid)
Kernel:
- Открывает inode файла
- Проверяет capabilities процесса:
CAP_CHOWNнужен для смены owner. У root она есть, у обычного user — нет (в default config). - Если разрешено — обновляет поля
i_uidиi_gidв inode, помечает inode dirty. - Сбрасывает SUID/SGID-биты (если они были) — security-мера, чтобы нельзя было передать privileged executable.
Последний пункт важен: после chown SUID/SGID слетают. Если ты сделал chown root:root /usr/bin/passwd, ты потеряешь SUID и passwd перестанет работать для обычных юзеров. Восстановить — chmod u+s /usr/bin/passwd.
$ ls -l setuid_binary
-rwsr-xr-x 1 root root 0 May 13 setuid_binary # SUID есть
$ sudo chown newowner setuid_binary
$ ls -l setuid_binary
-rwxr-xr-x 1 newowner root 0 May 13 setuid_binary # SUID СЛЕТЕЛ
Numeric IDs
USER и UID в Docker — как работает ownership в контейнерахМожно указывать UID/GID числом — особенно полезно в Docker, где имени airflow ещё может не быть в /etc/passwd контейнера:
$ chown 1001:1001 /data/airflow
# Эквивалентно chown airflow:airflow ЕСЛИ UID/GID совпадают
В Dockerfile часто так:
RUN chown -R 1001:1001 /opt/airflow
Это работает без зависимости от того, есть ли user airflow в image — kernel оперирует числами.
Если хочешь именованный chown в pure-number mode:
$ chown --no-dereference 1001:1001 file
$ chown -h 1001:1001 file # short for --no-dereference
Если в имени есть только цифры (например, chown 1001 file), chown сначала ищет user с именем "1001" в /etc/passwd. Если такого нет — трактует как numeric UID. Чтобы заставить numeric:
$ chown +1001 file # знак + явно говорит: это UID
Что НЕ может chown
- Менять owner файла на несуществующий UID обычного user — root это всё-таки может. Появится файл с
owner=12345, иls -lпокажет числовой UID без имени:
Это случается, если ты восстановил из tar бэкапа другой машины с другими UID.$ ls -l orphan.txt -rw-r--r-- 1 12345 12345 0 May 13 orphan.txt - Менять owner файла на read-only FS — получишь
EROFS. Сначала надо перемонтироватьrw. - Менять owner на FAT32/exFAT — эти FS не имеют POSIX permissions, chown молча игнорируется.
Попробуй сам
- Создай файл и посмотри owner/group:
touch mine.txt ls -l mine.txt # должно быть твой_user:твой_user - Узнай numeric UID и GID:
stat -c '%u %g' mine.txt - Создай файл под sudo и поменяй owner на себя:
sudo touch /tmp/root_owned.txt ls -l /tmp/root_owned.txt sudo chown "$(id -u):$(id -g)" /tmp/root_owned.txt ls -l /tmp/root_owned.txt - Скопируй ownership с одного файла на другой:
touch template.txt new.txt sudo chown nobody:nogroup template.txt sudo chown --reference=template.txt new.txt ls -l template.txt new.txt
macOS-различия
chownна macOS работает одинаково, но дефолтная primary group там обычноstaff(GID 20), не уникальная группа на пользователя.chgrpидентичен.- На APFS меняется ownership как на ext4. На FAT-USB-флешках — игнорируется (нет POSIX-метаданных).
Главное
- Owner + group хранятся в inode рядом с правами.
- Менять owner может только root (через
sudo chown). Менять group — owner файла (если он состоит в target group) или root. - Разделитель user/group —
:(не точка). chown -Rрекурсивно,--reference=otherкопирует ownership с другого файла,--from=oldограничивает scope.- После
chownслетают SUID/SGID — security-мера. - В Docker и в скриптах используй numeric UID/GID — это устраняет зависимость от наличия user в image.