sobota, 8 maja 2010

nasty filenames

Przyzwyczailiśmy się, że w nazwach plików występują głównie "normalne" znaki, z wyjątkiem ukośnika (separatora katalogów w ścieżce). Możliwe jest jednak wystąpienie innych znaków.

Stwórzmy katalog ze znakiem końca wiersza w środku jego nazwy. Dla odmiany po poprzednim wpisie użyjmy Perla.

linux$ perl -e 'mkdir("prefix\nsuffix")'


Co możemy powiedzieć o naszym dziele?

linux$ ls
prefix?suffix
linux$ ls | cat
prefix
suffix


Wygląda podejrzanie. Ma to pewne implikacje nie tylko dla mechanizmu autouzupełniania powłoki :) ale także dla innych aplikacji:

linux$ find . -type d -name 'prefix*' | xargs rmdir
rmdir: nie udało się usunąć `./prefix': Nie ma takiego pliku ani katalogu
rmdir: nie udało się usunąć `suffix': Nie ma takiego pliku ani katalogu


Po to właśnie wymyślono opcję użycia znaku NULL jako separatora wierszy:

linux$ find . -type d -name 'prefix*' | xargs printf "received [%s]\n"
received [./prefix]
received [suffix]
linux$ find . -type d -name 'prefix*' -print0 | xargs -0 printf "received [%s]\n"
received [./prefix
suffix]


Teraz już możemy bezpiecznie i skutecznie usunąć katalog.

linux$ find . -type d -name 'prefix*' -print0 | xargs -0 rmdir
linux$ ls
linux$


Na marginesie: spotkałem się kiedyś z komercyjnym UNIX-em, który zwyczajnie nie wspierał takich opcji w find i xargs. :)

Wniosek z tego płynie taki: jeśli przetwarzasz wynik dowolnych poleceń zwracających nazwy plików, lepiej nie polegaj na znaku końca wiersza jako faktycznym znaczniku końca linii. Możesz ryzykować nie tylko załamaniem procesu przetwarzania, ale także stworzyć zagrożenie.

Co by się stało, gdybyśmy tu mieli xargs rm -rf?

linux$ perl -e 'mkdir("prefix\n..")'
linux$ find . -type d -name 'prefix*' | xargs printf "received: [%s]\n"
received: [./prefix]
received: [..]


Potrzeba czujności nie dotyczy tylko skryptów powłoki, ale także np. logów. Wiele aplikacji prowadzi logi tekstowe, które parsuje się później wiersz po wierszu. Jeśli aplikacja wpisuje do loga nazwę pliku, może się okazać, że ten konkretny wpis został podzielony na wiele wierszy. Tego typu zachowanie zaobserwowałem kiedyś w logach serwera aplikacyjnego JEE: aplikacja przetwarzała pliki ze spoola i odkładała w logach ślad swojej pracy, w tym nazwę otwieranego pliku.

Brak komentarzy:

Prześlij komentarz