Next: , Previous: , Up: Files   [Contents][Index]


25.12 特定のファイル名の“Magic”の作成

特定のファイル名にたいして特別な処理を実装できます。これはそれらの名前にたいするmagic化と呼ばれます。この機能は主にリモートファイルにたいするアクセスの実装用に使用されます(Remote Files in The GNU Emacs Manualを参照)。

magicファイル名を定義するには、名前クラスを定義するための正規表現とそれにマッチするファイル名用のEmacsファイル操作プリミティブすべてを実装するハンドラーを定義しなければなりません。

変数file-name-handler-alistは各ハンドラーに適用するときを決定する正規表現とともにハンドラーのリストを保持します。各要素は以下の形式をもちます:

(regexp . handler)

ファイルアクセスとファイル名変換にたいするすべてのEmacsプリミティブは、file-name-handler-alistにたいして与えられたファイル名をチェックします。そのファイル名がregexpにマッチしたら、そのプリミティブがhandlerを呼び出してファイルを処理します。

handlerの1つ目の引数には、プリミティブの名前をシンボルとして与えます。残りの引数はそのプリミティブに引数として渡されます(これらの引数の1つ目はほとんどの場合はファイル名自身)。たとえば以下を行って:

(file-exists-p filename)

filenameがハンドラーhandlerをもつなら、handlerは以下のように呼び出されます:

