実行中のアクティブなプログラムを別のディレクトリに移動できることに気付きました。私の経験では、MacOやWindowsでは不可能でした。 Ubuntuではどのように機能しますか?
編集:Macでは不可能だと思っていましたが、コメントで確認できるように思われます。多分Windowsでは不可能です。すべての答えをありがとう。
分解させてください。
実行可能ファイルを実行すると、一連のシステムコールが実行されます。特に、 fork()
および execve()
:
fork()
は、呼び出しプロセスの子プロセスを作成します。これは(ほとんど)親の正確なコピーであり、両方とも同じ実行可能ファイルを実行しています(コピーオンライトメモリページを使用するため、効率的です)。 2回返します。親では、子PIDを返します。子では、0を返します。通常、子プロセスはすぐにexecveを呼び出します。
execve()
は、実行可能ファイルへのフルパスを引数として受け取り、呼び出しプロセスを実行可能ファイルに置き換えます。この時点で、新しく作成されたプロセスは独自の仮想アドレス空間、つまり仮想メモリを取得し、そのエントリポイントで(プラットフォームABIの新しいプロセスのルールで指定された状態で)実行が開始されます。
この時点で、カーネルのELFローダーは、 mmap()
システムコールを使用したかのように、実行可能ファイルの テキストおよびデータセグメント をメモリにマップしました(共有読み取り専用)およびプライベートの読み取り/書き込みマッピング)。 BSSは、MAP_ANONYMOUSを使用する場合と同様にマップされます。 (ところで、簡単にするためにここでは動的リンクを無視しています。動的リンカーopen()
sとmmap()
sは、メインの実行可能ファイルのエントリポイントにジャンプする前にすべての動的ライブラリです。)
新しく実行された()が独自のコードの実行を開始する前に、実際にディスクからメモリにロードされるページはわずかです。プロセスがその仮想アドレス空間のそれらの部分に触れる場合/いつ、必要に応じて、さらなるページは デマンドページイン です。 (ユーザー空間コードの実行を開始する前にコードまたはデータのページをプリロードすることは、パフォーマンスの最適化にすぎません。)
実行可能ファイルは、下位レベルのiノードによって識別されます。ファイルの実行が開始された後、カーネルは、開いているファイル記述子やファイルバックアップメモリマッピングの場合のように、ファイル名ではなくiノード参照によってファイルの内容をそのまま保持します。そのため、実行可能ファイルをファイルシステムの別の場所、または別のファイルシステムに簡単に移動できます。補足として、プロセスのさまざまな統計情報を確認するには、/proc/PID
(PIDは特定のプロセスのプロセスID)ディレクトリを覗きます。実行可能ファイルは、ディスクからリンク解除されていても、/proc/PID/exe
として開くこともできます。
では、動きを掘り下げましょう。
同じファイルシステム内でファイルを移動すると、実行されるシステムコールはrename()
になります。これはファイルの名前を別の名前に変更するだけで、ファイルのiノードは同じままです。
一方、2つの異なるファイルシステムの間では、2つのことが起こります。
read()
およびwrite()
によって、最初に新しい場所にコピーされたファイルのコンテンツ
その後、ファイルはunlink()
を使用してソースディレクトリからリンク解除され、明らかにファイルは新しいファイルシステムで新しいiノードを取得します。
rm
は、実際にはディレクトリツリーから指定されたファイルをunlink()
- ingするだけなので、ディレクトリに対する書き込み権限があると、そのディレクトリからファイルを削除する十分な権利が得られます。
では、2つのファイルシステム間でファイルを移動していて、ソースからファイルをunlink()
する権限がない場合に何が起こるか想像してみてください。
さて、ファイルは最初に宛先(read()
、write()
)にコピーされ、その後、unlink()
は権限不足のため失敗します。そのため、ファイルは両方のファイルシステムに残ります!!
まあ、それはかなり簡単です。/usr/local/bin/whoopdeedooという名前の実行可能ファイルを取得しましょう。これは、いわゆる inode (Unixファイルシステム上のファイルの基本構造)と呼ばれるものへの参照にすぎません。 「使用中」とマークされるのはiノードです。
ファイル/ usr/local/whoopdeedooを削除または移動すると、移動(またはワイプ)されるのはiノードへの参照のみです。 iノード自体は変更されません。それは基本的にそれです。
確認する必要がありますが、Mac OS Xファイルシステムでもこれを実行できると考えています。
Windowsは異なるアプローチを取ります。どうして?知るか...?私はNTFSの内部に精通していません。理論的には、ファイル名の内部構造への参照を使用するすべてのファイルシステムがこれを実行できるはずです。
私は過度に単純化したことを認めますが、ウィキペディアの「影響」のセクションを読んでください。
ファイルが開かれ、プログラムが開いているファイル記述子を保持すると、そのファイルはそれまでシステムからnot削除されませんファイル記述子は閉じられています。
参照先のiノードを削除しようとすると、ファイルが閉じるまで遅延します。同じまたは異なるファイルシステムで名前を変更しても、名前変更の動作とは無関係に、開いているファイルに影響を与えることはできません。ファイルを台無しにする唯一の方法は、ファイルの名前変更や削除などのディレクトリ操作ではなく、明示的にそのiノードを開いて内容を台無しにすることです。
さらに、カーネルがファイルを実行するとき、実行可能ファイルへの参照を保持します。これにより、実行中のファイルの変更が再び防止されます。
最終的に、実行中のプログラムを構成するファイルを削除/移動できるようにように見えても、実際にはそれらのファイルの内容はプログラムは終了します。
Linuxファイルシステムでは、ファイルを移動するときに、ファイルシステムの境界を越えない限り(読み取り:同じディスク/パーティションにとどまる)、変更するのは..
(親ディレクトリ)のiノードだけです。新しい場所のそれ。実際のデータはディスク上でまったく移動せず、ファイルシステムがどこにあるかを知るためのポインタだけが移動しました。
これが、移動操作が非常に迅速である理由であり、実際にプログラム自体を移動していないので、実行中のプログラムを移動しても問題はない可能性があります。
プログラムを移動しても、プログラムを起動して開始された実行中のプロセスには影響しないため、可能です。
プログラムが起動されると、そのディスク上のビットは上書きされないように保護されますが、名前を変更したり、同じファイルシステムの別の場所に移動したり、ファイルの名前を変更したり、移動したりするファイルを保護する必要はありません別のファイルシステムにコピーします。これは、ファイルを他の場所にコピーしてから削除するのと同じです。
プロセスがファイル記述子を開いているため、またはプロセスがそれを実行しているため、使用中のファイルを削除しても、ファイルデータは削除されず、ファイルiノードによって参照されたままで、ディレクトリエントリのみが削除されます。つまり、iノードに到達できるパス。
プログラムを起動しても、すべてが(物理)メモリに一度に読み込まれるわけではないことに注意してください。反対に、プロセスの開始に必要な厳密な最小値のみがロードされます。その後、必要なページは、プロセスの全期間を通じてオンデマンドでロードされます。これはデマンドページングと呼ばれます。 RAM不足がある場合、OSはこれらのページを保持しているRAMを自由に解放できるため、プロセスが実行可能なiノードから同じページを複数回ロードする可能性が高くなります。
Windowsでそれが不可能だった理由は、もともとは、基礎となるファイルシステム(FAT)がディレクトリエントリとiノードのスプリットコンセプトをサポートしていなかったためです。この制限はNTFSには存在しませんでしたが、OSの設計は長い間維持されており、新しいバージョンのバイナリをインストールするときに再起動しなければならないという不快な制約につながりました。これは最近のバージョンのWindowsには当てはまりません。
基本的に、Unixおよびそのilkでは、ファイル名(それにつながるディレクトリパスを含む)は、opening it(ファイルの実行がファイルを開く方法の1つである場合)の関連付け/検索に使用されますマナー)。その瞬間の後、ファイルの識別情報(「inode」を介して)が確立され、質問されなくなります。ファイルを削除し、名前を変更し、アクセス許可を変更できます。プロセスまたはファイルパスにそのファイル/ inodeのハンドルがある限り、プロセス間のパイプのように(実際には、歴史的なUNIXではパイプwasを持つ名前のないiノードiノードの「直接ブロック」ディスクストレージ参照にちょうど収まるサイズ、10ブロックのようなもの)。
PDFビューアーをPDFファイルで開いている場合、そのファイルを削除して、同じ名前の新しいファイルを開くことができます。古いビューアーが開いている限り、古いファイルにアクセスしても問題ありません(ファイルが元の名前で消えたときに通知するためにファイルシステムをアクティブに監視しない限り)。
一時ファイルを必要とするプログラムは、そのようなファイルを何らかの名前で開いてから、即時開いたままの状態で(またはむしろディレクトリエントリを)削除できます。その後、ファイルは名前でアクセスできなくなりますが、ファイルへの開いているファイル記述子を持つプロセスは引き続きアクセスできます。その後、プログラムの予期しない終了がある場合、ファイルは削除され、ストレージは自動的に再生されます。
そのため、ファイルへのパスはファイル自体のプロパティではなく(実際、ハードリンクはそのようないくつかの異なるパスを提供できます)、ファイルを開くためにのみ必要であり、既に開いているプロセスによる継続的なアクセスには必要ありません。