Ponowne łączenie usuniętego pliku

33

Czasami ludzie usuwają pliki, których nie powinni, długotrwały proces nadal ma otwarty plik, a odzyskiwanie danych przez catting /proc/<pid>/fd/Npo prostu nie jest wystarczająco niesamowite. Wystarczająco niesamowite byłoby, gdybyś mógł „cofnąć” usunięcie, uruchamiając jakąś magiczną opcję ln, która pozwoliłaby ci ponownie połączyć się z numerem i-węzła (odzyskanym przez lsof).

Nie mogę znaleźć żadnych narzędzi do Linuksa, aby to zrobić, a przynajmniej pobieżnego Googlinga.

Co masz, błąd serwera?

EDYCJA 1: Powodem, dla którego catowanie pliku /proc/<pid>/fd/Nnie jest wystarczająco niesamowite, jest to, że proces, który wciąż ma otwarty plik, wciąż do niego zapisuje. Usunięcie usuwa odwołanie do i-węzła z przestrzeni nazw systemu plików. To, czego chcę, to sposób na odtworzenie referencji.

EDYCJA 2: „debugfs ln” działa, ale ryzyko jest zbyt wysokie, ponieważ frobuje surowe dane systemu plików. Odzyskany plik jest również szalony niespójny. Liczba linków wynosi zero i nie mogę dodawać do nich linków. Mam gorzej, ponieważ mogę po prostu /proc/<pid>/fd/Nuzyskiwać dostęp do danych bez uszkadzania mojego fs.

mbac32768
źródło

Odpowiedzi:

14

Wystarczająco niesamowite byłoby, gdybyś mógł „cofnąć” usunięcie, uruchamiając jakąś magiczną opcję ln, która pozwoliłaby ci ponownie połączyć się z numerem i-węzła (odzyskanym przez lsof).

Ta niesamowitość została wprowadzona lnw wersji 8.0 (GNU / coreutils) z -L|--logicalopcją, która powoduje pierwsze lnzaniedbanie /proc/<pid>/fd/<handle>. To takie proste

ln -L /proc/<pid>/fd/<handle> /path/to/deleted/file

wystarczy ponownie połączyć usunięty plik.

tnimeu
źródło
7
To nie działa; jeśli plik zostanie usunięty, zakończy się niepowodzeniem.
Random832,
1
Nie zrobi tego. Regularnie używam tego do przywracania usuniętych, ale wciąż otwartych plików. Ale musisz się upewnić, że nowy /path/to/deleted/fileznajduje się w tym samym systemie plików, co plik tuż przed jego usunięciem, w przeciwnym razie to - w rzeczy samej - nie powiedzie się. (Możesz dostać starą ścieżkę za pomocą ls -l /proc/<pid>/fd/<handle>)
tnimeu
2
Ten rodzaj funkcjonalności (zobacz to pytanie i odpowiedź) został szczególnie odrzucony jako zagrożenie bezpieczeństwa [dla hipotetycznego schematu bezpieczeństwa obracającego się wokół uprzywilejowanego procesu, dającego procesowi uchwyt pliku tylko do odczytu dla pliku, który posiadasz, ale w przeciwnym razie nie masz dostępu do ]; Próbowałem (choć z małym programem C bezpośrednio używać odpowiedniego wywołania systemowego) i nie działało.
Random832,
7
Oczywiście przetestowałem to przed opublikowaniem mojego rozwiązania i wtedy faktycznie dla mnie zadziałało. Nie wiedziałem, że działało to tylko na tmpfssystemach plików, ale nie na np ext3. Ponadto ta funkcja została całkowicie wyłączona w 2.6.39, zobacz zatwierdzenie . Dlatego to rozwiązanie nie będzie działać z jądrem 2.6.39 lub nowszym, a we wcześniejszych wersjach zależy to od systemu plików.
tnimeu
7
@tnimeu ln -Lnie działa dla mnie. Mam usunięty plik i próbowałem ponownie połączyć go z pierwotną ścieżką. lndaje mi ln: failed to create hard link /my/path/file.pdf => /proc/19674/fd/16: No such file or directory. Ale mogę np. Z powodzeniemcat /proc/19674/fd/16
Eugene Beresovsky
13

Wygląda na to, że już dużo rozumiesz, więc nie będę wchodził w szczegóły. Istnieje kilka metod znalezienia i-węzła i zwykle można cat i przekierować STDOUT. Możesz użyć debugfs. Uruchom to polecenie w ciągu:

ln <$INODE> FILENAME

Upewnij się, że masz kopie zapasowe systemu plików. Prawdopodobnie będziesz musiał później uruchomić fsck. Przetestowałem to z powodzeniem, gdy i-węzeł wciąż jest zapisywany i działa, aby utworzyć nowe twarde łącze do dereferencyjnego i-węzła.

Jeśli plik zostanie rozłączony z nieotwartym plikiem w ext3, dane zostaną utracone. Nie jestem pewien, jak konsekwentnie jest to prawda, ale większość moich możliwości odzyskiwania danych dotyczy ext2. Z ext3 FAQ:

P: Jak mogę odzyskać (cofnąć) usunięte pliki z partycji ext3? Właściwie nie możesz! Tak powiedział o tym jeden z programistów, Andreas Dilger:

Aby zapewnić, że ext3 może bezpiecznie wznowić odłączenie po awarii, faktycznie zeruje wskaźniki bloków w i-węzle, podczas gdy ext2 tylko zaznacza te bloki jako nieużywane w bitmapach bloków i oznacza i-węzeł jako „usunięty” i opuszcza blok same wskazówki.

Jedyną nadzieją jest „grep” dla części plików, które zostały usunięte, i mam nadzieję na najlepsze.

W tym pytaniu znajdują się również istotne informacje:

