Postanowiłem sprzedać jeden z posiadanych dysków sieciowych (w celu zakupienia nowego, większego i lepszego) i stanąłem przed problemem wymazania znajdujących się danych. Wymazania, a nie skasowania czyli nie tylko usunięcia plików, ale także usunięcie pozostałości zalegających na nieużywanych obecnie obszarach dysku.

Pierwsze co zasugerował Google to komenda sfill z pakietu secure-delete. W wersji podstawowej wykonuje ona dwa przebiegi: najpierw wypełnia całe wolne miejsce losowymi bajtami, a następnie wypełnia je zerami. W wersji high-end wykonuje 38(!) przebiegów z różnymi kombinacjami danych losowych, zer i specjalnie opracowanych ciągów bajtów mających uniemożliwić odzyskanie oryginalnej zawartości. Ponieważ chciałem pozbyć się dysku jeszcze w tym roku, wybrałem wersję podstawową. Uruchomiłem sfill, zostawiłem komputer na kilka godzin i po sprawdzeniu okazało się, że wyczyszczone zostało około 1% wolnej powierzchni. Dalsze poszukiwania wskazały winowajcę: urządzenie /dev/urandom dostarczające losowych danych jest koszmarnie powolne.

Rozwiązaniem równie skutecznym - wierzę na słowo autorom dokumentacji - a znacznie szybszym okazał się OpenSSL (z małą tylko pomocą /dev/urandom). A dokładnie jakże urocze polecenie

openssl enc -aes-256-cbc -pass pass:"$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64)" -nosalt >random.bin

zapisujące losowe dane do random.bin tak długo, aż skończy się wolne miejsce. Potem pozostało skasować utworzony plik i voilà. Dla pewności jeszcze tylko wyzerowanie wolnego miejsca:

cat /dev/zero >zero.bin

Cała operacja trwała nieco ponad dobę dla dysku o pojemności 2TB, co jest całkiem rozsądną ceną za to, iż nikt już nie odzyska moich zdjęć wujka Floyda i cioci Beth.

Envers to część Hibernate ORM pozwalająca zapamiętywać historię zmian utrwalanych obiektów. Wystarczy dodać do klas encji kilka adnotacji, aby po każdym zapisie do głównej tabeli tworzony był wpis w tabeli historycznej pozwalający prześledzić co i kiedy zostało zmienione. Od wersji 4.1 Envers pozwala na rejestrowanie nie tylko wartości atrybutów, ale również znaczników określających czy w danej rewizji atrybut zmienił się w stosunku do rewizji poprzedniej (bez tego trzeba by było pracowicie porównywać kolejne wpisy). Niestety nie ma możliwości wygodnego odczytania tych informacji i choć dotyczące tego zgłoszenie HHH-8058 jest w Jirze od prawie roku, to nikt nie zabrał się jego realizację. Co ciekawe Envers zwraca stosowne dane, ale tylko “na potrzeby wewnętrzne” - w publicznym API nie są one już dostępne.

Dodanie stosownej funkcji okazało się bardzo proste - wymagało jedynie zmiany w klasie AuditQueryCreator tworzącej zapytania i oczywiście implementacji samego zapytania (w dużej mierze w oparciu o istniejący kod). Poprawki dla Hibernate w wersji 4.2.x i 4.3.x dostępne są w moim forku projektu hibernate-orm w branchach 4.2.HHH-8058 i 4.3.HHH-8058 w Githubie.

Ponieważ jednak potrzebowałem działającego rozwiązania na już, a czekanie na oficjalne zaakceptowanie (lub odrzucenie :-) moich commitów może potrwać kolejny rok, popełniłem rozszerzenie Enversa, które w ogóle nie ingeruje w oryginalny kod.

<dygresja>Przy okazji odkryłem bardzo sprytną aplikację do umieszczania na stronach WWW kodów źródłowych z Githuba - efekty poniżej.</dygresja>

Nowa fabryka AuditReaderów działa dokładnie tak jak oryginalna – jedyna różnica to typ obiektu zwracanego przez metodę get:


Tak samo interfejs ExtAuditReader różni się od oryginału tylko typem zwracanym przez metodę createQuery:


Implementacja ExtAuditReadera to formalność: zmieniamy zwracany typ i zachowujemy referencję do konfiguracji (jest w oryginalnej klasie, ale prywatna):


