250 lines
5.8 KiB
Go
250 lines
5.8 KiB
Go
// Copyright 2009 The go9p Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package go9p
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
func atime(fi os.FileInfo) time.Time {
|
|
return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
|
|
}
|
|
|
|
// IsBlock reports if the file is a block device
|
|
func isBlock(d os.FileInfo) bool {
|
|
// stat := d.Sys().(*syscall.Stat_t)
|
|
// return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
|
|
return true
|
|
}
|
|
|
|
// IsChar reports if the file is a character device
|
|
func isChar(d os.FileInfo) bool {
|
|
// stat := d.Sys().(*syscall.Stat_t)
|
|
// return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
|
|
return true
|
|
}
|
|
|
|
func dir2Qid(d os.FileInfo) *Qid {
|
|
var qid Qid
|
|
|
|
qid.Path = uint64(d.Sys().(*syscall.Win32FileAttributeData).FileSizeLow)
|
|
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
|
|
qid.Type = dir2QidType(d)
|
|
|
|
return &qid
|
|
}
|
|
|
|
func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) {
|
|
if r := recover(); r != nil {
|
|
fmt.Print("stat failed: ", r)
|
|
return nil, &os.PathError{"dir2Dir", path, nil}
|
|
}
|
|
sysif := d.Sys()
|
|
if sysif == nil {
|
|
return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil}
|
|
}
|
|
sysMode := sysif.(*syscall.Win32FileAttributeData)
|
|
|
|
dir := new(ufsDir)
|
|
dir.Qid = *dir2Qid(d)
|
|
dir.Mode = dir2Npmode(d, dotu)
|
|
dir.Atime = uint32(atime(d).Unix())
|
|
dir.Mtime = uint32(d.ModTime().Unix())
|
|
dir.Length = uint64(d.Size())
|
|
dir.Name = path[strings.LastIndex(path, "/")+1:]
|
|
|
|
if dotu {
|
|
dir.dotu(path, d, upool, sysMode)
|
|
return &dir.Dir, nil
|
|
}
|
|
|
|
// unixUid := int(sysMode.Uid)
|
|
// unixGid := int(sysMode.Gid)
|
|
// dir.Uid = strconv.Itoa(unixUid)
|
|
// dir.Gid = strconv.Itoa(unixGid)
|
|
|
|
dir.Uid = "none"
|
|
dir.Gid = "none"
|
|
dir.Muid = "none"
|
|
|
|
// BUG(akumar): LookupId will never find names for
|
|
// groups, as it only operates on user ids.
|
|
// u, err := user.LookupId(dir.Uid)
|
|
// if err == nil {
|
|
// dir.Uid = u.Username
|
|
// }
|
|
// g, err := user.LookupId(dir.Gid)
|
|
// if err == nil {
|
|
// dir.Gid = g.Username
|
|
// }
|
|
|
|
var err error
|
|
/* For Akaros, we use the Muid as the link value. */
|
|
if *Akaros && (d.Mode()&os.ModeSymlink != 0) {
|
|
dir.Muid, err = os.Readlink(path)
|
|
if err == nil {
|
|
dir.Mode |= DMSYMLINK
|
|
}
|
|
}
|
|
return &dir.Dir, nil
|
|
}
|
|
|
|
func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Win32FileAttributeData) {
|
|
// u := upool.Uid2User(int(sysMode.Uid))
|
|
// g := upool.Gid2Group(int(sysMode.Gid))
|
|
// dir.Uid = u.Name()
|
|
// if dir.Uid == "" {
|
|
// dir.Uid = "none"
|
|
// }
|
|
|
|
// dir.Gid = g.Name()
|
|
// if dir.Gid == "" {
|
|
// dir.Gid = "none"
|
|
// }
|
|
// dir.Muid = "none"
|
|
// dir.Ext = ""
|
|
// dir.Uidnum = uint32(u.Id())
|
|
// dir.Gidnum = uint32(g.Id())
|
|
// dir.Muidnum = NOUID
|
|
// if d.Mode()&os.ModeSymlink != 0 {
|
|
// var err error
|
|
// dir.Ext, err = os.Readlink(path)
|
|
// if err != nil {
|
|
// dir.Ext = ""
|
|
// }
|
|
// } else if isBlock(d) {
|
|
// dir.Ext = fmt.Sprintf("b %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
|
|
// } else if isChar(d) {
|
|
// dir.Ext = fmt.Sprintf("c %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
|
|
// }
|
|
dir.Uid = "none"
|
|
dir.Gid = "none"
|
|
dir.Muid = "none"
|
|
dir.Uidnum = 0
|
|
dir.Gidnum = 0
|
|
dir.Muidnum = NOUID
|
|
dir.Ext = ""
|
|
}
|
|
|
|
func (u *Ufs) Wstat(req *SrvReq) {
|
|
fid := req.Fid.Aux.(*ufsFid)
|
|
err := fid.stat()
|
|
if err != nil {
|
|
req.RespondError(err)
|
|
return
|
|
}
|
|
|
|
dir := &req.Tc.Dir
|
|
if dir.Mode != 0xFFFFFFFF {
|
|
mode := dir.Mode & 0777
|
|
if req.Conn.Dotu {
|
|
if dir.Mode&DMSETUID > 0 {
|
|
mode |= syscall.S_ISUID
|
|
}
|
|
if dir.Mode&DMSETGID > 0 {
|
|
mode |= syscall.S_ISGID
|
|
}
|
|
}
|
|
e := os.Chmod(fid.path, os.FileMode(mode))
|
|
if e != nil {
|
|
req.RespondError(toError(e))
|
|
return
|
|
}
|
|
}
|
|
|
|
uid, gid := NOUID, NOUID
|
|
if req.Conn.Dotu {
|
|
uid = dir.Uidnum
|
|
gid = dir.Gidnum
|
|
}
|
|
|
|
// Try to find local uid, gid by name.
|
|
if (dir.Uid != "" || dir.Gid != "") && !req.Conn.Dotu {
|
|
uid, err = lookup(dir.Uid, false)
|
|
if err != nil {
|
|
req.RespondError(err)
|
|
return
|
|
}
|
|
|
|
// BUG(akumar): Lookup will never find gids
|
|
// corresponding to group names, because
|
|
// it only operates on user names.
|
|
gid, err = lookup(dir.Gid, true)
|
|
if err != nil {
|
|
req.RespondError(err)
|
|
return
|
|
}
|
|
}
|
|
|
|
if uid != NOUID || gid != NOUID {
|
|
e := os.Chown(fid.path, int(uid), int(gid))
|
|
if e != nil {
|
|
req.RespondError(toError(e))
|
|
return
|
|
}
|
|
}
|
|
|
|
if dir.Name != "" {
|
|
fmt.Printf("Rename %s to %s\n", fid.path, dir.Name)
|
|
// if first char is / it is relative to root, else relative to
|
|
// cwd.
|
|
var destpath string
|
|
if dir.Name[0] == '/' {
|
|
destpath = path.Join(u.Root, dir.Name)
|
|
fmt.Printf("/ results in %s\n", destpath)
|
|
} else {
|
|
fiddir, _ := path.Split(fid.path)
|
|
destpath = path.Join(fiddir, dir.Name)
|
|
fmt.Printf("rel results in %s\n", destpath)
|
|
}
|
|
err := os.Rename(fid.path, destpath)
|
|
fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err)
|
|
if err != nil {
|
|
req.RespondError(toError(err))
|
|
return
|
|
}
|
|
fid.path = destpath
|
|
}
|
|
|
|
if dir.Length != 0xFFFFFFFFFFFFFFFF {
|
|
e := os.Truncate(fid.path, int64(dir.Length))
|
|
if e != nil {
|
|
req.RespondError(toError(e))
|
|
return
|
|
}
|
|
}
|
|
|
|
// If either mtime or atime need to be changed, then
|
|
// we must change both.
|
|
// if dir.Mtime != ^uint32(0) || dir.Atime != ^uint32(0) {
|
|
// mt, at := time.Unix(int64(dir.Mtime), 0), time.Unix(int64(dir.Atime), 0)
|
|
// if cmt, cat := (dir.Mtime == ^uint32(0)), (dir.Atime == ^uint32(0)); cmt || cat {
|
|
// st, e := os.Stat(fid.path)
|
|
// if e != nil {
|
|
// req.RespondError(toError(e))
|
|
// return
|
|
// }
|
|
// switch cmt {
|
|
// case true:
|
|
// mt = st.ModTime()
|
|
// default:
|
|
// //at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t))
|
|
// }
|
|
// }
|
|
// e := os.Chtimes(fid.path, at, mt)
|
|
// if e != nil {
|
|
// req.RespondError(toError(e))
|
|
// return
|
|
// }
|
|
// }
|
|
|
|
req.RespondRwstat()
|
|
}
|