(funcall handler 'file-exists-p filename)

関数が2つ以上の引数を受け取る場合には、それらはファイル名でなければならず、関数はそれらのファイル名それぞれにたいしてハンドラーをチェックします。たとえば、

(expand-file-name filename dirname)

以下を行うと、filenameにたいするハンドラーをチェックした後にdirnameにたいするハンドラーをチェックします。どちらの場合でもhandlerは以下のように呼び出されます:

(funcall handler 'expand-file-name filename dirname)

その後にhandlerfilenamedirnameのいずれかを処理するか解決する必要があります。

指定されたファイル名が2つ以上のハンドラーにマッチする場合には、ファイル名の中で最後に開始するマッチが優先されます。リモートファイルアクセスのようなジョブにたいするハンドラーに先立って、解凍のようなジョブにたいするハンドラーが最初に処理されるようにこのルールが選択されました。

以下はmagicファイル名ハンドラーが処理する操作です:

access-fileadd-name-to-filebyte-compiler-base-file-name,
copy-directorycopy-filedelete-directorydelete-filediff-latest-backup-filedirectory-file-namedirectory-filesdirectory-files-and-attributesdired-compress-filedired-uncache,
expand-file-namefile-accessible-directory-pfile-aclfile-attributesfile-directory-pfile-equal-pfile-executable-pfile-exists-pfile-in-directory-pfile-local-copyfile-modesfile-name-all-completionsfile-name-as-directoryfile-name-case-insensitive-pfile-name-completionfile-name-directoryfile-name-nondirectoryfile-name-sans-versionsfile-newer-than-file-pfile-notify-add-watchfile-notify-rm-watchfile-notify-valid-pfile-ownership-preserved-pfile-readable-pfile-regular-pfile-remote-pfile-selinux-contextfile-symlink-pfile-truenamefile-writable-pfind-backup-file-name,
get-file-bufferinsert-directoryinsert-file-contents,
loadmake-auto-save-file-namemake-directorymake-directory-internalmake-nearby-temp-filemake-symbolic-link,
process-filerename-fileset-file-aclset-file-modesset-file-selinux-contextset-file-timesset-visited-file-modtimeshell-commandstart-file-processsubstitute-in-file-name,
temporary-file-directoryunhandled-file-name-directoryvc-registeredverify-visited-file-modtime
write-region.

insert-file-contentsにたいするハンドラーはvisit引数が非nilなら、通常は(set-buffer-modified-p nil)によりそのバッファーの変更フラグをクリアーする必要があります。これにはもしそのバッファーがロックされていたら、ロックを解除する効果もあります。

ハンドラー関数は上記すべての操作を処理しなければならず、他の操作が将来追加される可能性もあります。これらの操作自体すべてを実装する必要はありません — 特定の操作にたいして特別なことを行う必要がないときには、その操作を通常の方法で処理するように、そのプリミティブを再呼び出しできます。認識できない操作にたいしては、常にそのプリミティブを再呼び出しするべきです。以下はこれを行う方法の1つです:

(defun my-file-handler (operation &rest args)
  ;; 特別に処理する必要がある、
  ;; 特別な操作を最初にチェックする
  (cond ((eq operation 'insert-file-contents) …)
        ((eq operation 'write-region) …)
        …
        ;; 関知しないその他の操作を処理する
        (t (let ((inhibit-file-name-handlers
                  (cons 'my-file-handler
                        (and (eq inhibit-file-name-operation operation)
                             inhibit-file-name-handlers)))
                 (inhibit-file-name-operation operation))
             (apply operation args)))))

ハンドラー関数が通常のEmacsプリミティブを呼び出す決定をした際には、無限再帰を引き起こすような同一ハンドラーからのプリミティブの再呼び出しを防ぐ必要があります。上記の例では変数inhibit-file-name-handlersinhibit-file-name-operationによって、これを行う方法を示しています。上記の例のように、これらを正確に使用するよう注意してください。複数ハンドラーの正しい振る舞いと、それぞれがハンドラーをもつかもしれない2つのファイル名にたいする操作にたいする詳細は非常に重要です。

ファイルへの実アクセスにたいして実際には特別なことを行わないハンドラー(たとえばリモートファイル名にたいしてホスト名の補完を実装するハンドラー等)は、safe-magicプロパティに非nilをもつべきです。たとえばEmacsは通常はPATH内で見い出されるようなディレクトリーがプレフィックス‘/:’によってmagicファイル名に見えるようなら、magicファイル名にならないように保護します。しかしsafe-magicプロパティに非nilをもつハンドラーがそれらにたいして使用された場合には、‘/:’は追加されません。

ファイル名ハンドラーは普通とは異なる方法でそれを処理(handle)するのがどの操作(operation)なのかを宣言するために、operationsプロパティをもつことができます。このプロパティが非nil値をもつなら、それは操作のリストであるべきです。その場合には、それらの操作だけがハンドラーを呼び出すでしょう。これは無駄を省きますが、主な目的はオートロードされるハンドラー関数が実際に処理を行うとき以外はロードされないようにすることです。

通常のプリミティブにたいして単にすべての操作を延期しても機能しません。たとえばファイル名ハンドラーがfile-exists-pにたいして適用された場合には、通常のloadコードは正しく機能しないでしょうから、ハンドラー自身でloadを処理しなければなりません。しかしハンドラーがfile-exists-pプロパティを使用してfile-exists-pを処理しないことを宣言した場合には、普通とは異なる方法でloadを処理する必要はなくなります。

Variable: inhibit-file-name-handlers

この変数は特定の操作にたいして現在のところ使用を抑制されているハンドラーのリストを保持する。

Variable: inhibit-file-name-operation

特定のハンドラーにたいしてその時点で抑制されている操作。

Function: find-file-name-handler file operation

この関数はfileというファイル名にたいするハンドラー関数、それが存在しなければnilをリターンする。引数operationはそのファイルを処理する操作であること。これはハンドラー呼び出し時に1つ目の引数として渡すことになる値である。operationinhibit-file-name-operationと等しいか、そのハンドラーのoperations内に存在しなければ、この関数はnilをリターンする。

Function: file-local-copy filename

この関数はファイルfilenameがまだローカルマシン上になければ、それをローカルマシン上の通常の非magicファイルにコピーする。magicファイル名は、それらが他のマシン上のファイルを参照する場合には、file-local-copy操作を処理するべきである。リモートファイルアクセス以外の目的にたいして使用されるmagicファイル名は、file-local-copyを処理するべきではない。この場合には関数はそのファイルをローカルファイルとして扱うだろう。

filenameがローカルなら、それがmagicか否かにかかわらずこの関数は何も行わずにnilをリターンする。それ以外ならローカルコピーファイルのファイル名をリターンする。

Function: file-remote-p filename &optional identification connected

この関数はfilenameがリモートファイルかどうかをテストする。filenameがローカル(リモートではない)ならリターン値はnilfilenameが正にリモートならリターン値はそのリモートシステムを識別する文字列。

この識別子文字列はホスト名とユーザー名、およびリモートシステムへのアクセスに使用されるメソッドを表す文字列も同様に含めることができる。たとえばファイル名/sudo::/some/fileにたいするリモート識別子文字列は/sudo:root@localhost:

2つの異なるファイルにたいしてfile-remote-pが同じ識別子をリターンした場合には、それらが同じファイルシステム上に格納されていて互いに配慮しつつアクセス可能であることを意味する。これはたとえば同時に両方のファイルにアクセスするリモートプロセスを開始することが可能なことを意味する。ファイルハンドラーの実装者はこの方式を保証する必要がある。

identificationは文字列としてリターンされるべき識別子の一部を指定する。identificationにはmethoduserhostのシンボルを指定できる。他の値はすべてnilのように扱われて、それは完全な識別子文字列をリターンすることを意味する。上記の例ではリモートのuser識別子文字列はrootになるだろう。

connectedが非nilなら、たとえfilenameがリモートであってもEmacsがそのホストにたいする接続をもたなければ、この関数はnilをリターンする。これは接続が存在しない際の接続の遅延を回避したいときに有用。

Function: unhandled-file-name-directory filename

この関数は非magicのディレクトリーの名前をリターンする。これは非magicのfilenameには対応するディレクトリー名(Directory Namesを参照)をリターンする。magicのfilenameには、何の値をリターンするかを決定するためにファイル名ハンドラーを呼び出す。filenameがローカルプロセスからアクセス不能なら、ファイル名ハンドラーはnilをリターンすることによってそれを示すこと。

これはサブプロセスの実行に有用。すべてのサブプロセスは自身が所属するカレントディレクトリーとして非magicディレクトリーをもたなければならず、この関数はそれを導出するよい手段である。

Function: file-local-name filename

この関数はfilenameローカル部分(local part)をリターンする。これはリモートホスト上でファイル名を識別する部分であり、通常はリモートファイル名からリモートホストを指定する部分とアクセス方法を取り除いた部分である。たとえば:

(file-local-name "/ssh:user@host:/foo/bar")
     ⇒ "/foo/bar"

この関数はリモートのfilenameにたいして、リモートプロセス(Asynchronous ProcessesSynchronous Processesを参照)やリモートホスト上で実行されるプログラムの引数として直接使用可能なファイル名をリターンする。filenameがローカルなら、この関数はそれを変更せずにリターンする。

User Option: remote-file-name-inhibit-cache

リモートファイルの属性は、よりよいパフォーマンスのためにキャッシュすることができる。キャッシュがEmacsの制御外で変更されると、そのキャッシュ値は無効になり再読込しなければならない。

この変数がnilにセットされているとキャッシュ値は決して失効しない。このセッティングはEmacs以外にリモートファイルを変更するものがないことが確実な場合のみ慎重に使用すること。これがtにセットされているとキャッシュ値は決して使用されない。これはもっとも安全な値であるがパフォーマンスは低下するかもしれない。

折衷的な値としてはこれを正の数字にセットする。これはキャッシュされてからその数字の秒数の間は、ャッシュ値を使用することを意味する。リモートファイルが定期的にチェックされる場合には、この変数を定期的なチェックの間隔より小さい値にletバインドするのは、よい考えかもしれない。たとえば:

(defun display-time-file-nonempty-p (file)
  (let ((remote-file-name-inhibit-cache
         (- display-time-interval 5)))
    (and (file-exists-p file)
         (< 0 (nth 7 (file-attributes
                       (file-chase-links file)))))))