lib9p

Go 9P library.
Log | Files | Refs | LICENSE

stat_plan9.go (2952B)


      1 //go:build plan9
      2 
      3 package diskfs
      4 
      5 import (
      6 	"fmt"
      7 	"io/fs"
      8 	"os"
      9 	"os/user"
     10 	"path"
     11 	"strconv"
     12 	"syscall"
     13 	"time"
     14 
     15 	"git.mtkn.jp/lib9p"
     16 )
     17 
     18 // fiStat generates lib9p.Stat from the FileInfo.
     19 // It requires QidPool and fileID to fill the Qid field of Stat.
     20 func fiStat(pool *QidPool, id fileID, info fs.FileInfo) (*lib9p.Stat, error) {
     21 	dir := info.Sys().(*syscall.Dir)
     22 	qid := lib9p.Qid{
     23 		Type: lib9p.QidType(dir.Qid.Type),
     24 		Vers: dir.Qid.Vers,
     25 		Path: dir.Qid.Path,
     26 	}
     27 	return &lib9p.Stat{
     28 		Type:   dir.Type,
     29 		Dev:    dir.Dev,
     30 		Qid:    qid,
     31 		Mode:   info.Mode(),
     32 		Atime:  dir.Atime,
     33 		Mtime:  dir.Mtime,
     34 		Length: dir.Length,
     35 		Name:   dir.Name,
     36 		Uid:    dir.Uid,
     37 		Gid:    dir.Gid,
     38 		Muid:   dir.Muid,
     39 	}, nil
     40 }
     41 
     42 // Stat is real implementation of File.Stat.
     43 func (f *File) stat() (*lib9p.FileInfo, error) {
     44 	fi, err := f.file.Stat()
     45 	if err != nil {
     46 		return nil, fmt.Errorf("stat: %v", err)
     47 	}
     48 	stat, err := fiStat(nil, fileID{}, fi)
     49 	if err != nil {
     50 		return nil, fmt.Errorf("fiStat: %v", err)
     51 	}
     52 	return &lib9p.FileInfo{Stat: *stat}, nil
     53 }
     54 
     55 // wstat is the real implementation of File.WStat.
     56 // TODO: when error occurs, file stat should be restored.
     57 func (f *File) wstat(s *lib9p.Stat) error {
     58 	file, err := os.OpenFile(path.Join(f.fs.rootPath, f.path), os.O_RDWR, 0)
     59 	if err != nil {
     60 		return err
     61 	}
     62 	defer file.Close()
     63 
     64 	fi, err := f.Stat()
     65 	if err != nil {
     66 		return fmt.Errorf("stat: %v", err)
     67 	}
     68 
     69 	oldStat := fi.Sys().(*lib9p.Stat)
     70 
     71 	if s.Name != oldStat.Name {
     72 		// TODO: check neither Names contains "/"
     73 		oldpath := path.Join(f.fs.rootPath, path.Dir(f.path), oldStat.Name)
     74 		newpath := path.Join(f.fs.rootPath, path.Dir(f.path), s.Name)
     75 		if err := os.Rename(oldpath, newpath); err != nil {
     76 			return fmt.Errorf("rename: %v", err)
     77 		}
     78 	}
     79 	if s.Length != oldStat.Length {
     80 		if err := file.Truncate(s.Length); err != nil {
     81 			return fmt.Errorf("truncate: %v", err)
     82 		}
     83 		ret, err := file.Seek(0, 0)
     84 		if err != nil {
     85 			return fmt.Errorf("seek 0: %d, %w", ret, err)
     86 		}
     87 	}
     88 	if s.Mode != oldStat.Mode {
     89 		if err := file.Chmod(s.Mode); err != nil {
     90 			return fmt.Errorf("chmod: %v", err)
     91 		}
     92 	}
     93 	if s.Mtime != oldStat.Mtime {
     94 		err := os.Chtimes(f.path, time.Time{}, time.Unix(int64(s.Mtime), 0))
     95 		if err != nil {
     96 			return fmt.Errorf("chtimes: %v", err)
     97 		}
     98 	}
     99 
    100 	if s.Gid != oldStat.Gid {
    101 		return fmt.Errorf("not implemented in plan9")
    102 		group, err := user.LookupGroup(s.Gid)
    103 		if err != nil {
    104 			return fmt.Errorf("lookupgroup: %v", err)
    105 		}
    106 		usr, err := user.Lookup(oldStat.Uid)
    107 		if err != nil {
    108 			return fmt.Errorf("lookup user: %v", err)
    109 		}
    110 		u, err := strconv.Atoi(usr.Uid)
    111 		if err != nil {
    112 			return fmt.Errorf("convert uid: %v", err)
    113 		}
    114 		g, err := strconv.Atoi(group.Gid)
    115 		if err != nil {
    116 			return fmt.Errorf("convert gid: %v", err)
    117 		}
    118 
    119 		if err := file.Chown(u, g); err != nil {
    120 			return fmt.Errorf("chown: %v", err)
    121 		}
    122 	}
    123 
    124 	return nil
    125 }
    126 
    127 // TODO: implement
    128 func chown(ospath, uid, gid string) error { return nil }