2023/09/07(木)ジャンクション(NTFS)の更新日時を変更する

ジャンクション(NTFS)の更新日時を変更する

ちょっとジャンクション(NTFS)の更新日時を書き換えようとしたら、すんなりできなくて結構手間取ったのでメモ。

通常の方法ではリンク先の更新日時が変更される

まずはディレクトリとジャンクションをセットで作成。

$directory = New-Item -Path "test_directory" -ItemType Directory
$junction = New-Item -Value "test_directory" -Path "test_junction" -ItemType Junction
dir

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2023/09/07      3:48                test_directory
d----l        2023/09/07      3:48                test_junction

そして、ジャンクションの方に更新日時を設定してみると、ジャンクションではなくリンク先のディレクトリの更新日時が書き換えられてしまいました。

$junction.LastWriteTime = "2000-01-02T03:04:05+09:00"
dir

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2000/01/02      3:04                test_directory
d----l        2023/09/07      3:48                test_junction

仕様と言えばそうなのかも知れませんが、それだったら表示される更新日時もリンク先のものでないと一貫性が無いような……。

ジャンクションそのものの更新日時を変更する方法

まずは「Junction LastWriteTime」とかで調べてみると、英語圏で同様の疑問が挙がっていましたが手っ取り早い解決策は無さそうでした。(Windows APIを直接使う必要がありそうな感じ。)

更新日時変更をWindows APIを使って行う場合、CreateFile→SetFileTimeという手順になるのでこっちを調べてみたところ、ジャンクション(リパースポイント)をCreateFileで開くときにOPEN_REPARSE_POINTフラグを付けて開くとリンクを辿らずに開いてくれそうです。

FileTimeコピープログラム作成

OPEN_REPARSE_POINTを指定するにはWindows APIで直接指定するしか無さそうなので、自分でプログラムを作ることにしました。

日時を自由に指定できるようにするには日時文字列の解釈が必要になって面倒なので、他のファイル・フォルダの日時をコピーするプログラムです。これなら、GetFileTimeが使えるので楽。

SetFileTimeがcreationTime/lastAccessTime/lastWriteTimeを扱うので全部コピーしています。(コピーしたくなければNULLを渡せば変更されない。)

手抜きなので失敗してもメッセージとかは出ません(^_^;)

  • ソースコード
    #include <windows.h>
    #include <tchar.h>
    
    int _tmain(int argc, _TCHAR *argv[])
    {
        HANDLE hFrom;
        HANDLE hTo;
    
        FILETIME creationTime, lastAccessTime, lastWriteTime;
    
        if (argc < 3)
        {
            return 1;
        }
    
        //----------------------------------------
        // Get FILETIME from argv[1]
        //----------------------------------------
        hFrom = CreateFile(
            argv[1],
            GENERIC_READ,
            0,
            NULL,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS,
            NULL);
        if (hFrom == INVALID_HANDLE_VALUE)
        {
            return 1;
        }
        if (!GetFileTime(hFrom, &creationTime, &lastAccessTime, &lastWriteTime))
        {
            return 1;
        }
        CloseHandle(hFrom);
    
        //----------------------------------------
        // Set FILETIME to argv[2]
        //----------------------------------------
        hTo = CreateFile(
            argv[2],
            GENERIC_READ | GENERIC_WRITE,
            0,
            NULL,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
            NULL);
        if (hTo == INVALID_HANDLE_VALUE)
        {
            return 1;
        }
        if (!SetFileTime(hTo, &creationTime, &lastAccessTime, &lastWriteTime))
        {
            return 1;
        }
        CloseHandle(hTo);
    
        return 0;
    }
    
  • コンパイル
    "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars32.bat"
    cl.exe /DUNICODE /D_UNICODE /source-charset:utf-8 CopyFileTime.c
    

ジャンクションへのFileTimeコピー実験

CopyFileTime.exe test_directory test_junction

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2000/01/02      3:04                test_directory
d----l        2000/01/02      3:04                test_junction

ちゃんと日時コピーできてました。

コピー元の方はOPEN_REPARSE_POINTを付けずに開いている(リンク先を辿る)ので、

CopyFileTime.exe test_junction test_junction

としても同じ効果のはず。

2023/06/11(日)Synology DS218+ Entware導入 & Subversion導入

PC::NAS

Synology DS218+ Entware導入 & Subversion導入

以前、Entware-ngというパッケージ管理ツールを導入しましたが、Entware-ngとEntware-3xが統合されてEntwareになったようなので、Entwareを導入してみます。それから、DSM7からパッケージセンターのSVN Serverが使えなくなったので、Subversionの導入もやってみます。

続きを読む

2023/05/17(水)X-Finder → Tablacus Explorer 移行メモ

PC::Memo

今さらながらファイラーをX-FinderからTablacus Explorerに移行したので設定などをメモ。

以前移行を試したときは独自メニューの作り方が分からなくて諦めたけど、今回はちゃんとできました。

tc.png

続きを読む

2023/04/22(土)[Tampermonkey] fetch responseの割り込み取得

[Tampermonkey] fetch responseの横取り取得

Webページがfetchで動的に取得したJSONデータを観測する手段は無いかなと思って見つけた方法。

ソースコード

// ==UserScript==
// @name        Test intercept fetch
// @description Test intercept fetch
// @namespace   Test
// @version     1.0
// @match       https://example.com/*
// @run-at      document-start
// @grant       unsafeWindow
// ==/UserScript==

const proc_fetch_resp = (data, url) => {
    console.log("proc_fetch_resp:" + url, data);
}