Nadpisałem duży plik pustym plikiem na serwerze Linux. Czy mogę odzyskać istniejący plik?

Warner
źródło
Mam nadzieję, że komentarz został usunięty, ponieważ nie był rewelacyjny.
mdpc,
1
W przypadku usuniętego, ale wciąż otwartego pliku, nie sądzę, aby wyzerował wskaźniki w i-węzle. Ponadto zamiast używania „ln” w debugfach użyłbym „cofnij”, aby liczba referencji i-węzła została poprawnie zaktualizowana.
Mark Wagner,
Nie miałem na myśli aluzji jako takiego, embobo. Nie, przetestowałem wydajność. Wyjaśniłem swój język.
Warner,
Sprytne, ale psuje mój system plików. :)
mbac32768,
To jedyne rozwiązanie dla scenariusza, w którym go opisujesz. Manipulowanie systemem plików na niskim poziomie, który jest podłączony rw i jest aktywnie zapisywany, może spowodować uszkodzenie w prawie wszystkich scenariuszach.
Warner,
8

debugfs, jak widzieliście, tak naprawdę nie działa, a co najwyżej plik zostanie automatycznie usunięty (z powodu dziennika) po ponownym uruchomieniu komputera, aw najgorszym wypadku możesz zniszczyć system plików, co spowoduje „ponowny cykl śmierci”. Właściwe rozwiązanie (TM) polega na przeprowadzeniu cofnięcia usunięcia na poziomie VFS (co ma również dodatkową zaletę pracy z praktycznie wszystkimi obecnymi systemami plików Linux). Systemowy sposób wywoływania (flink) był zastrzelony za każdym razem, gdy pojawiał się w LKML, więc najlepszym sposobem jest moduł + ioctl.

Projekt, który implementuje to podejście i ma dość mały i czysty kod, to fdlink ( https://github.com/pkt/fdlink.git dla wersji testowanej z jądrem Ubuntu Maverick). Dzięki niemu po wstawieniu modułu (sudo insmod flink_dev.ko) możesz po prostu zrobić „./flinkapp / proc // fd / X / my / link / path” i zrobi dokładnie to, co chcesz.

Możesz także użyć przekierowanej wersji vfs-undelete.sourceforge.net, która również działa (i może również automatycznie łączyć się ponownie z oryginalną nazwą), ale kod fdlink jest prostszy i działa równie dobrze, więc to moja preferencja.

pktoss
źródło
3

Nie wiem, jak zrobić dokładnie to, co chcesz, ale chciałbym:

  • Otwórz plik RO z innego procesu
  • Poczekaj na zakończenie oryginalnego procesu
  • Skopiuj dane z otwartego FD do pliku

Oczywiście nie idealne, ale możliwe. Inną opcją jest bawienie się debugfami (za pomocą linkpolecenia), ale to trochę przerażające na maszynie produkcyjnej!

Bill Weiss
źródło
Polecenie debugfs link w ogóle nie obsługuje tego przypadku użycia.
mbac32768,
tldp.org/HOWTO/Ext2fs-Undeletion-11.html sugeruje, że tak. Nie próbowałem tego, ale wydaje się to rozsądne.
Bill Weiss,
linknie działał w moich testach, ale działał ln.
Warner,
3

Wpadłem dzisiaj na ten sam problem. Najlepsze, co mogłem wymyślić, to biegać

% tail -n +0 -f /proc/<pid>/fd/<fd> /path/to/deleted_file

w sesji tmux / screen aż do zakończenia procesu.

nickray
źródło
2
Linkowanie do oryginalnych plików, tak jak w zaakceptowanej odpowiedzi, powinno działać.
Chris S,
1
Nie ma żadnej akceptowanej odpowiedzi na to pytanie, do którego masz odniesienie?
Hamman Samuel
Czy nie powinno to wymagać przekierowania ( >) do usuniętego pliku?
ncasas
1

Interesujące pytanie. Ankieter zadał mi to samo pytanie podczas rozmowy o pracę. Powiedziałem mu, że nie było łatwego sposobu na zrobienie tego i ogólnie nie było warte poświęconego czasu i wysiłku. Zapytałem go, co według niego jest rozwiązaniem tego problemu ...

  1. Użyj lsof, aby znaleźć numer i-węzła na dysku dla procesu, ponieważ będzie on nadal wyświetlany, nawet jeśli plik został usunięty ... kluczem jest to, że jest nadal otwarty.
  2. Wyodrębnij oparte na tym informacje z systemu plików za pomocą debugera systemu plików.
mdpc
źródło
Mogę dobrze wyodrębnić dane z / proc / <pid> / fd / N, ale nie o to mi chodzi.
mbac32768,
1

Użyj icat Sleuthkit.

sudo icat /dev/rdisk1s2 5484287 > accidentally_deleted_open_file
Izaak
źródło
Działa to poprzez ominięcie funkcjonalności systemu plików systemu operacyjnego i bezpośrednią analizę bajtów dysku.
Flimm
0

Szybkie rozwiązanie, które zadziałało dla mnie bez zastraszania narzędzi:

1) znajdź proces + fd, patrząc bezpośrednio w / proc:

ls -al /proc/*/fd/* 2>/dev/null | grep {filename}

2) Następnie technika podobna do @ nickray's, pvwrzucona:

tail -c +0 -f /proc/{procnum}/fd/{fdnum} | pv -s {expectedsize} > {recovery_filename}

Po ls /proc/{procnum}/fd/{fdnum}zakończeniu może być konieczne naciśnięcie klawiszy Ctrl + C ( poinformuje cię, że plik już nie istnieje)), ale jeśli znasz dokładny rozmiar w bajtach, możesz go użyć, pv -Saby zakończyć działanie po osiągnięciu liczby.

ksenoid
źródło