Powoli dochodzimy do sedna. Rozszerzenie AuditQueryCreatora dodaje nową metodę forRevisionsOfEntityAndChanges(Class c, boolean selectDeletedEntities), która tworzy zapytanie zwracające nazwy zmienionych atrybutów. Jest podobna do forRevisionsOfEntity, jednak nie ma parametru selectEntitiesOnly – nie ma sensu zwracanie samych obiektów, skoro interesują nas i obiekty i lista zmian. Tak jak w ExtAuditReaderImpl musimy sami zapamiętać konfigurację i readera - są prywatne w klasie bazowej:


I w końcu właściwa implementacja zapytania. Dziedziczymy ze standardowego zapytania RevisionsOfEntityQuery, ale zmieniamy metodę list obrabiającą wyniki zapytania. Dodajemy również metodę, która wyszuka wszystkie atrybuty mające znacznik modyfikacji ustawiony na true. Na koniec dodajemy kopię metody getRevisionNumber – jest prywatna w klasie bazowej a potrzebujemy jej w list:


Składając wszystko razem możemy zapytać Enversa o nazwy zmienionych atrybutów w następujący sposób:


Kompletny projekt zawierający powyższe klasy, gotowy do zbudowanie Mavenem można ściągnąć z Githuba , w wersjach dla Hibernate 4.2.8.Final i 4.3.1.Final.

A co. Mój blog to mi wolno.

Kilka dni temu Apple był uprzejmy zaakceptować moją pierwszą sensowną aplikację działającą na iOS. Nie jest to moja pierwsza aplikacja w ogóle, ale poprzednia była średnio sensowna z racji trudnej współpracy z zamawiającym i, niech jej ziemia lekką będzie, już nie jest dostępna w App Store.

Aplikacja numer dwa służy do monitorowania maszyny wirtualnej Java za pomocą doskonałej biblioteki Jolokia . Jak na razie nie potrafi zbyt wiele (tzn. wersja iOSowa, nie sama biblioteka) - wyświetla tylko ilość zajętej pamięci i obciążenie procesora:


 ale mam ambitne plany aby dodać więcej informacji.

App Store

Po raz kolejny mojemu backupu trafiła się przypadłość pod tytułem "To improve reliability, Time Machine must create a new backup for you".


Przy pierwszym razie rzeczywiście pozwoliłem na utworzenie nowej kopii (tracąc wszystkie poprzednie). Przy drugim pomyślałem że w końcu co, kurczę blade, nie po to się robi backupy aby je potem tracić, odłączyłem dysk od routera, podpiąłem do komputera i - posiłkując się kilkom tutorialami z sieci - reanimowałem go. Przy trzecim razie uznałem, że trzeba wiedzę zebrać w jednym miejscu bo najwyraźniej będzie się od czasu do czasu przydawać. Uruchamiamy Terminal i:

1) Po podłączeniu dysku do komputera zostanie on automatycznie zamontowany. U mnie nazywa się Time Machine, więc jest dostępny jako /Volumes/Time\ Machine i zawiera tylko jeden plik: nazwa.sparsebundle.

2) Profilaktycznie ustawiamy uprawnienia - system po stwierdzeniu, że kopia jest uszkodzona może ustawić immutable flag (nie wiem od czego to zależy - w tutorialach o tym nie było, ale u mnie tak robi).
Uwaga: tę i wszystkie dalsze komendy musimy wykonywać z uprawnieniami administratora, stąd przed każdą sudo.

sudo chflags -R nouchg /Volumes/Time\ Machine/nazwa.sparsebundle

3) Dołączamy (ale nie montujemy) wirtualny dysk z kopią zapasową:

sudo hdiutil attach -nomount -noverify -noautofsck /Volumes/Time\ Machine/nazwa.sparsebundle

System wypisze znajdujące się na nim partycje (mogą mieć inne numery):

/dev/disk3           Apple_partition_scheme        
/dev/disk3s1         Apple_partition_map            
/dev/disk3s2         Apple_HFSX 

4) Interesuje nas ostatnia z partycji, to na niej jest backup i ona jest weryfikowana. Aby ją naprawić trzeba wykonać komendę:

sudo fsck_hfs -fyrd /dev/disk3s2

Znaczenie poszczególnych opcji:

-f (force) wymusza sprawdzenie i naprawę, nawet gdyby system uważał inaczej

-y próbuje naprawiać wszelkie znalezione nieprawidłowości

-r (rebuild) przebudowuje b-drzewo katalogów (cokolwiek to znaczy - w tutorialach sugerują, aby to zrobić)

