標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

Windows でジャンクション作れない・リベンジ編

「DeviceIoControl用の構造体」を作るのに、Microsoft ご本家の Go 言語パッケージ Microsoft/go-winio: Win32 IO-related utilities for Goを使ったら、うまく動作するようになった!やったね、たえちゃん、nyagosの機能が増えるよ

junction_run.go

package main

import (
    "errors"
    "os"

    "golang.org/x/sys/windows"
    "golang.org/x/xerrors"

    "github.com/Microsoft/go-winio"
)

const (
    _FSCTL_SET_REPARSE_POINT          = 589988
    _INVALID_HANDLE_VALUE = ^windows.Handle(0)
)


func MountPointCreate(mountPointPath, target string) error {
    _mountPointPath, err := windows.UTF16FromString(mountPointPath)
    if err != nil {
        return xerrors.Errorf("UTF16FromString(%s): %v", mountPointPath, err)
    }

    err = windows.CreateDirectory(&_mountPointPath[0], nil)
    if err != nil {
        return xerrors.Errorf("windows.CreateDirectory(%s): %v", mountPointPath, err)
    }
    ok := false
    defer func() {
        if !ok {
            os.Remove(mountPointPath)
        }
    }()

    handle, err := windows.CreateFile(&_mountPointPath[0],
        windows.GENERIC_WRITE,
        0,
        nil,
        windows.OPEN_EXISTING,
        windows.FILE_FLAG_BACKUP_SEMANTICS,
        0)
    if err != nil {
        return xerrors.Errorf("windows.CreateFile(%s): %v", mountPointPath, err)
    }
    if handle == _INVALID_HANDLE_VALUE {
        return errors.New("windows.CreateFile: invalid handle value")
    }
    defer windows.CloseHandle(handle)

    rp := winio.ReparsePoint{
        Target:       target,
        IsMountPoint: true,
    }

    data := winio.EncodeReparsePoint(&rp)

    var size uint32

    err = windows.DeviceIoControl(
        handle,
        _FSCTL_SET_REPARSE_POINT,
        &data[0],
        uint32(len(data)),
        nil,
        0,
        &size,
        nil)

    if err != nil {
        return xerrors.Errorf("windows.DeviceIoControl: %v", err)
    }
    ok = true
    return nil
}

func main() {
    if len(os.Args) < 3 {
        println("go run junction.go DST SRC")
        return
    }
    if err := MountPointCreate(os.Args[1], os.Args[2]); err != nil {
        println(err.Error())
        os.Exit(1)
    }
}
$ go run junction_run.go Hoge c:\tmp
$ ls -ld Hoge\
-rw---- 0 Mar 24 20:06:42 Hoge@ -> c:\tmp
$ cd Hoge\
$