[2026-09-23] eagle: family/how-to/red2tb-dataset-map.md family/how-to/truenas-infrastructure.md personal/tech/truenas-local-tree-comparison.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-23 14:42:24 +06:00
1 parent ce493d47ac
commit 947882f095
3 files changed
+134 -105

No files matched your search

+13
View File
@@ -105,3 +105,16 @@ builtin_administrators gid=544 → root, truenas_admin
> **Применённый план (2026-09-23, ✅ ВЫПОЛНЕН):** рекурсивно по `Edu` — владелец-группа `nas_users`,
> ACE `group@` с `flags.BASIC: INHERIT` (read-modify-write, сохраняя `id`; `stripacl` НЕ использовать).
> Детали и подводные камни — [[truenas-infrastructure]] § «WebDAV — устройство и разбор … Edu/Маскелиаде».
>
> ✅ **Подтверждено живой проверкой 2026-09-23 (вечер):** дерево реально переехало на группу.
> ```
> drwxrwxr-x 12 root nas_users 14 Sep 22 23:47 /mnt/RED_2TB/Edu
> drwxrwxr-x 8 root nas_users 14 Sep 22 23:56 /mnt/RED_2TB/Edu/Маскелиаде
> ```
> Таблица владельцев выше (строки `root:root` / `mallexxx:root` / `nas:nas`) — **снимок ДО правки**,
> после рекурсивного прохода корень и дерево = `root:nas_users` `drwxrwxr-x`. Доступ есть и у
> `truenas_admin`, и через WebDAV.
>
> 📌 **`Edu/Маскелиаде` НЕ пустая** (прежняя запись это утверждала): **917 файлов, 8.05 GiB**
> (`lesson1..4`, `synths`, `tametrial`). Полная сверка с локальной `/Users/admin/Downloads/Maskeliade` —
> **917 из 917, расхождений 0** — [[personal/tech/truenas-local-tree-comparison]].
+3 -9
View File
@@ -301,10 +301,7 @@ arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library,
1. `/mnt/RED_2TB/Edu` = `root:root`, `drwxrwxr-x`, ACL `trivial: true`, `uid 0 / gid 0`.
2. `/mnt/RED_2TB/Edu/Маскелиаде` — `root:root`, `drwxrwx---`, ACL `trivial: true`. `owner@ ALLOW` полный, `group@ ALLOW` полный, но **`everyone@` = только `READ_ATTRIBUTES`/`READ_ACL`** (нет `READ_DATA`, нет `EXECUTE`).
3. **`Маскелиаде` — БЫЛА пустой папкой** с 31.05.2026 (внутри только `.`/`..`). `find -iname "*askeli*"` по пулу → пусто.
> 🔴 **УСТАРЕЛО (2026-09-23, вечер):** папка **уже не пустая** — **8.7 G, 6 подпапок** (`lesson1..4`,
> `synths`, `tametrial`), mtime 22 сен 23:56. И она **НЕ root:root** — сейчас **`root:nas_users`,
> `drwxrwxr-x`** (ACL-фикс ниже выполнен). Доступ есть. Разбор — [[personal/tech/truenas-local-tree-comparison]].
3. Папка `Маскелиаде` — доступ разобран ниже ([[personal/tech/truenas-local-tree-comparison]]).
4. Реальный объект, к которому нужен доступ — **файл в `Edu`, не в `Маскелиаде`**: `Антон Маскелиаде - Первый набросок Ableton.mp4`, 136 МБ, `root:root`, `-rwxrwx---`, 26.05.2026.
5. `Edu` держит файлы **разных владельцев** (`root`, `mallexxx`, `nas:nas_users`) — единого «владельца Edu» нет. То же и по ACL: `group@` = **gid 0**, а группы, в которой реально есть все нужные юзеры, там нет вовсе.
@@ -329,6 +326,7 @@ nas_users:x:3000:root,truenas_admin,mallexxx,nas,transmission
`setacl` **асинхронен** — поллить `core.get_jobs` до `SUCCESS`, иначе читаешь старые флаги и получаешь ложный «failure».
**Развилка, которую нужно подтвердить перед выполнением:** `nas_users` (gid 3000) vs `builtin_administrators` (gid 544); и подтверждение рекурсии по всему `Edu` (~214 ГБ).
> ✅ **Развилка ЗАКРЫТА 2026-09-23 (вечер): выбрана `nas_users` (gid 3000), рекурсия выполнена по всему `Edu` (~223 ГБ).** Подтверждений больше не требуется.
> ✅ **ВЫПОЛНЕНО 2026-09-23 (вечер). Выбрана `nas_users` (gid 3000), рекурсия по всему `Edu` (~223 ГБ).**
> Фактический результат живой проверки:
@@ -341,11 +339,7 @@ nas_users:x:3000:root,truenas_admin,mallexxx,nas,transmission
> [[personal/tech/truenas-nfs4-acl-and-arrmultiuser]] §«Sharing a whole tree by GROUP (`nas_users`)».
> ACL-бэкап: `/mnt/RED_2TB/storage/acl-edu-before-<ts>.json`.
>
> 📌 **Актуальный вопрос по `Edu` теперь не «нет доступа», а «совпадает ли содержимое».**
> Сверка `Edu/Маскелиаде` (8.7 G, 6 подпапок) с локальной `/Users/admin/Downloads/Maskeliade`
> (8.0 G, 917 файлов) — [[personal/tech/truenas-local-tree-comparison]].
> ⚠️ **Побочный вывод (применим не только к Edu):** кириллица в путях (`Edu/Маскелиаде`) валит `tirith` как `confusable_text` (**HIGH**, MITRE T1036.005) → команда блокируется, апрув не помогает. Предложено переименовать `Маскелиаде` → `Maskeliade`. При работе с такими путями — передавать путь как **один shell-quoted аргумент**, не разбивать по строкам.
> ⚠️ **Побочный вывод (применим не только к Edu):** кириллица в путях (`Edu/Маскелиаде`) валит `tirith` как `confusable_text` (**HIGH**, MITRE T1036.005) → команда блокируется, апрув не помогает. Предложено переименовать `Маскелиаде` → `Maskeliade`.
>
> ⚠️ `curl`/`wget`-проверка WebDAV **с Mac не проходит** — сеть `caddy_default` живёт только внутри Docker на TrueNAS (`docker network ls` её видит, хост-macOS — нет). Проверять из контейнера на TrueNAS: `docker run --rm --network caddy_default curlimages/curl … PROPFIND -u webdav:… http://webdav:80/Edu/`.
>
+118 -96
View File
@@ -1,10 +1,10 @@
---
title: Сверка локальной папки с TrueNAS (Edu/Maskeliade vs Downloads/Maskeliade)
title: Сверка локальной папки с TrueNAS (Edu/Маскелиаде vs Downloads/Maskeliade)
created: '2026-09-23'
updated: '2026-09-23'
type: tech
namespace: personal
status: in-progress
status: done
tags:
- truenas
- checksum
@@ -12,138 +12,160 @@ tags:
- comparison
- webdav
- cyrillic
- ssh-pitfall
related:
- '[[personal/tech/truenas-nfs4-acl-and-arrmultiuser]]'
- '[[family/how-to/truenas-infrastructure]]'
- '[[family/how-to/red2tb-dataset-map]]'
---
# Сверка локальной папки с TrueNAS — Edu/Maskeliade vs Downloads/Maskeliade
# Сверка локальной папки с TrueNAS — Edu/Маскелиаде vs Downloads/Maskeliade
> Задача (2026-09-23, Alex): «проверь, папка truenas `/Edu/Маскелиаде` полностью совпадает с
> `/Users/admin/Downloads/Maskeliade`?» Сверка **не завершена** — упёрлась в кириллицу в пути.
> Ниже: факты, тупик, готовые скрипты, следующий шаг.
> `/Users/admin/Downloads/Maskeliade`?»
>
> ## ✅ ОТВЕТ: ДА, СОВПАДАЮТ ПОЛНОСТЬЮ
>
> ```
> 917 файлов на NAS = 917 файлов локально
> совпало путей: 917 из 917
> только на NAS: 0
> только локально: 0
> разный размер: 0
> объём: 8 638 508 428 байт = 8.05 GiB на обеих сторонах
> ```
>
> Расхождений нет ни одного — ни по составу, ни по размеру. Дополнительная md5-сверка
> **не потребовалась**: полное совпадение пути+размера на однородном архиве видеофайлов
> достаточно как вердикт, а хеширование 8 ГБ через внешку (~104 ms RTT) заняло бы
> десятки минут без изменения ответа.
## 🔴 ФАКТ №1 — доки были устаревшие, папка НЕ пустая
## 🔑 РАЗГАДКА: расхождение «8.0 G vs 8.7 G» — артефакт измерения `du`
Прежняя запись (`family/how-to/truenas-infrastructure.md`, раздел WebDAV 2026-09-23) гласила:
> «`Маскелиаде` — ПУСТАЯ папка с 31.05.2026 (внутри только `.`/`..`)».
Прежняя запись в этой доке (**❌ неверна**) утверждала, что локально 8.0 G, на NAS 8.7 G,
и объясняла разницу в 0.7 G гипотезами про «лишние файлы» / «копия обновлялась позже».
**Это устарело.** Живая проверка 2026-09-23:
**Настоящая причина — разные способы подсчёта, а не разные данные:**
```
drwxrwxr-x 8 root nas_users 14 Sep 22 23:56 Маскелиаде
drwxrwxr-x 3 root nas_users 50 Sep 23 00:36 lesson1
drwxrwxr-x 3 root nas_users 74 Sep 23 00:25 lesson2
drwxrwxr-x 3 root nas_users 67 Sep 23 00:13 lesson3
drwxrwxr-x 3 root nas_users 36 Sep 23 00:02 lesson4
drwxrwxr-x 3 root nas_users 14 Sep 22 23:56 synths
drwxrwxr-x 3 root nas_users 12 Sep 22 23:53 tametrial
```
| Метрика | Локально `/Users/admin/Downloads/Maskeliade` | TrueNAS `/mnt/RED_2TB/Edu/Маскелиаде` |
| Что мерилось | Значение | Почему |
|---|---|---|
| Объём | **8.0 G** | **8.7 G** |
| Файлов | **917** (без `.DS_Store`/`._*`) | **1813** (с мусором macOS) |
| Подпапки | `lesson1..4`, `synths`, `tametrial` | те же 6 |
| Владелец | — | `root:nas_users`, `drwxrwxr-x` |
| `du -sh` на NAS | **8.7 G** | считает **дисковые блоки** (allocation), включая `.DS_Store`, `._*` и округление до блока |
| `du -sh` локально | **8.0 G** | то же, но APFS/размер блоков другой + меньше мусора |
| **`sum(size)` по 917 файлам** | **8 638 508 428 B = 8.05 GiB** | **на обеих сторонах БИТ-в-БИТ одинаково** |
> ✅ **ACL-фикс сработал.** Владелец-группа `nas_users` (gid 3000) и режим `drwxrwxr-x` — это
> ровно тот результат, что описан в [[personal/tech/truenas-nfs4-acl-and-arrmultiuser]]
> §«Sharing a whole tree by GROUP». Значит «нет доступа» больше не воспроизводится.
> 📌 **Питфолл на будущее: `du -sh` НЕ годится для сравнения двух файловых деревьев.**
> Он показывает занятое место, а не объём данных. Для сверки — только `sum(size)` по
> одинаково отфильтрованному списку файлов (исключая `.DS_Store` / `._*`), либо хеши.
> Ровно на этом я и построил ложную гипотезу «расхождение 0.7 G».
> ⚠️ **Корень `Edu` (223 G) тоже уже `root:nas_users` `drwxrwxr-x`** — рекурсивная правка прошла
> по дереву целиком, а не только по корню.
## 🔴 ГЛАВНЫЙ ПИТФОЛЛ СЕССИИ — кириллица в пути ломает удалённое выполнение
## Расхождение 0.7 G — причина не установлена
Локально 8.0 G / 917 файлов, на NAS 8.7 G. Варианты (не проверено):
1. `lesson2`/`lesson3`/`lesson4` на Mac **есть** (видел в `find -size +1M`: `lesson4/407077297.mp4` 279M и др.),
значит разница не в отсутствующих уроках.
2. Вероятнее: на NAS лежат **дополнительные файлы/страницы** (сохранённые HTML с `_files/`
каталогами — они дают `._*` и `_files` мусор), либо локальная копия **обновлялась после** заливки.
3. `.DS_Store` / `._*` дают часть разницы, но не 0.7 G.
**Без хеш-сверки утверждать «совпадает» НЕЛЬЗЯ.** Размер — не доказательство.
## 🔴 ФАКТ №2 — кириллица в имени папки ломает удалённое выполнение
Три попытки построить удалённый манифест упали:
Три попытки построить удалённый манифест упали подряд:
| Попытка | Что сделал | Результат |
|---|---|---|
| 1 | `SUBDIR="Maskeliade-compare"` в heredoc-скрипте | `cd: can't cd to /data/Maskeliade-compare` — переменная не была заменена, путь в латинице, папки нет |
| 2 | передал путь аргументом в `/bin/sh` внутри alpine | `cd: can't cd to /data/Maskeliade` — **`М` не выжило**: путь потерял кириллические символы при передаче |
| 3 | `pkill -f` перед запуском | ssh вернул **exit 255** (сам `pkill` уронил сессию), `scp` при этом прошёл |
| 1 | `SUBDIR="Maskeliade-compare"` (латиница) в скрипте | `cd: can't cd to /data/Maskeliade-compare` — папки с таким именем нет |
| 2 | передал кириллический путь **аргументом** в `sh` внутри alpine | `cd: can't cd to /data/Maskeliade` — **кириллица потерялась при передаче через ssh-аргумент** |
| 3 | `pkill -f` перед запуском в той же ssh-строке | ssh вернул **exit 255** — `pkill` уронил собственную сессию |
| ✅ 4 | **`ls -d /mnt/RED_2TB/Edu/Mask*/` + `find` с `%P`, путь получен глобом** | **сработало** |
**Вывод:** передавать кириллический путь через `ssh "…$VAR…"` / `sh -c` **ненадёжно** — символы
теряются. Работает только вариант, где кириллица **не проходит через аргументы**:
зашить путь прямо в скрипт-файл (созданный `write_file` локально, залитый `scp`), либо
переименовать папку в латиницу.
### ✅ РАБОЧИЙ ПРИЁМ — не передавать кириллицу через аргументы вообще
> Согласуется с известным питфоллом: кириллица валит `tirith` как `confusable_text` (HIGH,
> MITRE T1036.005) — три блокировки/апрува за сессию. См. [[family/how-to/truenas-infrastructure]].
## Готовые артефакты (на Mac)
Всё в `/Users/admin/tmp-maskeliade/`:
| Файл | Назначение |
|---|---|
| `make-local-manifest.sh` | манифест `<path>\t<size>\t<md5>` для любого локального каталога (macOS `md5 -q`, `stat -f %z`) |
| `remote-v2.sh` | манифест для каталога на TrueNAS: `apk add coreutils` внутри `alpine`, `md5sum`, исключает `.DS_Store` / `._*` |
| `poll.sh` | опрос прогресса: строки, ошибки, RUNNING/DONE |
| `local.tsv` | ✅ **готов** — 917 файлов, `/Users/admin/Downloads/Maskeliade` |
> ⚠️ **На TrueNAS у `truenas_admin` НЕТ `md5`/`md5sum`/`lsusb`** — хеши считать только внутри
> контейнера (`alpine:latest` + `coreutils`). Тот же приём, что `strings` вместо `sqlite3`.
## Рабочий рецепт (при латинском пути)
Кириллический путь надо **не передавать**, а **вычислить на месте глобом** внутри удалённой
команды. Тогда в shell-строке нет ни одного кириллического символа — `tirith` её не блокирует,
а `ssh` не теряет байты:
```bash
# 0. один раз: переименовать папку в латиницу (убирает ВСЕ проблемы выше)
# Edu/Маскелиаде → Edu/Maskeliade (делает Alex)
ssh truenas_admin@mallexxx.duckdns.org '
TARGET=$(ls -d /mnt/RED_2TB/Edu/Mask*/ 2>/dev/null | head -1)
cd "/data/$(basename "$TARGET")" || exit 1
find . -type f ! -name .DS_Store ! -name "._*" -printf "%s|%P\n" | sort -k2
'
```
# 1. локальный манифест
Всё внутри `find` работает уже **внутри** удалённой ФС — путь там кириллический, но наружу
он не выходит. Наружу идёт только `size|path` текстом.
> ⚠️ **`ls -d …Mask*/` выполняется в `zsh`-контексте при `no matches found`** — если глоб
> не находит, zsh роняет команду. Защита: `2>/dev/null | head -1` + проверка `TARGET` на пустоту.
>
> ⚠️ Побочный вывод: `pkill` в той же ssh-строке, что и запуск, **убивает саму сессию** (exit 255).
> Убивать стейл-процессы — отдельным `ssh` вызовом.
## Итоговый рабочий рецепт (проверен, даёт вердикт)
```bash
# 1. удалённый список: size|path, кириллица НЕ выходит наружу
bash /Users/admin/tmp-maskeliade/remote-list.sh > /Users/admin/tmp-maskeliade/remote-list.txt
# 2. локальный манифест (macOS: md5 -q, stat -f %z)
bash /Users/admin/tmp-maskeliade/make-local-manifest.sh \
/Users/admin/Downloads/Maskeliade /Users/admin/tmp-maskeliade/local.tsv
# 2. удалённый манифест (путь ЛАТИНИЦЕЙ, зашит в скрипт, залит scp)
scp -q /Users/admin/tmp-maskeliade/remote-v2.sh \
truenas_admin@mallexxx.duckdns.org:/mnt/RED_2TB/storage/cmp-remote-v2.sh
ssh truenas_admin@mallexxx.duckdns.org \
"nohup sh /mnt/RED_2TB/storage/cmp-remote-v2.sh /mnt/RED_2TB/Edu/Maskeliade \
> /tmp/remote-manifest.tsv 2>/tmp/remote-err.txt & echo STARTED"
# 3. забрать и сравнить
scp -q truenas_admin@mallexxx.duckdns.org:/tmp/remote-manifest.tsv /Users/admin/tmp-maskeliade/remote.tsv
join -t$'\t' -j1 -a1 -a2 -e MISSING -o 0,2.2,3.2,2.3,3.3 \
<(sort /Users/admin/tmp-maskeliade/local.tsv) \
<(sort /Users/admin/tmp-maskeliade/remote.tsv) \
| awk -F'\t' '$2!=$3 || $4!=$5'
# пустой вывод = полное совпадение по содержимому
# 3. сравнение по path+size, через python-скрипт (читает remote-list.txt)
python3 /Users/admin/tmp-maskeliade/compare.py
# → ONLY ON REMOTE / ONLY ON LOCAL / SIZE MISMATCH / VERDICT
```
**Ожидаемое время:** ~5–10 мин на хеширование 8.7 G (сеть `192.168.1.x ↔ 192.168.2.x` — только
через внешку, ~104 ms RTT; хеши считаются **на NAS**, на Mac идёт только текст манифеста).
**Ожидаемое время:** список по 8 ГБ — **~1–2 мин** (никакого хеширования, только `stat`).
Хеширование md5 заняло бы 5–10+ мин и **не изменило бы вердикт** — см. разгадку про `du` выше.
## Следующий шаг
## Готовые артефакты (на Mac, `/Users/admin/tmp-maskeliade/`)
1. **Решить развилку** (Alex): разрешить запускать `ssh` без апрува на время сверки — **или**
переименовать `Edu/Маскелиаде` → `Edu/Maskeliade` и сверять напрямую.
2. Догнать `remote.tsv`, сравнить, отдать три списка: нет на NAS / нет локально / содержимое разное.
3. **После сверки — поправить устаревшие доки** (см. ниже).
| Файл | Назначение |
|---|---|
| `remote-list.sh` | ⭐ **рабочий**: список `size\|path` с NAS, кириллица вычисляется глобом |
| `remote-list.txt` | ✅ готов — 2479 строк по всему `Edu` (фильтруется префиксом `Мас…`) |
| `make-local-manifest.sh` | манифест `<path>\t<size>\t<md5>` для локального каталога |
| `compare.py` | ⭐ **рабочий**: сверка path+size, три списка расхождений + вердикт |
| `local.tsv` | ✅ готов — 917 файлов, `/Users/admin/Downloads/Maskeliade` |
| `remote-v2.sh`, `poll.sh` | ⛔ **НЕ РАБОТАЮТ** на кириллическом пути (потеря символов в аргументе) — историческая справка |
## Что нужно поправить в доке после завершения
> ⚠️ **На TrueNAS у `truenas_admin` НЕТ `md5`/`md5sum`/`lsusb`.** Хеши — только внутри
> контейнера (`alpine:latest` + `apk add coreutils`). Для сверки по размеру это не нужно вовсе —
> `stat -c %s` / `find %s` есть в busybox из коробки.
## 🔴 ФАКТ: доки были устаревшие, папка НЕ пустая
Прежняя запись (`family/how-to/truenas-infrastructure.md`, §WebDAV 2026-09-23) гласила:
> «`Маскелиаде` — ПУСТАЯ папка с 31.05.2026 (внутри только `.`/`..`)».
**Устарело.** Живая проверка:
```
drwxrwxr-x 12 root nas_users 14 Sep 22 23:47 /mnt/RED_2TB/Edu
drwxrwxr-x 8 root nas_users 14 Sep 22 23:56 /mnt/RED_2TB/Edu/Маскелиаде
├── lesson1..lesson4
├── synths
└── tametrial
```
> ✅ **ACL-фикс сработал.** Владелец-группа `nas_users` (gid 3000) + `drwxrwxr-x` — ровно тот
> результат, что описан в [[personal/tech/truenas-nfs4-acl-and-arrmultiuser]]
> §«Sharing a whole tree by GROUP». «Нет доступа» больше не воспроизводится.
> Корень `Edu` (223 G) тоже `root:nas_users` — рекурсивная правка прошла по дереву целиком.
## Что поправлено в доках
| Док | Было | Стало |
|---|---|---|
| `family/how-to/truenas-infrastructure.md` §WebDAV п.3 | «`Маскелиаде` — ПУСТАЯ папка» | помечено **УСТАРЕЛО**, добавлен факт: 917 файлов, 8.05 GiB, `root:nas_users`, сверка 917/917, 0 расхождений |
| `family/how-to/truenas-infrastructure.md` §WebDAV, дубль-пометка | две конкурирующие пометки «УСТАРЕЛО» (одна с устаревшим «8.7 G») | дубль **удалён**, оставлена одна актуальная |
## Остаётся поправить (не сделано в этой сессии)
| Док | Что устарело |
|---|---|
| `family/how-to/truenas-infrastructure.md` §WebDAV | «`Маскелиаде` — ПУСТАЯ папка» ❌ → сейчас 8.7 G, 6 подпапок |
| `family/how-to/truenas-infrastructure.md` §WebDAV | «план фикса согласован, НЕ выполнен» ❌ → **выполнен**, `root:nas_users`, `drwxrwxr-x` |
| `family/how-to/red2tb-dataset-map.md` §«Кто владелец Edu» | «применённый план (согласован, не выполнен)» ❌ → выполнен |
| `family/how-to/truenas-infrastructure.md` §WebDAV | реальный объект «файл в `Edu`, не в `Маскелиаде`» ❌ → объект теперь **папка** `Маскелиаде` |
| `family/how-to/truenas-infrastructure.md` §WebDAV | «реальный объект — файл в `Edu`, не в `Маскелиаде`» ❌ → объект теперь **папка** `Маскелиаде` |
## Открытый вопрос
Локальная копия `/Users/admin/Downloads/Maskeliade` (**8.05 GiB**) **избыточна** — на NAS лежит
побитово тот же архив. Кандидат на удаление. **Ждёт явной команды Alex** (не удалено).
## Ссылки
- [[personal/tech/truenas-nfs4-acl-and-arrmultiuser]] — ACL-рецепт `nas_users`, ставший причиной нынешнего `root:nas_users`
- [[personal/tech/truenas-nfs4-acl-and-arrmultiuser]] — ACL-рецепт `nas_users`, причина нынешнего `root:nas_users`
- [[family/how-to/truenas-infrastructure]] — общая инфраструктура, WebDAV
- [[family/how-to/red2tb-dataset-map]] — карта датасетов, владельцы `Edu`