summaryrefslogtreecommitdiff
path: root/src/pkg/os/file_plan9.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/os/file_plan9.go')
-rw-r--r--src/pkg/os/file_plan9.go95
1 files changed, 85 insertions, 10 deletions
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index 7b473f802..03792191e 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -9,6 +9,32 @@ import (
"syscall"
)
+// File represents an open file descriptor.
+type File struct {
+ fd int
+ name string
+ dirinfo *dirInfo // nil unless directory being read
+ nepipe int // number of consecutive EPIPE in Write
+}
+
+// Fd returns the integer Unix file descriptor referencing the open file.
+func (file *File) Fd() int {
+ if file == nil {
+ return -1
+ }
+ return file.fd
+}
+
+// NewFile returns a new File with the given file descriptor and name.
+func NewFile(fd int, name string) *File {
+ if fd < 0 {
+ return nil
+ }
+ f := &File{fd: fd, name: name}
+ runtime.SetFinalizer(f, (*File).Close)
+ return f
+}
+
// Auxiliary information if the File describes a directory
type dirInfo struct {
buf [syscall.STATMAX]byte // buffer for directory I/O
@@ -30,14 +56,43 @@ const DevNull = "/dev/null"
// methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
- var fd int
- var e syscall.Error
+ var (
+ fd int
+ e syscall.Error
+ create bool
+ excl bool
+ trunc bool
+ append bool
+ )
- syscall.ForkLock.RLock()
if flag&O_CREATE == O_CREATE {
- fd, e = syscall.Create(name, flag & ^O_CREATE, perm)
+ flag = flag & ^O_CREATE
+ create = true
+ }
+ if flag&O_EXCL == O_EXCL {
+ excl = true
+ }
+ if flag&O_TRUNC == O_TRUNC {
+ trunc = true
+ }
+ // O_APPEND is emulated on Plan 9
+ if flag&O_APPEND == O_APPEND {
+ flag = flag &^ O_APPEND
+ append = true
+ }
+
+ syscall.ForkLock.RLock()
+ if (create && trunc) || excl {
+ fd, e = syscall.Create(name, flag, perm)
} else {
fd, e = syscall.Open(name, flag)
+ if e != nil && create {
+ var e1 syscall.Error
+ fd, e1 = syscall.Create(name, flag, perm)
+ if e1 == nil {
+ e = nil
+ }
+ }
}
syscall.ForkLock.RUnlock()
@@ -45,6 +100,12 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
return nil, &PathError{"open", name, e}
}
+ if append {
+ if _, e = syscall.Seek(fd, 0, SEEK_END); e != nil {
+ return nil, &PathError{"seek", name, e}
+ }
+ }
+
return NewFile(fd, name), nil
}
@@ -69,8 +130,12 @@ func (file *File) Close() Error {
// Stat returns the FileInfo structure describing file.
// It returns the FileInfo and an error, if any.
-func (file *File) Stat() (fi *FileInfo, err Error) {
- return dirstat(file)
+func (f *File) Stat() (fi *FileInfo, err Error) {
+ d, err := dirstat(f)
+ if iserror(err) {
+ return nil, err
+ }
+ return fileInfoFromStat(new(FileInfo), d), err
}
// Truncate changes the size of the file.
@@ -90,10 +155,15 @@ func (f *File) Truncate(size int64) Error {
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error {
var d Dir
- d.Null()
+ var mask = ^uint32(0777)
- d.Mode = mode & 0777
+ d.Null()
+ odir, e := dirstat(f)
+ if iserror(e) {
+ return &PathError{"chmod", f.name, e}
+ }
+ d.Mode = (odir.Mode & mask) | (mode &^ mask)
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", f.name, e}
}
@@ -188,10 +258,15 @@ func Rename(oldname, newname string) Error {
// Chmod changes the mode of the named file to mode.
func Chmod(name string, mode uint32) Error {
var d Dir
- d.Null()
+ var mask = ^uint32(0777)
- d.Mode = mode & 0777
+ d.Null()
+ odir, e := dirstat(name)
+ if iserror(e) {
+ return &PathError{"chmod", name, e}
+ }
+ d.Mode = (odir.Mode & mask) | (mode &^ mask)
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", name, e}
}