Właśnie zdałem sobie sprawę, że jestem w stanie przenieść działający program do innego katalogu. Z mojego doświadczenia wynika, że nie było to możliwe w MacOs lub Windows. Jak to działa w Ubuntu?
Edycja: Myślałem, że nie jest to możliwe na Macu, ale najwyraźniej jest to możliwe po zweryfikowaniu komentarzy. Może nie jest to możliwe tylko w systemie Windows. Dzięki za wszystkie odpowiedzi.
rename(2)
uruchomić działającego pliku wykonywalnego w systemie OS X? Co się dzieje, dostajeszEBUSY
czy coś? Dlaczego to nie działa? Strona podręcznika zmiany nazwy (2) nie dokumentujeETXTBUSY
tego wywołania systemowego i mówi tylko oEBUSY
możliwości zmiany nazw katalogów, więc nie wiedziałem, że system POSIX może nawet zabronić zmiany nazw plików wykonywalnych.Odpowiedzi:
Pozwól mi to zepsuć.
Po uruchomieniu pliku wykonywalnego wykonywana jest sekwencja wywołań systemowych, w szczególności
fork()
iexecve()
:fork()
tworzy proces potomny procesu wywołującego, który jest (przeważnie) dokładną kopią elementu nadrzędnego, przy czym oba nadal uruchamiają ten sam plik wykonywalny (używając stron pamięci kopiowania przy zapisie, więc jest to wydajne). Zwraca dwa razy: W obiekcie nadrzędnym zwraca podrzędny PID. W potomku zwraca 0. Zwykle wywołania procesów potomnych wykonują natychmiast:execve()
przyjmuje pełną ścieżkę do pliku wykonywalnego jako argument i zastępuje proces wywołujący plikiem wykonywalnym. W tym momencie nowo utworzony proces otrzymuje własną wirtualną przestrzeń adresową, tj. Pamięć wirtualną, a wykonywanie rozpoczyna się w punkcie wejścia (w stanie określonym przez zasady ABI platformy dla nowych procesów).W tym momencie moduł ładujący ELF jądra zmapował segmenty tekstu i danych pliku wykonywalnego do pamięci, tak jakby używał
mmap()
wywołania systemowego (odpowiednio ze współdzielonymi mapami tylko do odczytu i prywatnymi mapowaniami do odczytu i zapisu). BSS jest również odwzorowany tak, jakby zawierał MAP_ANONYMOUS. (BTW, ja ignorując dynamiczne łączenie tutaj dla uproszczenia: Dynamiczne łącznikopen()
S immap()
wszystko bibliotek dynamicznych przed skokiem do punktu wejścia głównego wykonywalnego).Tylko kilka stron jest ładowanych do pamięci z dysku, zanim nowo-exec () ed zacznie uruchamiać swój własny kod. Dalsze strony są wczytywane w razie potrzeby, jeśli / kiedy proces dotknie tych części wirtualnej przestrzeni adresowej. (Wstępne ładowanie dowolnych stron kodu lub danych przed rozpoczęciem wykonywania kodu przestrzeni użytkownika to tylko optymalizacja wydajności).
Plik wykonywalny jest identyfikowany przez i-węzeł na niższym poziomie. Po uruchomieniu pliku jądro utrzymuje zawartość pliku nienaruszoną przez odwołanie do i-węzła, a nie przez nazwę pliku, jak w przypadku otwartych deskryptorów plików lub mapowań pamięci opartych na pliku. Dzięki temu możesz łatwo przenieść plik wykonywalny w inne miejsce systemu plików lub nawet w innym systemie plików. Na marginesie, aby sprawdzić różne statystyki procesu, możesz zajrzeć do katalogu
/proc/PID
(PID to identyfikator procesu danego procesu). Możesz nawet otworzyć plik wykonywalny, ponieważ/proc/PID/exe
nawet on został odłączony od dysku.Teraz wykopmy ruch:
Gdy przenosisz plik w tym samym systemie plików, wykonywane jest wywołanie systemowe
rename()
, które po prostu zmienia nazwę pliku na inną nazwę, i-węzeł pliku pozostaje taki sam.Natomiast między dwoma różnymi systemami plików zdarzają się dwie rzeczy:
Zawartość pliku jest najpierw kopiowana do nowej lokalizacji przez
read()
iwrite()
Następnie plik jest odłączany od katalogu źródłowego przy użyciu
unlink()
i oczywiście plik otrzyma nowy i-węzeł w nowym systemie plików.rm
to po prostuunlink()
-podanie danego pliku z drzewa katalogów, więc posiadanie uprawnienia do zapisu w katalogu zapewni ci wystarczające prawo do usunięcia dowolnego pliku z tego katalogu.Teraz dla zabawy, wyobraź sobie, co się dzieje, gdy przenosisz pliki między dwoma systemami plików i nie masz uprawnień do
unlink()
pliku ze źródła?Plik zostanie najpierw skopiowany do miejsca docelowego (
read()
,write()
), a następnieunlink()
zakończy się niepowodzeniem z powodu niewystarczających uprawnień. Tak więc plik pozostanie w obu systemach plików !!źródło
mmap
iunmap
wywołania systemowe nie są wykorzystywane do załadunku i rozładunku stron na żądanie strony są ładowane przez jądro podczas uzyskiwania dostępu do nich generuje błąd strony, strony są usuwane z pamięci, gdy czuje OS RAM byłyby lepiej wykorzystane do czegoś innego. Żadne wywołanie systemowe nie jest zaangażowane w te operacje ładowania / rozładowywania.Cóż, to całkiem proste. Weźmy plik wykonywalny o nazwie / usr / local / bin / whoopdeedoo. Jest to tylko odniesienie do tak zwanego i- węzła (podstawowa struktura plików w systemach plików Unix). To i-węzeł zostaje oznaczony jako „w użyciu”.
Teraz, gdy usuwasz lub przenosisz plik / usr / local / whoopdeedoo, jedyną rzeczą, która jest przenoszona (lub usuwana), jest odwołanie do i-węzła. Sam i-węzeł pozostaje niezmieniony. Zasadniczo to jest to.
Powinienem to zweryfikować, ale wierzę, że możesz to zrobić również w systemach plików Mac OS X.
Windows ma inne podejście. Czemu? Kto wie...? Nie znam wewnętrznych elementów NTFS. Teoretycznie wszystkie systemy plików, które używają odniesień do struktur wewnętrznych dla nazw plików, powinny mieć taką możliwość.
Przyznaję, że nadmiernie uprościłem, ale przeczytaj sekcję „Implikacje” na Wikipedii, która wykonuje znacznie lepszą pracę niż ja.
źródło
Jedną z rzeczy, która wydaje się brakować we wszystkich innych odpowiedziach, jest to, że: gdy plik zostanie otwarty, a program utrzyma otwarty deskryptor pliku, plik nie zostanie usunięty z systemu, dopóki deskryptor pliku nie zostanie zamknięty.
Próby usunięcia odnośnego i-węzła będą opóźnione do momentu zamknięcia pliku: zmiana nazwy w tym samym lub innym systemie plików nie może wpływać na otwarty plik, niezależnie od zachowania zmiany nazwy, ani jawnie usuwać lub nadpisywać pliku nowym. Jedynym sposobem, w jaki można zepsuć plik, jest jawne otwarcie jego i-węzła i zepsuć zawartość, a nie operacje w katalogu, takie jak zmiana nazwy / usuwanie pliku.
Ponadto, gdy jądro wykonuje plik, zachowuje odniesienie do pliku wykonywalnego, co ponownie zapobiegnie jego modyfikacji podczas wykonywania.
W końcu, nawet jeśli wygląda na to, że jesteś w stanie usunąć / przenieść pliki tworzące działający program, tak naprawdę zawartość tych plików jest przechowywana w pamięci aż do zakończenia programu.
źródło
execve()
nie zwraca FD, po prostu wykonuje program. Tak na przykład, jeśli uruchomićtail -f /foo.log
następnie ich jest FD (/proc/PID/fd/<fd_num>
) związane zetail
dlafoo.log
ale nie dla samego pliku wykonywalnegotail
, a nie na jego rodzica, jak również. Dotyczy to również pojedynczych plików wykonywalnych.execve
więc nie rozumiem, jak to jest istotne. Gdy jądro zacznie wykonywać plik, próba zastąpienia pliku nie zmodyfikuje programu, który jądro zamierza załadować, renderując punktową dyskusję. Jeśli chcesz „zaktualizować” plik wykonywalny podczas jego działania, możeszexecve
w pewnym momencie wywołać plik, aby jądro ponownie odczytało plik, ale nie rozumiem, jak to ma znaczenie. Chodzi o to: usunięcie „działającego pliku wykonywalnego” tak naprawdę nie powoduje usunięcia danych, dopóki plik wykonywalny się nie zatrzyma.execve()
i FD, gdy w tej sprawie nie występuje FD.open()
zwraca deskryptor pliku , o którym tu mówi Heemaylexecve()
. Tak, działający proces ma odniesienie do pliku wykonywalnego, ale nie jest to deskryptor pliku. Prawdopodobnie nawet jeślimunmap()
edytuje wszystkie swoje odwzorowania pliku wykonywalnego, nadal będzie mieć odwołanie (odzwierciedlone w / proc / self / exe), które powstrzyma uwolnienie i-węzła. (Byłoby to możliwe bez awarii, gdyby zrobił to z funkcji biblioteki, która nigdy nie powróciła.) BTW, obcinanie lub modyfikowanie używanego pliku wykonywalnego może ci daćETXTBUSY
, ale może działać.W systemie plików Linux, gdy przenosisz plik, o ile nie przekracza on granic systemu plików (czytaj: pozostaje na tym samym dysku / partycji), zmieniasz tylko i-węzeł
..
(katalog macierzysty) do katalogu nowej lokalizacji . Rzeczywiste dane w ogóle nie zostały przeniesione na dysk, tylko wskaźnik, aby system plików wiedział, gdzie je znaleźć.Dlatego operacje przenoszenia są tak szybkie i prawdopodobnie nie ma problemu z przeniesieniem uruchomionego programu, ponieważ tak naprawdę nie przenosisz samego programu.
źródło
Jest to możliwe, ponieważ przeniesienie programu nie wpływa na uruchamianie procesów uruchomionych przez jego uruchomienie.
Po uruchomieniu programu jego bity na dysku są chronione przed nadpisaniem, ale nie ma potrzeby ochrony pliku, którego nazwę należy zmienić, przenieść do innej lokalizacji w tym samym systemie plików, co jest równoważne zmianie nazwy pliku lub przeniesieniu do innego systemu plików, co jest równoważne z skopiowaniem pliku w inne miejsce, a następnie usunięcie go.
Usunięcie używanego pliku albo dlatego, że proces ma otwarty deskryptor pliku, albo ponieważ proces go wykonuje, nie usuwa danych pliku, do których odwołuje się i-węzeł pliku, a jedynie usuwa pozycję katalogu, tj. ścieżka, z której można dotrzeć do i-węzła.
Pamiętaj, że uruchomienie programu nie powoduje załadowania wszystkiego naraz w (fizycznej) pamięci. Przeciwnie, ładowane jest tylko ścisłe minimum wymagane do rozpoczęcia procesu. Następnie wymagane strony są ładowane na żądanie przez cały czas trwania procesu. nazywa się to stronicowaniem na żądanie. Jeśli brakuje pamięci RAM, system operacyjny może zwolnić pamięć RAM zawierającą te strony, więc proces może ładować wielokrotnie tę samą stronę z wykonywalnego i-węzła.
Powodem, dla którego nie było to możliwe w systemie Windows, był pierwotnie prawdopodobny fakt, że bazowy system plików (FAT) nie obsługiwał podzielonego pojęcia pozycji katalogu w porównaniu z i-węzłami. To ograniczenie nie było już obecne w systemie plików NTFS, ale projekt systemu operacyjnego był utrzymywany przez długi czas, co prowadzi do nieznośnego ograniczenia konieczności ponownego uruchamiania podczas instalowania nowej wersji pliku binarnego, co nie ma miejsca w przypadku najnowszych wersji systemu Windows.
źródło
Zasadniczo w systemie Unix i jego nazwie nazwa pliku (w tym ścieżka do katalogu prowadząca do niego) służy do skojarzenia / znalezienia pliku podczas jego otwierania (wykonanie pliku jest jednym ze sposobów jego otwarcia). Po tym momencie tożsamość pliku (poprzez „i-węzeł”) zostaje ustalona i nie jest już kwestionowana. Możesz usunąć plik, zmienić jego nazwę, zmienić uprawnienia. Tak długo, jak jakikolwiek proces lub ścieżka do pliku ma uchwyt na tym pliku / i-węźle, będzie się on trzymał, podobnie jak potok między procesami (w rzeczywistości w historycznym systemie UNIX rura była bezimiennym i-węzłem o rozmiarze, który właśnie pasował do odniesienie do pamięci dyskowej „bezpośrednich bloków” w i-węzle, coś w rodzaju 10 bloków).
Jeśli przeglądarka plików PDF jest otwarta na pliku PDF, możesz usunąć ten plik i otworzyć nowy o tej samej nazwie, i tak długo, jak stara przeglądarka jest otwarta, nadal będzie mieć dostęp do starego pliku (chyba że aktywnie ogląda system plików, aby zauważyć, kiedy plik znika pod oryginalną nazwą).
Programy wymagające plików tymczasowych mogą po prostu otworzyć taki plik pod jakąś nazwą, a następnie natychmiast go usunąć (a raczej pozycję katalogu), gdy jest on nadal otwarty. Następnie plik nie jest już dostępny według nazwy, ale każdy proces mający otwarty deskryptor pliku może nadal uzyskać do niego dostęp, a jeśli nastąpi nieoczekiwane zamknięcie programu, plik zostanie usunięty, a pamięć automatycznie odzyskana.
Zatem ścieżka do pliku nie jest właściwością samego pliku (w rzeczywistości twarde linki mogą zapewnić kilka różnych takich ścieżek) i jest potrzebna tylko do otwarcia, a nie do ciągłego dostępu przez procesy, które już go otwierają.
źródło