//=====================================================
// Intercept fetch
//=====================================================
const origFetch = unsafeWindow.fetch;
//元のfetchを差し替え
unsafeWindow.fetch = async (...args) => {
    console.log("fetch called with args:", args);
    const response = await origFetch(...args);

    //レスポンスをクローンして使う
    response
        .clone()
        .json()
        .then(body => {
            proc_fetch_resp(body, response.url);
        })
        .catch(err => console.error(err))
        ;

    //元のレスポンスを返す
    return response;
}
  • @match は対象サイトのURLを指定
  • @run-at は割り込みたいfetchよりに先にfetch差し替えができるように指定
  • unsafeWindow を使わないとfetch差し替えができない
  • サンプルなのでレスポンスをJSONとして読み取ってconsole.logに出すだけ。

参考URL

2021/01/09(土)Synology NAS 取り外したHDDへのアクセス(USB経由)

PC::NAS

Synology NAS 取り外したHDDへのアクセス(USB経由)

20210109_1.png

Synology DS216jのHDDを入れ替えたときに、USB経由で旧HDDデータへのアクセスを試してみたのでメモ。


前提

20210109_2.png

  • RAIDタイプ: Basic (データ保護無し)
    • RAID無しの単一HDDとしての運用。

たぶんRAID1でも同じ事ができます。SHR (Synology Hybrid RAID) で同じ事ができるかは不明……。



HDD交換

今回は1台のみ新しいHDDと交換しました。Basicで運用している場合も、DSM (OS) はミラーリングされているようなので、片方だけの交換ならDSMの再インストールは不要です。

USB接続

旧HDDを外付けHDDケースに入れて、USBでNASに接続します。HDD自体は認識され、パーティションの存在も確認出来ますが、このままだとデータにはアクセス出来ません。

20210109_3.png

外付けHDDの状態確認

  1. 作業前にroot権限を取っておきます。
    sudo -i
    
  2. 接続したHDDの確認
    fdisk -l
    Disk /dev/sdq: 7.3 TiB, 8001563222016 bytes, 15628053168 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes
    Disklabel type: gpt
    Disk identifier: ****
    
    Device       Start         End     Sectors  Size Type
    /dev/sdq1     2048     4982527     4980480  2.4G Linux RAID
    /dev/sdq2  4982528     9176831     4194304    2G Linux RAID
    /dev/sdq3  9437184 15627848351 15618411168  7.3T Linux RAID
    
    • /dev/sdq1~3として認識されているようです。データが入っているのは/dev/sdq3ですが、Basicの場合でもRAIDは作られるようで、TypeはLinux RAIDです。
    • 認識されていない場合は、partprobeコマンドを実行すれば認識されるかも。
  3. RAID状態の確認
    cat /proc/mdstat
    Personalities : [linear] [raid0] [raid1] [raid10] [raid6] [raid5] [raid4] 
    md3 : active raid1 sda3[0]
          9761614848 blocks super 1.2 [1/1] [U]
          
    md2 : active raid1 sdb3[0]
          7809204544 blocks super 1.2 [1/1] [U]
          
    md1 : active raid1 sda2[0] sdb2[1]
          2097088 blocks [2/2] [UU]
          
    md0 : active raid1 sda1[0] sdb1[1]
          2490176 blocks [2/2] [UU]
    
    • md0~md3が作られています。BasicはHDDが1個だけのRAID1扱い。
    • あとでmd9を作るので使われていないことを確認。

外付けHDDのマウント

まずRAIDを認識させてから、RAIDボリュームをマウントする必要があります。

  1. 作業前にroot権限を取っておきます。
    sudo -i
    
  2. RAIDを編成。
    mdadm -A -R /dev/md9 /dev/sdq3
    
  3. マウント。場所はどこでも良いですが、今回は/volume1/from_USBにマウントします。
    mkdir /volume1/from_USB
    mount /dev/md9 /volume1/from_USB
    
  4. これで、/volume1/from_USB 下に外付けHDDのデータが見えるので、コピーなどが可能です。
    # backupフォルダを/volume1 下にコピーする例
    cp -a /volume1/from_USB/backup   /volume1/
    
  5. アンマウント
    umount /volume1/from_USB
    mdadm -S /dev/md9
    

暗号化フォルダ(ディレクトリ)のマウント

共有フォルダを暗号化していた場合は、中を見るには暗号化フォルダのマウントが必要です。(当然パスワードは必要。)暗号化されたフォルダは@で囲まれた名前になっています。

    • 暗号化されたフォルダ名: /volume1/from_USB/@backup_e@
    • マウント先フォルダ名: /volume1/from_USB/backup_e
  1. 作業前にroot権限を取っておきます。
    sudo -i
    
  2. 暗号化フォルダをマウント。
    mkdir /volume1/from_USB/backup_e
    mount.ecryptfs /volume1/from_USB/@backup_e@ /volume1/from_USB/backup_e -o 'key=passphrase:passphrase_passwd=パスワード,ecryptfs_cipher=aes,ecryptfs_key_bytes=32,ecryptfs_passthrough=n,no_sig_cache,ecryptfs_enable_filename_crypto=y'
    
  3. これで、/volume1/from_USB/backup_e 下に暗号化フォルダのデータが見えるようになります。
  4. アンマウント
    umount /volume1/from_USB/backup_e
    

なお、まるごとコピーしたいだけなら、@backup_e@を/volume1の下にそのままコピーすれば、DSMのコントロールパネルからマウントできるようです。

おまけ:取り外したHDDのWindowsでの再利用

  1. Windows PCに接続
  2. 「ディスクの管理」を開く
    20210109_4.png
    • 3つのパーティション(と隙間)が確認出来ます。
  3. パーティションを右クリック→ボリュームの削除で、全てのパーティションを削除。
    20210109_5.png
  4. 右クリック→新しいシンプルボリュームで、新しいパーティションを作成。NTFSなどでフォーマットすればWindowsで使用出来るようになります。
    20210109_6.png