ls.exe -n does not work on NFS filesystems

オープン
#86 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
45/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
静か
技術スタック
rust

調査の方向性

ls.exe のメタデータ処理の Rust 実装から開始し、Windows で -n オプションがファイル属性を取得する方法を追跡してください。その経路を、issue にある NfsV3Attributes EA と ZwQueryEaFile の例と比較し、その後、列挙されている Windows NFS ドライバーのいずれかを使ってテストしてください。ls.exe -n が NFS ファイルシステム上で期待される数値メタデータを報告すれば完了です。

索引モデルが issue の本文から書いたものです。

説明

C-bug

ls.exe -n does not work on NFS filesystems, e.g. Windows NFSv3 driver, OpenText/Exceed NFSv4 driver, ms-nfs41-client driver.

All these drivers implement the ServicesForUNIX API to obtain stat()-alike information.

The API is simply to get the EA "NfsV3Attributes" for for a file or directory, which contains a nfs3_attrs struct:

#define EA_NFSV3ATTRIBUTES "NfsV3Attributes"
#define EA_NFSV3ATTRIBUTES_LEN (15)

/*
 * "NfsV3Attributes" uses |nfs3_attrs| as content
 */
/*
 * Note that we cannot use <stdint.h> in the Windows kernel, so we
 * use Windows Types here
 */
typedef struct _nfs3_attrs_timestruc_t {
    INT32   tv_sec;
    UINT32  tv_nsec;
} nfs3_attrs_timestruc_t;

typedef struct _nfs3_attrs {
    UINT32 type, mode, nlink, uid, gid, filler1;
    UINT64 size, used;
    struct {
        UINT32 specdata1;
        UINT32 specdata2;
    } rdev;
    UINT64 fsid, fileid;
    nfs3_attrs_timestruc_t atime, mtime, ctime;
} nfs3_attrs;

enum ftype3 {
    NF3REG = 1,
    NF3DIR,
    NF3BLK,
    NF3CHR,
    NF3LNK,
    NF3SOCK,
    NF3FIFO
};

Example function, based on https://github.com/kofemann/ms-nfs41-client/blob/master/include/nfs_ea.h and https://github.com/kofemann/ms-nfs41-client/blob/master/tests/winfsinfo1/winfsinfo.c

int get_nfs3attr(const char *progname, const char *filename)
{
    int res = EXIT_FAILURE;

    HANDLE fileHandle = CreateFileA(filename,
        GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS, NULL);
    if (fileHandle == INVALID_HANDLE_VALUE) {
        (void)fprintf(stderr,
            "%s: Error opening file '%s'. Last error was %d.\n",
            progname,
            filename,
            (int)GetLastError());
        return EXIT_FAILURE;
    }

    struct {
        FILE_FULL_EA_INFORMATION ffeai;
        char buf[sizeof(EA_NFSV3ATTRIBUTES) + sizeof(nfs3_attrs)];
    } ffeai_buf;
    struct {
        FILE_GET_EA_INFORMATION fgeai;
        char buf[sizeof(EA_NFSV3ATTRIBUTES)];
    } fgeai_buf;

    NTSTATUS status;
    IO_STATUS_BLOCK io;

    fgeai_buf.fgeai.NextEntryOffset = 0;
    fgeai_buf.fgeai.EaNameLength = 15;
    (void)strcpy(fgeai_buf.fgeai.EaName, EA_NFSV3ATTRIBUTES);

    status = ZwQueryEaFile(fileHandle, &io,
        &ffeai_buf.ffeai, sizeof(ffeai_buf), TRUE,
        &fgeai_buf.fgeai, sizeof(fgeai_buf), NULL, TRUE);

    switch (status) {
        case STATUS_SUCCESS:
            break;
        case STATUS_NO_EAS_ON_FILE:
            (void)fprintf(stderr, "No EAs on file, status=0x%lx.\n", (long)status);
            res = EXIT_FAILURE;
            goto done;
        default:
            (void)fprintf(stderr, "ZwQueryEaFile() failed with 0x%lx\n", (long)status);
            res = EXIT_FAILURE;
            goto done;
    }

    if (ffeai_buf.ffeai.EaValueLength < sizeof(nfs3_attrs)) {
            (void)fprintf(stderr,
                "EA '%s' size too small (%ld bytes), "
                "expected at least %ld bytes for nfs3_attrs\n",
                EA_NFSV3ATTRIBUTES,
                (long)ffeai_buf.ffeai.EaValueLength,
                (long)sizeof(nfs3_attrs));
            res = EXIT_FAILURE;
            goto done;
    }

    nfs3_attrs *n3a = (nfs3_attrs *)(ffeai_buf.ffeai.EaName
        + ffeai_buf.ffeai.EaNameLength + 1);

    (void)printf("(\n");

    (void)printf("\tfilename='%s'\n"
        "\ttype=%d\n"
        "\tmode=0%o\n"
        "\tnlink=%d\n"
        "\tuid=%d\n\tgid=%d\n"
        "\tsize=%lld\n\tused=%lld\n"
        "\trdev=( specdata1=0x%x specdata2=0x%x )\n"
        "\tfsid=0x%llx\n\tfileid=0x%llx\n"
        "\tatime=( tv_sec=%ld tv_nsec=%lu )\n"
        "\tmtime=( tv_sec=%ld tv_nsec=%lu )\n"
        "\tctime=( tv_sec=%ld tv_nsec=%lu )\n"
        ")\n",
        filename,
        (int)n3a->type,
        (int)n3a->mode,
        (int)n3a->nlink,
        (int)n3a->uid,
        (int)n3a->gid,
        (long long)n3a->size,
        (long long)n3a->used,
        (int)n3a->rdev.specdata1,
        (int)n3a->rdev.specdata2,
        (unsigned long long)n3a->fsid,
        (unsigned long long)n3a->fileid,
        (long)n3a->atime.tv_sec, (unsigned long)n3a->atime.tv_nsec,
        (long)n3a->mtime.tv_sec, (unsigned long)n3a->mtime.tv_nsec,
        (long)n3a->ctime.tv_sec, (unsigned long)n3a->ctime.tv_nsec);
    res = EXIT_SUCCESS;

done:
    (void)CloseHandle(fileHandle);
    return res;
}
主要言語
Rust
スター
5.2k
フォーク
107
平均マージ
2日 19時間
マージ済み PR(30日)
4

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

microsoft/coreutils のほかの issue

microsoft/coreutils の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。