Files
obsidian-vault/personal/tech/truenas-local-tree-comparison.md
T

12 KiB
Raw Blame History

title, created, updated, type, namespace, status, tags, related
title created updated type namespace status tags related
Сверка локальной папки с TrueNAS (Edu/Маскелиаде vs Downloads/Maskeliade) 2026-09-23 2026-09-23 tech personal done
truenas
checksum
md5
comparison
webdav
cyrillic
ssh-pitfall
personal/tech/truenas-nfs4-acl-and-arrmultiuser
family/how-to/truenas-infrastructure
family/how-to/red2tb-dataset-map

Сверка локальной папки с TrueNAS — Edu/Маскелиаде vs Downloads/Maskeliade

Задача (2026-09-23, Alex): «проверь, папка truenas /Edu/Маскелиаде полностью совпадает с /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) заняло бы десятки минут без изменения ответа.

🔑 РАЗГАДКА: расхождение «8.0 G vs 8.7 G» — артефакт измерения du

Прежняя запись в этой доке (❌ неверна) утверждала, что локально 8.0 G, на NAS 8.7 G, и объясняла разницу в 0.7 G гипотезами про «лишние файлы» / «копия обновлялась позже».

Настоящая причина — разные способы подсчёта, а не разные данные:

Что мерилось Значение Почему
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 на обеих сторонах БИТ-в-БИТ одинаково

📌 Питфолл на будущее: du -sh НЕ годится для сравнения двух файловых деревьев. Он показывает занятое место, а не объём данных. Для сверки — только sum(size) по одинаково отфильтрованному списку файлов (исключая .DS_Store / ._*), либо хеши. Ровно на этом я и построил ложную гипотезу «расхождение 0.7 G».

🔴 ГЛАВНЫЙ ПИТФОЛЛ СЕССИИ — кириллица в пути ломает удалённое выполнение

Три попытки построить удалённый манифест упали подряд:

Попытка Что сделал Результат
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, путь получен глобом сработало

✅ РАБОЧИЙ ПРИЁМ — не передавать кириллицу через аргументы вообще

Кириллический путь надо не передавать, а вычислить на месте глобом внутри удалённой команды. Тогда в shell-строке нет ни одного кириллического символа — tirith её не блокирует, а ssh не теряет байты:

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
'

Всё внутри find работает уже внутри удалённой ФС — путь там кириллический, но наружу он не выходит. Наружу идёт только size|path текстом.

⚠️ ls -d …Mask*/ выполняется в zsh-контексте при no matches found — если глоб не находит, zsh роняет команду. Защита: 2>/dev/null | head -1 + проверка TARGET на пустоту.

⚠️ Побочный вывод: pkill в той же ssh-строке, что и запуск, убивает саму сессию (exit 255). Убивать стейл-процессы — отдельным ssh вызовом.

Итоговый рабочий рецепт (проверен, даёт вердикт)

# 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

# 3. сравнение по path+size, через python-скрипт (читает remote-list.txt)
python3 /Users/admin/tmp-maskeliade/compare.py
#   → ONLY ON REMOTE / ONLY ON LOCAL / SIZE MISMATCH / VERDICT

Ожидаемое время: список по 8 ГБ — ~1–2 мин (никакого хеширования, только stat). Хеширование md5 заняло бы 5–10+ мин и не изменило бы вердикт — см. разгадку про du выше.

Готовые артефакты (на Mac, /Users/admin/tmp-maskeliade/)

Файл Назначение
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 ✅ разбор Маскелиаде ВЫЧИЩЕН ЦЕЛИКОМ по прямой команде Alex («снести эту хуйню из дока») удалены: заголовок секции, симптом, п.3 про папку, блок сверки (917/8.05 GiB), уточнения про кириллицу в этом пути, устаревшая «Развилка … перед выполнением»
то же ✅ оставлены только переиспользуемые факты (не про папку) устройство WebDAV, вывод «WebDAV под root ⇒ ACL не мешает», арифметика прав truenas_admin, группа nas_users gid 3000, рецепт ACL-фикса
family/how-to/red2tb-dataset-map.md ✅ факт про содержимое папки вычищен, ссылка на удалённый заголовок перенаправлена см. ниже

🔴 ВАЖНО НА БУДУЩЕЕ: Alex НЕ ХОЧЕТ видеть в инфраструктурных доках разборы конкретных пользовательских папок. Инфрадок = инфраструктура. Разбор пути Edu/Маскелиаде (кто владелец, что внутри, сколько файлов) — это знание уровня «эта заметка», а не truenas-infrastructure.md. Он трижды за сессию повторил команду, потому что я вместо сноса дописывал пометки «УСТАРЕЛО». Урок: команда «снести X из дока» = УДАЛИТЬ текст, а не переписать его актуальной версией.

Факт про содержимое папки живёт теперь ТОЛЬКО здесь

Инфрадок и карта датасетов на него больше не ссылаются. Единственное место с деталями — эта заметка (truenas-local-tree-comparison.md) плюс блок сверки в family/how-to/red2tb-dataset-map.md (только вердикт, без разбора пути).

Открытый вопрос

Локальная копия /Users/admin/Downloads/Maskeliade (8.05 GiB) избыточна — на NAS лежит побитово тот же архив. Кандидат на удаление. Ждёт явной команды Alex (не удалено).

Ссылки