-d (debug) będzie wypisywać sporo informacji w terminalu ale dzięki temu będziemy wiedzieli, że coś się dzieje (proces sprawdzania może trwać nawet kilka godzin)

5) Całkiem możliwe, że fsck_hfs odmówi współpracy i napisze:

Unable to open block device /dev/disk3s2:
Resource busyjournal_replay(/dev/disk3s2) returned 16
** /dev/rdisk3s2 (NO WRITE)

co znaczy, że system po podłączeniu dysku zaczął automatyczne sprawdzanie i trzeba poczekać aż skończy. Aby stwierdzić kiedy to nastąpi należy zajrzeć do logu:

tail -f /var/log/fsck_hfs.log

będzie tam:

** Checking Journaled HFS Plus volume.
** Detected a case-sensitive volume.
   The volume name is Time Machine Backups
** Checking extents overflow file.
** Checking catalog file.

i po jakimś czasie pojawi się:

/dev/rdisk3s2: ** The volume Time Machine Backups could not be verified completely.

wtedy możemy wrócić do punktu 4).

6) Drugi z możliwych problemów to:

Unable to open block device /dev/disk3s2:
Permission deniedjournal_replay(/dev/disk3s2) returned 13
** /dev/rdisk3s2 (NO WRITE)

- tutaj pomaga restart komputera

7) Kiedy fsck_hfs zacznie pracę wypisze (m. in.):

** Checking Journaled HFS Plus volume.
...
** Rebuilding catalog B-tree.

i po dłuższym czasie:


** Rechecking volume.

Jeżeli po kolejnym sprawdzaniu zobaczymy niezbyt zachęcający komunikat:


** The volume Time Machine Backups could not be repaired.

nie należy się tym zrażać tylko uruchomić fsck_hfs po raz kolejny. W moim przypadku dopiero za drugim razem zobaczyłem oczekiwane:

** The volume Time Machine Backups was repaired successfully.
CheckHFS returned 0, fsmodified = 1

8) Pomimo, że partycja z kopią zapasową jest już naprawiona, to system nie rejestruje tej informacji - musimy zrobić to ręcznie edytując plik com.apple.TimeMachine.MachineID.plist:

sudo nano /Volumes/Time\ Machine/nazwa.sparsebundle/com.apple.TimeMachine.MachineID.plist 

dla klucza:

VerificationState

zmieniamy wartość 2 na 0.

Gotowe!

Po przejściach z instalacją Liona opisanych tutaj dwa duże update'y (10.7.1 i 10.7.2) nie sprawiły mojemu MacBookowi żadnych problemów. Jednak po zainstalowaniu wersji 10.7.3 system przestał się uruchamiać, prezentując znane i nieszczególnie lubiane objawy niekończącego się oczekiwania na inicjalizację FireWire. Możliwe, że sam sobie strzeliłem w kolano, ponieważ po przeczytaniu o problemach z tą aktualizacją nie instalowałem jej przyrostowo (przez System Update), ale ściągnąłem pełną wersję (Combo). Problemów opisywanych na forach nie doświadczyłem, ale najwyraźniej system został przywrócony do stanu fabrycznego. Na szczęście tym razem sprawę udało się załatwić w kilka minut: wystarczyło zabootować system w single user mode (naciskając command-s podczas uruchamiania komputera), zamontować dysk z możliwością zapisu (/sbin/fsck -y, /sbin/mount -wu /) a następnie skasować moduł IOFireWireFamily (rm -rf /System/Library/Extensions/IOFireWireFamily.kext). Voilà! Do następnego razu.


[aktualizacja 2012.10.13]

Po zainstalowaniu wersji 10.7.4 jest ok, w 10.7.5 problem znowu się pojawia. Na szczęście powyższy sposób nadal jest skuteczny.


Nie pamiętam czy już się chwaliłem, ale popsułem w MacBooku port FireWire. Sam jego brak nie jest zbyt bolesny (właściwie go nie używałem), ale ma przykry skutek uboczny: przy starcie i przy wybudzaniu systemu jądro, próbuje zainicjować port i zatrzymuje się na tym etapie na prawie 10 minut. Skutecznym sposobem na powrót do normalnego stanu okazało się usunięcie modułów odpowiedzialnych za FireWire, tutaj jest opisane co i jak trzeba zrobić.

