~rbn/neinp

314a874f1439902314753295580dc8ef3083fde8 — Aaron Bieber 3 months ago f0b9198
Split FileInfo into separate files that can be used per OS.

This allows neinp to be used on Darwin and plan9.
M qid/fileinfo.go => qid/fileinfo.go +1 -21
@@ 3,31 3,11 @@ package qid // import "go.rbn.im/neinp/qid"
import (
	"hash/fnv"
	"os"
	"syscall"
)

// FileInfo creates a neinp.Qid from os.FileInfo, using Sys of FileInfo if possible.
func FileInfo(fi os.FileInfo) Qid {
	s, ok := fi.Sys().(*syscall.Stat_t)
	if !ok {
		return Generic(fi)
	}

	t := TypeFile
	if fi.IsDir() {
		t = TypeDir
	}

	// fvn hashes match the size of version and path fields. they are no cryptographical hashes, but should work good enough.
	v := fnv.New32a()
	v.Write([]byte{uint8(s.Mtim.Sec), uint8(s.Mtim.Sec >> 8), uint8(s.Mtim.Sec >> 16), uint8(s.Mtim.Sec >> 24), uint8(s.Mtim.Sec >> 32), uint8(s.Mtim.Sec >> 40), uint8(s.Mtim.Sec >> 48), uint8(s.Mtim.Sec >> 56)})
	v.Write([]byte{uint8(s.Mtim.Nsec), uint8(s.Mtim.Nsec >> 8), uint8(s.Mtim.Nsec >> 16), uint8(s.Mtim.Nsec >> 24), uint8(s.Mtim.Nsec >> 32), uint8(s.Mtim.Nsec >> 40), uint8(s.Mtim.Nsec >> 48), uint8(s.Mtim.Nsec >> 56)})

	p := fnv.New64a()
	p.Write([]byte{uint8(s.Dev), uint8(s.Dev >> 8), uint8(s.Dev >> 16), uint8(s.Dev >> 24), uint8(s.Dev >> 32), uint8(s.Dev >> 40), uint8(s.Dev >> 48), uint8(s.Dev >> 56)})
	p.Write([]byte{uint8(s.Ino), uint8(s.Ino >> 8), uint8(s.Ino >> 16), uint8(s.Ino >> 24), uint8(s.Ino >> 32), uint8(s.Ino >> 40), uint8(s.Ino >> 48), uint8(s.Ino >> 56)})

	return Qid{Type: t, Version: v.Sum32(), Path: p.Sum64()}
	return fileInfo(fi)
}

// Generic creates a neinp.Qid not using FileInfo.Sys().

A qid/fileinfo_nostat.go => qid/fileinfo_nostat.go +13 -0
@@ 0,0 1,13 @@
//+build darwin plan9

package qid // import "go.rbn.im/neinp/qid"

import (
	"os"
)

// fileInfo creates a neinp.Qid from os.FileInfo on systems where syscall.Stat
// is missing or limited.
func fileInfo(fi os.FileInfo) Qid {
	return Generic(fi)
}

A qid/fileinfo_stat.go => qid/fileinfo_stat.go +33 -0
@@ 0,0 1,33 @@
//+build !darwin,!plan9

package qid // import "go.rbn.im/neinp/qid"

import (
	"hash/fnv"
	"os"
	"syscall"
)

// fileInfo creates a neinp.Qid from os.FileInfo, using Sys of FileInfo if possible.
func fileInfo(fi os.FileInfo) Qid {
	s, ok := fi.Sys().(*syscall.Stat_t)
	if !ok {
		return Generic(fi)
	}

	t := TypeFile
	if fi.IsDir() {
		t = TypeDir
	}

	// fvn hashes match the size of version and path fields. they are no cryptographical hashes, but should work good enough.
	v := fnv.New32a()
	v.Write([]byte{uint8(s.Mtim.Sec), uint8(s.Mtim.Sec >> 8), uint8(s.Mtim.Sec >> 16), uint8(s.Mtim.Sec >> 24), uint8(s.Mtim.Sec >> 32), uint8(s.Mtim.Sec >> 40), uint8(s.Mtim.Sec >> 48), uint8(s.Mtim.Sec >> 56)})
	v.Write([]byte{uint8(s.Mtim.Nsec), uint8(s.Mtim.Nsec >> 8), uint8(s.Mtim.Nsec >> 16), uint8(s.Mtim.Nsec >> 24), uint8(s.Mtim.Nsec >> 32), uint8(s.Mtim.Nsec >> 40), uint8(s.Mtim.Nsec >> 48), uint8(s.Mtim.Nsec >> 56)})

	p := fnv.New64a()
	p.Write([]byte{uint8(s.Dev), uint8(s.Dev >> 8), uint8(s.Dev >> 16), uint8(s.Dev >> 24), uint8(s.Dev >> 32), uint8(s.Dev >> 40), uint8(s.Dev >> 48), uint8(s.Dev >> 56)})
	p.Write([]byte{uint8(s.Ino), uint8(s.Ino >> 8), uint8(s.Ino >> 16), uint8(s.Ino >> 24), uint8(s.Ino >> 32), uint8(s.Ino >> 40), uint8(s.Ino >> 48), uint8(s.Ino >> 56)})

	return Qid{Type: t, Version: v.Sum32(), Path: p.Sum64()}
}

