179 lines
12 KiB
Markdown
179 lines
12 KiB
Markdown
---
|
||
title: Сверка локальной папки с TrueNAS (Edu/Маскелиаде vs Downloads/Maskeliade)
|
||
created: '2026-09-23'
|
||
updated: '2026-09-23'
|
||
type: tech
|
||
namespace: personal
|
||
status: done
|
||
tags:
|
||
- truenas
|
||
- checksum
|
||
- md5
|
||
- 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/Маскелиаде 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` не теряет байты:
|
||
|
||
```bash
|
||
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` вызовом.
|
||
|
||
## Итоговый рабочий рецепт (проверен, даёт вердикт)
|
||
|
||
```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
|
||
|
||
# 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** (не удалено).
|
||
|
||
## Ссылки
|
||
|
||
- [[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`
|