Wszystko działało bez problemów do momentu kiedy postanowiłem zrobić upgrade do Mac OSa 10.7. Po ściągnięciu nowego systemu z App Store instalator uruchomił się bez problemu, ale po restarcie system nie wstał ani po dwóch minutach, ani po dziesięciu ani po godzinie. Nie było co prawda ewidentnych dowodów na to, że winny jest FireWire ale objawy były na tyle podobne że wstępnie przyjąłem taką wersję. Google nie znajduje wiele na temat "instalacja Liona z uszkodzonym FireWire", ale trafił się jeden post  potwierdzający moje przypuszczenia. Opisana w nim metoda ma dwie wady: wymaga drugiego komputera z działającym Lionem (ok, mam iMaka) i powoduje nadpisanie całej zawartości dysku docelowego komputera (na co zdecydowanie nie mogłem się zgodzić). Nie pozostało nic innego jak znalezienie sposobu na przygotowanie jakiegoś medium instalacyjnego i jądra zmodyfikowanie tak, aby nie zawierało obsługi FireWire. Drobiazg.

W pierwszym odruchu pomyślałem o zrobieniu instalacyjnego DVD, ale zreflektowałem się że MacBook równie dobrze wystartuje z napędu podłączonego przez USB, a zawartość pendrive'a będzie można modyfikować jeżeli coś się nie uda przy pierwszym podejściu. Poniższy opis to wersja ostateczna, bez niezwykle fascynujących nieudanych prób. Here we go.

1. Instalator Liona to najzwyklejsza aplikacja Mac OSowa i po ściągnięciu z App Store trafia do folderu Applications. Klikamy prawym przyciskiem myszy na ikonce Install Mac OS X Lion i wybieramy z menu kontekstowego Show Package Contents. Następnie otwieramy folder Contents i znajdujący się w nim SharedSupport, powinniśmy zobaczyć tam obraz dysku InstallESD.dmg - to właściwy instalator. Gdyby chodziło jedynie o przygotowanie medium instalacyjnego to wystarczyłoby zapisać ten obraz dysku na pendrive'a, ale ponieważ chcemy usunąć obsługę FireWire trzeba będzie trochę więcej wysiłku.

2. Najpierw przygotujemy miejsce do zapisania instalatora. Uruchamiamy systemową aplikację Disk Utility i podłączamy do komputera pendrive. Instalator ma rozmiar 3.8 GB, więc teoretycznie wystarczy napęd 4 GB, ja dla pewności użyłem 8 GB. Zaznaczamy pendrive'a na liście po lewej, potem klikamy zakładkę Partition, wybieramy układ z jedną partycją, format Mac OS X Extended (Journaled) i klikamy Apply.

3. Montujemy obraz InstallESD.dmg dwuklikając na nim w Finderze i wracamy do Disk Utility. Klikamy pendrivie i wybieramy zakładkę Restore. Klikamy przycisk Image... (znajdujący się obok pola tekstowego Source), wybieramy z listy napędów Mac OS X Install ESD, naciskamy command-shift-. (co spowoduje wyświetlenie ukrytych plików) i wybieramy obraz BaseSystem.dmg. Do pola Destination przeciągamy utworzoną w poprzednim kroku partycję (u mnie nazywała się ona "Untitled 1") i klikamy przycisk Restore. Po potwierdzeniu rozpocznie się zapis, powinien potrwać kilka minut. Jeżeli pendrive nie zostanie automatycznie zamontowany robimy to sami klikając ikonkę Mount w Disk Utility.

4. Now for the tricky part. Uruchamiamy Terminal i wpisujemy kolejno komendy:

cp "/Volumes/Mac OS X Install ESD/mach_kernel" "/Volumes/Mac OS X Base System/mach_kernel"

rm "/Volumes/Mac OS X Base System/System/Installation/Packages"

cp -R "/Volumes/Mac OS X Install ESD/Packages" "/Volumes/Mac OS X Base System/System/Installation/Packages"

rm -r "/Volumes/Mac OS X Base System/System/Library/Extensions/IOFireWire*"

Gdyby system czepiał się o brak odpowiednich uprawnień, to każde z powyższych poleceń można
uruchomić jako administrator (tzn. "sudo cp ...", "sudo rm ..." itd.).

Z tak przygotowanego pendrive'a można wystartować instalację wciskając klawisz alt podczas uruchamiania komputera (Plan zadziałał, plan zadziałał! Jestem genialny! Jestem wybrańcem!). Powinny się wyświetlić ikonki wszystkich bootowalnych napędów, wśród nich Mac OS X Base System - po dwukliknięciu na nim już bez problemu uruchamia się instalator Liona.