M stat/fileinfo.go => stat/fileinfo.go +3 -42
@@ 1,54 1,15 @@
package stat // import "go.rbn.im/neinp/stat"

import (
	"go.rbn.im/neinp/qid"
	"os"
	"os/user"
	"strconv"
	"syscall"
	"time"

	"go.rbn.im/neinp/qid"
)

// FileInfo creates Stat using os.FileInfo.Sys(). If using the information
// returned by Sys() fails, it returns a stat like returned by GenericStat.
func FileInfo(fi os.FileInfo) Stat {
	s, ok := fi.Sys().(*syscall.Stat_t)
	if !ok {
		return Generic(fi)
	}

	size := fi.Size()
	if fi.IsDir() {
		size = 0
	}

	var uid, gid string

	x, err := user.LookupId(strconv.Itoa(int(s.Uid)))
	if err != nil {
		return Generic(fi)
	}
	uid = x.Name

	y, err := user.LookupGroupId(strconv.Itoa(int(s.Gid)))
	if err != nil {
		return Generic(fi)
	}
	gid = y.Name

	stat := Stat{
		Qid:    qid.FileInfo(fi),
		Mode:   Mode(fi.Mode()),
		Atime:  time.Unix(s.Atim.Sec, s.Atim.Nsec),
		Mtime:  time.Unix(s.Mtim.Sec, s.Mtim.Nsec),
		Length: uint64(size),
		Name:   fi.Name(),
		Uid:    uid,
		Gid:    gid,
		Muid:   uid,
	}

	return stat
	return fileInfo(fi)
}

// Generic creates a neinp.Stat not using FileInfo.Sys().

A stat/fileinfo_nostat.go => stat/fileinfo_nostat.go +13 -0
@@ 0,0 1,13 @@
//+build darwin plan9

package stat // import "go.rbn.im/neinp/stat"

import (
	"os"
)

// fileInfo creates Stat using os.FileInfo.Sys(). If using the information
// returned by Sys() fails, it returns a stat like returned by GenericStat.
func fileInfo(fi os.FileInfo) Stat {
	return Generic(fi)
}

A stat/fileinfo_stat.go => stat/fileinfo_stat.go +55 -0
@@ 0,0 1,55 @@
//+build !darwin,!plan9

package stat // import "go.rbn.im/neinp/stat"

import (
	"os"
	"os/user"
	"strconv"
	"syscall"
	"time"

	"go.rbn.im/neinp/qid"
)

// fileInfo creates Stat using os.FileInfo.Sys(). If using the information
// returned by Sys() fails, it returns a stat like returned by GenericStat.
func fileInfo(fi os.FileInfo) Stat {
	s, ok := fi.Sys().(*syscall.Stat_t)
	if !ok {
		return Generic(fi)
	}

	size := fi.Size()
	if fi.IsDir() {
		size = 0
	}

	var uid, gid string

	x, err := user.LookupId(strconv.Itoa(int(s.Uid)))
	if err != nil {
		return Generic(fi)
	}
	uid = x.Name

	y, err := user.LookupGroupId(strconv.Itoa(int(s.Gid)))
	if err != nil {
		return Generic(fi)
	}
	gid = y.Name

	stat := Stat{
		Qid:    qid.FileInfo(fi),
		Mode:   Mode(fi.Mode()),
		Atime:  time.Unix(s.Atim.Sec, s.Atim.Nsec),
		Mtime:  time.Unix(s.Mtim.Sec, s.Mtim.Nsec),
		Length: uint64(size),
		Name:   fi.Name(),
		Uid:    uid,
		Gid:    gid,
		Muid:   uid,
	}

	return stat
}