パスワードを忘れた? アカウント作成
13904617 story
Windows

Windowsにおけるファイルコピーに関する驚くほど複雑な注意点 103

ストーリー by hylom
互換性と拡張の結果 部門より
あるAnonymous Coward 曰く、

ソフトイーサの創業者として知られる登大遊氏が、「Windows のファイルのコピーは、驚くほど奥が深い」としてWindowsにおけるファイルおよびディレクトリーのコピー時に注意しなければならない仕様19点を挙げている。

どうしてそうなったんだ……。

これによると、Windowsでは歴史的経緯から長いファイル名を扱う際に「謎の呪文」を使わなければならなかったり、Windows特有の複雑なファイル属性やアクセス権限や代替ストリーム、ファイルシステムによって異なるタイムスタンプ精度などの仕様、面倒なシンボリックの仕様、OSのバージョンによる互換性問題などを考慮しなければならないとのことで、Windowsのファイルコピーは非常に複雑になっているという。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • ってそういうことなんすね。
    というのが♪ 当然書き連ねられていた。
    (知らない/よくわからないのが多かったけど)

    そして、♪?♪?♪? 最大限の恐怖!

  • by Anonymous Coward on 2019年05月09日 19時36分 (#3611861)

    UNIXではコピー先に書き込みパーミッションの落とされたファイルがあるときに、勝手にパーミッションを立てて更新したりはしないと思うんだけど、Windowsでも間違って書き込まれたくないから読み取り専用属性を立てるんじゃないの? 上書きしていいかどうかは状況によるのでは?

    BackupReadやBackupWriteに言及していないのは非同期I/Oをサポートしていないからか? しかし(公開APIでは)これ以外に読み書きの方法がないメタ情報もあるので、避けて通ることはできない。

    WSLが第3のシンボリックリンク的な実装としてIO_REPARSE_TAG_LX_SYMLINKを導入した。

    Vista以降ではCancelSynchronusIoという同期I/Oをキャンセルできる関数が追加された。

    実際には、NT系ではゼロクリアされると仮定していい。別ドキュメントに根拠もある(Windowsのプロたるものドキュメントが相互矛盾している程度のことでうろたえてはならない)。ゼロクリアしたくないときはSetFileValidDataを使う。削除されたファイルの残骸かもしれないデータが読めてしまうのは重大なセキュリティ問題なので、この動作が変わることは考えづらい。SetFileValidDataもSeManageVolumePrivilegeを持つ(最初からボリューム全体を読み取れる)ユーザーにしか許可されていない。SetEndOfFileやSetFilePointerのドキュメントが保証を与えていないのは、Win9xではゼロクリアされなかったため。詳しくは白水氏(FastCopyの作者)のツイートを参照。

    FSCTL_SET_ZERO_DATAはNT系では無駄に二重にゼロクリアするだけだし、Win9x系ではサポートされていないので、ゼロ初期化の目的で役に立つ場面はない。これは基本的にスパースファイルに穴を開けるために使うもの。

    Vista以降ではGetFileInformationByHandleExでACLを無視したストリーム情報が取れるはずなので、これを使うべき。(18)を考慮しても、FindFirstStreamWがそもそもVista以降だしそれ以前のOSでもBackupReadがあるので非公開APIに出番はない。ていうかWin95時代から脳死状態でコピペを繰り返してるだけのSetEndOfFileやSetFilePointerのドキュメントの重箱の隅は異常に気にするくせにどうしてドキュメント化されていないAPIを平気で使うんだよ。

  • by Anonymous Coward on 2019年05月09日 16時06分 (#3611724)

    NTFSはUnix系のファイルシステムより高機能・複雑だし、権限管理周りもそう。
    普段意識する事はないがたまに気づかされる時もある。
    そういう事もあって、Windowsのファイル操作をExplorer意外でやるのはちょっと怖い。
    Linuxでマウントして操作するのも多少不安感があるな。
    ファイラーを作るってのはそこまで難しい事ではないし、Explorerの不便な点(主にタブ、あと長いパス名)もあるがそれでも避けてしまうな。
    Explorerなら安全は保障されていると思えるし。
    とはいえ場合によっては権限周りを無視できる点でLinuxとかから触った方が早い。

    まぁAPIがややこしいと言っても裏でrobocopyあたりを呼べば大概OKだろうけど、自前で高速コピーツールとか作る人は流石だと思う。
    相当仕様(非公開APIまで!)に知悉していないとできないだろうね。
    普通に使う時はスパースファイルやら代替ストリームやらのない単なるファイルだと思って、せいぜい残り容量・既にファイルが存在するか・長いファイル名・禁止文字(コピーだから触れられていないが重要)程度に注意すれば十分だろう。
    あと予想できない不条理な理由でファイルが作成できない事もあるくらいに想定しておくべきか。
    ついでにファイルシステムを超えるとタイムスタンプが一致しないってのも基本かな。期待する方がおかしいが。

    なんというか、NTFSの問題というよりAPIの問題が多くを占めているように思える。
    Win32 APIがクソだってのはみんな知ってるからその点では今更感はあるな。

    とはいえ権限もシンボリックリンクもハードリンクも代替データストリームもないFATの世界の気楽さは確かにある。
    USBメモリやSDカードの利便性の一つだと言えると思う。NTFSとかだと相当混乱したはずだ。

  • by Anonymous Coward on 2019年05月09日 14時53分 (#3611678)

    ほんの十数年前までは31文字までだったんだから、今でもそのくせで長いファイル名を名付けようと思わない。
    https://support.apple.com/kb/TA20771?locale=ja_JP&viewlocale=ja_JP [apple.com]

    SEOやファイル検索対策で、やたらと長いファイル名やURLにする人いるけど、扱う側にとっては無駄でしかないと思う。
    ページタイトルを英語にしなきゃいけないし、下手なローマ字変換していると恥をかくし。

    • by Anonymous Coward on 2019年05月09日 15時15分 (#3611689)

      最初の項目「(1)♪」で述べられているのは「パス文字列」なのだから、
      ファイル名が短かろうと、ディレクトリ階層の奥深くにあったりしたら、
      トータルのパス文字列数があっさり260を超えてしまうこともありうるのだよ。

      それに自分でつけなくとも、
      ・ネットからファイルをダウンロードしようとしたら、それにとんでもなく長い名前が付けられていた。
      ・アーカイブされたファイルを展開しようとしたら、それに(以下略。
      ・アーカイブファイルに深いファイル構造が仕込まれていて、展開場所のパスに追加されて260文字の制限を超えてしまう。
      なんてことも起きうるんだ。

      親コメント
    • >ほんの十数年前までは31文字までだったんだから、今でもそのくせで長いファイル名を名付けようと思わない。

      ファイル名だけでなくて、デリレクトリ含めたファイルパスの文字列の長さのことなんじゃないすかね。

      (1)♪ 当然、ファイルやディレクトリのパス文字列は 260 文字を超える可能性があるのだから、当然、先頭に謎の呪文である "\\?\" という文字列を付加する必要がある。これにより最大約 32767 文字までのパス名を取り扱えるようにすることを忘れるな。

      ♪ 当然
      ってどっかで流行ってる?

      親コメント
      • by Anonymous Coward

        Win10で、エクスプローラからルードディレクトリにファイル作って、
        300文字をファイル名にペーストしたら244文字で切られました。半角全角共に。
        パス長36文字のフォルダ以下だと211文字。

        場所によってファイル名に使える文字数が変わるってのがまたいやらしい。

        ドライブ+フォルダ+ファイル名=247文字っすかね。
        260文字までの残り13文字ってなんだろう。

        ちなみにWSL(Ubuntu)からファイル作れば255文字行けました。半角でも全角でも255文字。
        くっそ深い階層のWSLのホーム以下でも、浅い階層のWin側のホーム以下でも変わらず。
        まあそうじゃないとダメなんですが。

    • by Anonymous Coward on 2019年05月09日 15時40分 (#3611708)

      Windowsでは歴史的経緯から長いファイル名を扱う際

      Windowsではファイル名の長さが8.3形式より長いものをさして「長いファイル名(LFN,Long File Name)」という歴史的経緯があるので、この書き方はまずいと思う。
      ソースの文章の記述は正しいのに、色々と台無しだw

      親コメント
  • by Anonymous Coward on 2019年05月09日 15時06分 (#3611684)

    Win10のエクスプローラーは「長いパス名」に対応しておらず、
    長いパス名を含むフォルダを右クリックしてファイルの個数や容量をしらべたり、
    長いパス名を含むフォルダをコピーすると、長いパス名のファイルが含まれてないことがある

    ところが、長いファイル名のファイルをWin10のエクスプローラで作ることは可能

    作ったはずのファイルが、環境によって存在したり消えたりする不思議な仕様?バグ?

  • by Anonymous Coward on 2019年05月09日 15時09分 (#3611687)

    FAT16でフォーマットされているSDカードにコピーしてもアクセス権限や所有者などの定義は残るのか。それはすごいな。

    • by Anonymous Coward

      NTFSはフォーマットが非公開なのでファイルにどのような機能があるのか分かりにくく、多くの人たちに意見を聞けないのだろうね。
      そして場当たり的な拡張が積もり積もった結果今に至っているんじゃないかと。

      #簡単にファイルを整理するためのアプリをC#.NETで作ろうとしたら、dllの直接呼出しだらけになってC#を諦めるしかなかったOrz

  • by Anonymous Coward on 2019年05月09日 15時19分 (#3611693)

    各種フォーマット毎のお約束が有るのが当然の上、それらの相互処理もやろうってのだからねぇ。
    どっかで互換性を切って統一化すれば良いだろうが、今更それも無理だろうし。

  • 構成の限られた組み込み OS ではなく、現実的な一般ユーザーの使う OS で「何も考えなくても大丈夫」な FileCopy ができる OS ってどれ?
    Linux と macOS は外れるしなぁ

    • by Anonymous Coward

      Human68k

    • by Anonymous Coward

      mac、悪の枢軸HFS+は論外ですがAPFSそんなに筋悪いですか

    • by Anonymous Coward

      ファイルシステムとしてはFATは割と頭使わなくて済むんじゃない?
      機能が制限されてるから難しい事も考えなくて済む。

      現代的なOSでは何も考えずに確実なファイルコピーができるって事はシステムを破壊できかねないって事だから基本は無理だと思う。
      でも「ユーザーが通常期待するファイルコピーを行うAPI」を提供する事は可能だし、大抵のOSは標準のコマンドがそういう動作を行っているとは期待できる。
      もちろん安全に/権限上それができない時は失敗するわけだが。

  • by Anonymous Coward on 2019年05月09日 15時29分 (#3611701)

    コマンドプロンプトからmoveを使う場合「上書きしますか?」と確認が来るのだが、
    batにまとめて実行すると確認なしの強制上書きになるのです。

    最近知ってガクブル。

  • by Anonymous Coward on 2019年05月09日 15時45分 (#3611710)

    だけど、ほとんどの人にとってはCopyFile系のAPIで事足りるんじゃないかなぁ。
    https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbas... [microsoft.com]

  • by Anonymous Coward on 2019年05月09日 15時47分 (#3611712)

    それだけ判っているならサクッと作って公開してくれたら(ただで)
    よのなかの沢山の人が幸せになれると思うの

    • by Anonymous Coward

      それはOSベンダーがやるべき仕事じゃないのかねえ。
      つーかWindows付属のxcopyとかrobocopyもこれらの仕様を網羅できてないのでは。

      • ちょっと前に、HDDが死にかけたので慌てて吸い出せる分だけrobocopyで吸い出したのですが
        (普通のバックアップ系ソフトでは途中でエラーになって落ちてダメだった。robocopy で何度かリトライさせれば読み取りにに成功してある程度救える状況)、

        C:\Documents and Settings\ほげ\Local Settings\Application Data\Application Data\Application Data\…
        と無限ループコピーしようとしたり、
        「C:\Documents and Settings\ほげ」と「C:\Users\ほげ」とで二重にコピーしやがってコピー元よりもコピー先の方が容量くってたりとか
        さんざんでした。今回の記事指摘のジャンクション関係はまったく対応してなさそうな感じ。

        親コメント
        • robocopy /? より

          /XJ :: 接合ポイントとシンボリック リンクを除外します (通常は既定で含まれます)。

          # ヘルプがわかりにくい、とは思いますが。

          親コメント
        • by Anonymous Coward

          以前、robocopyでまるっと日付を保存してバックアップコピーしたかったのですが
          ディレクトリの日付が変わってしまっていました
          該当のオプションは指定したはずなのに・・・
          なんだかマイナーバグがありそうです

  • ファイルを読むだけで鼻から悪魔が出る可能性があるのか…
    ファイルの内容は不定です、ならまあゴミデータか何か訳わからんけど何がしかのバイト列が読み出されてくるんだろうな、と期待できるけど、未定義ですとか言われちゃうと本当に悪魔から核ミサイルまで何でも出てくる可能性があるってことになるが。
    • > ファイルを読むだけで鼻から悪魔が出る可能性があるのか…

      ここの原文は以下のようになっていて undefined behavior (鼻から悪魔) というわけではなく
      データの内容が未定義というだけです:

      https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileap... [microsoft.com]
      > the contents of the file between the old end of the file and the new end of the file are not defined

      あと、このデータ内容が未定義という仕様は Windows 95 の実装を考慮した記述になっているせいで
      Windows NT 系なら seek して飛ばして書いたところはゼロクリアされることが保証されているとか:

      https://twitter.com/shirouzu/status/1125975975735377920 [twitter.com]
      > MSの生き字引、レイモンド・チェンによると(ACLなどない)Win95ではSetEndOfFileでゼロクリアしていなかったらしい。
      > ドキュメントに保証する記述が無いのは、そのためと。
      > https://devblogs.microsoft.com/oldnewthing/?p=45171 [microsoft.com]

      https://twitter.com/shirouzu/status/1125977301831671808 [twitter.com]
      > それに関して「(ファイルシステム部が)NT系なら拡張部分を0と仮定してよい」と書いてあった。

      そのセクターに書かれていた古いデータが読めたりするとセキュリティ的な問題が生じるわけで、
      モダンなOSであれば 0 フィルされていることを期待しても大丈夫な筈です。

      親コメント
    • 悪魔が出ることはないが、仕様上何が入ってるか保証されない、という意味で本当にわからない。
      ゼロ埋めするかもしれないし、しないかもしれないし、てきとーなビット列で埋まってるかもしれない。
      だから例えばセクタ上の古いデータを読み出す目的に使えるかというと、そういうことにも使えない。
      ゼロ埋めされて「いない」データを期待することもできない。
      昔、巨大なダミーファイルを作る必要があって(Windows2000時代で、まだfsutilコマンドは無かった)、調べてSetEndOfFileの仕様を知ったとき、「へ〜、一体どんなデータが読めるんだろう?」とワクワクしながら叩いてみたら、きっかり全ゼロで埋められててガッカリした。

      親コメント
    • by Anonymous Coward

      悪魔がデジタルデータに変化して潜んでいても上書きされないかもしれないんだから、出てくる可能性はあるんじゃないの?

    • by Anonymous Coward

      まあ未定義と不定の違いは置いといて、mallocからの類推から当然に既定では内容は不定だと思ってた。
      記事書いた人的には「最大限の恐怖」らしいんだけど、しがないアプリ書きには全然ピンと来ない話だ。
      // 未定義と不定の違いを言ってるのかと思ったけど、そこらへんは問題にしてないようだし。

    • by Anonymous Coward

      「不定」と「未定義」って同じようなものとは思わないがそんなにかけ離れてはいない気がするけど

    • by Anonymous Coward

      そういや、たしかJavaの旧IO系(java.io)APIもこのWindowsの仕様に準じてファイルポインタの移動で拡張した領域の内容は未定義とかってなってたはず……

      もっともファイルポインタの移動でファイル領域を拡張できる全てのAPIにこの注意書きが書いてあるわけではないとかいうアレげな事になってるので……

typodupeerror

一つのことを行い、またそれをうまくやるプログラムを書け -- Malcolm Douglas McIlroy

読み込み中...