From 216594102622db628b8b38038e6ae93884b052e4 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Thu, 27 Jun 2024 02:28:18 +0800 Subject: [PATCH] patch: os.File --- README.md | 4 + internal/lib/fmt/print.go | 248 +++++++++++++++++++--------------- internal/lib/os/file.go | 50 ++++--- internal/lib/os/file_posix.go | 243 +++++++++++++++++++++++++++++++++ internal/lib/os/os.go | 37 +++++ internal/lib/os/types.go | 25 +++- 6 files changed, 474 insertions(+), 133 deletions(-) create mode 100644 internal/lib/os/file_posix.go diff --git a/README.md b/README.md index 56593341..320afeab 100644 --- a/README.md +++ b/README.md @@ -213,8 +213,12 @@ Here are the Go packages that can be imported correctly: * [sync/atomic](https://pkg.go.dev/sync/atomic) * [sync](https://pkg.go.dev/sync) (partially) * [syscall](https://pkg.go.dev/syscall) (partially) +* [errors](https://pkg.go.dev/errors) (partially) +* [io](https://pkg.go.dev/io) (partially) +* [io/fs](https://pkg.go.dev/io/fs) (partially) * [os](https://pkg.go.dev/os) (partially) * [reflect](https://pkg.go.dev/reflect) (partially) +* [time](https://pkg.go.dev/time) (partially) ## Dependencies diff --git a/internal/lib/fmt/print.go b/internal/lib/fmt/print.go index 562a1450..7ab33145 100644 --- a/internal/lib/fmt/print.go +++ b/internal/lib/fmt/print.go @@ -7,9 +7,6 @@ package fmt import ( "io" "os" - "reflect" - "strconv" - "sync" "unicode/utf8" ) @@ -32,6 +29,7 @@ const ( invReflectString = "" ) +/* TODO(xsw): // State represents the printer state passed to custom formatters. // It provides access to the io.Writer interface plus information about // the flags and options for the operand's format specifier. @@ -53,6 +51,7 @@ type State interface { type Formatter interface { Format(f State, verb rune) } +*/ // Stringer is implemented by any value that has a String method, // which defines the “native” format for that value. @@ -71,6 +70,7 @@ type GoStringer interface { GoString() string } +/* TODO(xsw): // FormatString returns a string representing the fully qualified formatting // directive captured by the State, followed by the argument verb. (State does not // itself contain the verb.) The result has a leading percent sign followed by any @@ -95,6 +95,7 @@ func FormatString(state State, verb rune) string { b = utf8.AppendRune(b, verb) return string(b) } +*/ // Use simple []byte instead of bytes.Buffer to avoid large dependency. type buffer []byte @@ -123,7 +124,8 @@ type pp struct { arg any // value is used instead of arg for reflect values. - value reflect.Value + // TODO(xsw): + // value reflect.Value // fmt is used to format basic items such as integers or strings. fmt fmt @@ -142,13 +144,17 @@ type pp struct { wrappedErrs []int } +/* TODO(xsw): var ppFree = sync.Pool{ New: func() any { return new(pp) }, } +*/ // newPrinter allocates a new pp struct or grabs a cached one. func newPrinter() *pp { - p := ppFree.Get().(*pp) + // TODO(xsw): + // p := ppFree.Get().(*pp) + p := &pp{} p.panicking = false p.erroring = false p.wrapErrs = false @@ -175,9 +181,11 @@ func (p *pp) free() { } p.arg = nil - p.value = reflect.Value{} + // TODO(xsw): + // p.value = reflect.Value{} p.wrappedErrs = p.wrappedErrs[:0] - ppFree.Put(p) + // TODO(xsw): + // ppFree.Put(p) } func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent } @@ -214,6 +222,7 @@ func (p *pp) WriteString(s string) (ret int, err error) { return len(s), nil } +/* TODO(xsw): // These routines end in 'f' and take a format string. // Fprintf formats according to a format specifier and writes to w. @@ -250,6 +259,7 @@ func Appendf(b []byte, format string, a ...any) []byte { p.free() return b } +*/ // These routines do not take a format string @@ -334,6 +344,7 @@ func Appendln(b []byte, a ...any) []byte { return b } +/* TODO(xsw): // getField gets the i'th field of the struct value. // If the field is itself is an interface, return a value for // the thing inside the interface, not the interface itself. @@ -376,28 +387,33 @@ func (p *pp) unknownType(v reflect.Value) { p.buf.writeString(v.Type().String()) p.buf.writeByte('?') } +*/ func (p *pp) badVerb(verb rune) { - p.erroring = true - p.buf.writeString(percentBangString) - p.buf.writeRune(verb) - p.buf.writeByte('(') - switch { - case p.arg != nil: - p.buf.writeString(reflect.TypeOf(p.arg).String()) - p.buf.writeByte('=') - p.printArg(p.arg, 'v') - case p.value.IsValid(): - p.buf.writeString(p.value.Type().String()) - p.buf.writeByte('=') - p.printValue(p.value, 'v', 0) - default: - p.buf.writeString(nilAngleString) - } - p.buf.writeByte(')') - p.erroring = false + /* + p.erroring = true + p.buf.writeString(percentBangString) + p.buf.writeRune(verb) + p.buf.writeByte('(') + switch { + case p.arg != nil: + p.buf.writeString(reflect.TypeOf(p.arg).String()) + p.buf.writeByte('=') + p.printArg(p.arg, 'v') + case p.value.IsValid(): + p.buf.writeString(p.value.Type().String()) + p.buf.writeByte('=') + p.printValue(p.value, 'v', 0) + default: + p.buf.writeString(nilAngleString) + } + p.buf.writeByte(')') + p.erroring = false + */ + panic("todo: fmt.(*pp).badVerb") } +/* TODO(xsw): func (p *pp) fmtBool(v bool, verb rune) { switch verb { case 't', 'v': @@ -483,6 +499,7 @@ func (p *pp) fmtComplex(v complex128, size int, verb rune) { p.badVerb(verb) } } +*/ func (p *pp) fmtString(v string, verb rune) { switch verb { @@ -505,6 +522,7 @@ func (p *pp) fmtString(v string, verb rune) { } } +/* TODO(xsw): func (p *pp) fmtBytes(v []byte, verb rune, typeString string) { switch verb { case 'v', 'd': @@ -541,10 +559,12 @@ func (p *pp) fmtBytes(v []byte, verb rune, typeString string) { case 'q': p.fmt.fmtQ(string(v)) default: - p.printValue(reflect.ValueOf(v), verb, 0) + // p.printValue(reflect.ValueOf(v), verb, 0) + panic("todo: fmt.(*pp).fmtBytes") } } +/* TODO(xsw): func (p *pp) fmtPointer(value reflect.Value, verb rune) { var u uintptr switch value.Kind() { @@ -676,10 +696,12 @@ func (p *pp) handleMethods(verb rune) (handled bool) { } return false } +*/ func (p *pp) printArg(arg any, verb rune) { p.arg = arg - p.value = reflect.Value{} + // TODO(xsw): + // p.value = reflect.Value{} if arg == nil { switch verb { @@ -695,49 +717,54 @@ func (p *pp) printArg(arg any, verb rune) { // %T (the value's type) and %p (its address) are special; we always do them first. switch verb { case 'T': - p.fmt.fmtS(reflect.TypeOf(arg).String()) - return + // p.fmt.fmtS(reflect.TypeOf(arg).String()) + // return + panic("todo: fmt.(*pp).printArg") case 'p': - p.fmtPointer(reflect.ValueOf(arg), 'p') - return + // p.fmtPointer(reflect.ValueOf(arg), 'p') + // return + panic("todo: fmt.(*pp).printArg") } // Some types can be done without reflection. switch f := arg.(type) { - case bool: - p.fmtBool(f, verb) - case float32: - p.fmtFloat(float64(f), 32, verb) - case float64: - p.fmtFloat(f, 64, verb) - case complex64: - p.fmtComplex(complex128(f), 64, verb) - case complex128: - p.fmtComplex(f, 128, verb) - case int: - p.fmtInteger(uint64(f), signed, verb) - case int8: - p.fmtInteger(uint64(f), signed, verb) - case int16: - p.fmtInteger(uint64(f), signed, verb) - case int32: - p.fmtInteger(uint64(f), signed, verb) - case int64: - p.fmtInteger(uint64(f), signed, verb) - case uint: - p.fmtInteger(uint64(f), unsigned, verb) - case uint8: - p.fmtInteger(uint64(f), unsigned, verb) - case uint16: - p.fmtInteger(uint64(f), unsigned, verb) - case uint32: - p.fmtInteger(uint64(f), unsigned, verb) - case uint64: - p.fmtInteger(f, unsigned, verb) - case uintptr: - p.fmtInteger(uint64(f), unsigned, verb) + /* + case bool: + p.fmtBool(f, verb) + case float32: + p.fmtFloat(float64(f), 32, verb) + case float64: + p.fmtFloat(f, 64, verb) + case complex64: + p.fmtComplex(complex128(f), 64, verb) + case complex128: + p.fmtComplex(f, 128, verb) + case int: + p.fmtInteger(uint64(f), signed, verb) + case int8: + p.fmtInteger(uint64(f), signed, verb) + case int16: + p.fmtInteger(uint64(f), signed, verb) + case int32: + p.fmtInteger(uint64(f), signed, verb) + case int64: + p.fmtInteger(uint64(f), signed, verb) + case uint: + p.fmtInteger(uint64(f), unsigned, verb) + case uint8: + p.fmtInteger(uint64(f), unsigned, verb) + case uint16: + p.fmtInteger(uint64(f), unsigned, verb) + case uint32: + p.fmtInteger(uint64(f), unsigned, verb) + case uint64: + p.fmtInteger(f, unsigned, verb) + case uintptr: + p.fmtInteger(uint64(f), unsigned, verb) + */ case string: p.fmtString(f, verb) + /* TODO(xsw): case []byte: p.fmtBytes(f, verb, "[]byte") case reflect.Value: @@ -750,16 +777,21 @@ func (p *pp) printArg(arg any, verb rune) { } } p.printValue(f, verb, 0) + */ default: - // If the type is not simple, it might have methods. - if !p.handleMethods(verb) { - // Need to use reflection, since the type had no - // interface methods that could be used for formatting. - p.printValue(reflect.ValueOf(f), verb, 0) - } + /* + // If the type is not simple, it might have methods. + if !p.handleMethods(verb) { + // Need to use reflection, since the type had no + // interface methods that could be used for formatting. + p.printValue(reflect.ValueOf(f), verb, 0) + } + */ + panic("todo: fmt.(*pp).printArg") } } +/* // printValue is similar to printArg but starts with a reflect value, not an interface{} value. // It does not handle 'p' and 'T' verbs because these should have been already handled by printArg. func (p *pp) printValue(value reflect.Value, verb rune, depth int) { @@ -802,37 +834,34 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { case reflect.String: p.fmtString(f.String(), verb) case reflect.Map: - /* - if p.fmt.sharpV { - p.buf.writeString(f.Type().String()) - if f.IsNil() { - p.buf.writeString(nilParenString) - return + if p.fmt.sharpV { + p.buf.writeString(f.Type().String()) + if f.IsNil() { + p.buf.writeString(nilParenString) + return + } + p.buf.writeByte('{') + } else { + p.buf.writeString(mapString) + } + sorted := fmtsort.Sort(f) + for i, key := range sorted.Key { + if i > 0 { + if p.fmt.sharpV { + p.buf.writeString(commaSpaceString) + } else { + p.buf.writeByte(' ') } - p.buf.writeByte('{') - } else { - p.buf.writeString(mapString) } - sorted := fmtsort.Sort(f) - for i, key := range sorted.Key { - if i > 0 { - if p.fmt.sharpV { - p.buf.writeString(commaSpaceString) - } else { - p.buf.writeByte(' ') - } - } - p.printValue(key, verb, depth+1) - p.buf.writeByte(':') - p.printValue(sorted.Value[i], verb, depth+1) - } - if p.fmt.sharpV { - p.buf.writeByte('}') - } else { - p.buf.writeByte(']') - } - */ - panic("todo") + p.printValue(key, verb, depth+1) + p.buf.writeByte(':') + p.printValue(sorted.Value[i], verb, depth+1) + } + if p.fmt.sharpV { + p.buf.writeByte('}') + } else { + p.buf.writeByte(']') + } case reflect.Struct: if p.fmt.sharpV { p.buf.writeString(f.Type().String()) @@ -934,6 +963,7 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { } } +/* TODO(xsw): // intFromArg gets the argNumth element of a. On return, isInt reports whether the argument has integer type. func intFromArg(a []any, argNum int) (num int, isInt bool, newArgNum int) { newArgNum = argNum @@ -1201,18 +1231,22 @@ formatLoop: p.buf.writeByte(')') } } +*/ func (p *pp) doPrint(a []any) { - prevString := false - for argNum, arg := range a { - isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String - // Add a space between two non-string arguments. - if argNum > 0 && !isString && !prevString { - p.buf.writeByte(' ') + /* + prevString := false + for argNum, arg := range a { + isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String + // Add a space between two non-string arguments. + if argNum > 0 && !isString && !prevString { + p.buf.writeByte(' ') + } + p.printArg(arg, 'v') + prevString = isString } - p.printArg(arg, 'v') - prevString = isString - } + */ + panic("todo: fmt.(*pp).doPrint") } // doPrintln is like doPrint but always adds a space between arguments diff --git a/internal/lib/os/file.go b/internal/lib/os/file.go index 7a3ab586..5bb2ec29 100644 --- a/internal/lib/os/file.go +++ b/internal/lib/os/file.go @@ -8,6 +8,7 @@ import ( "errors" "io" "syscall" + "time" ) // Name returns the name of the file as presented to Open. @@ -172,36 +173,42 @@ func (f *File) WriteAt(b []byte, off int64) (n int, err error) { } return */ - panic("todo") + panic("todo: os.(*File).WriteAt") } -/* // Seek sets the offset for the next Read or Write on file to offset, interpreted // according to whence: 0 means relative to the origin of the file, 1 means // relative to the current offset, and 2 means relative to the end. // It returns the new offset and an error, if any. // The behavior of Seek on a file opened with O_APPEND is not specified. func (f *File) Seek(offset int64, whence int) (ret int64, err error) { - if err := f.checkValid("seek"); err != nil { - return 0, err - } - r, e := f.seek(offset, whence) - if e == nil && f.dirinfo != nil && r != 0 { - e = syscall.EISDIR - } - if e != nil { - return 0, f.wrapErr("seek", e) - } - return r, nil + /* + if err := f.checkValid("seek"); err != nil { + return 0, err + } + r, e := f.seek(offset, whence) + if e == nil && f.dirinfo != nil && r != 0 { + e = syscall.EISDIR + } + if e != nil { + return 0, f.wrapErr("seek", e) + } + return r, nil + */ + panic("todo: os.(*File).Seek") } // WriteString is like Write, but writes the contents of string s rather than // a slice of bytes. func (f *File) WriteString(s string) (n int, err error) { - b := unsafe.Slice(unsafe.StringData(s), len(s)) - return f.Write(b) + /* + b := unsafe.Slice(unsafe.StringData(s), len(s)) + return f.Write(b) + */ + panic("todo: os.(*File).WriteString") } +/* // setStickyBit adds ModeSticky to the permission bits of path, non atomic. func setStickyBit(name string) error { fi, err := Stat(name) @@ -293,6 +300,7 @@ func (f *File) wrapErr(op string, err error) error { func TempDir() string { return tempDir() } +*/ // Chmod changes the mode of the file to mode. // If there is an error, it will be of type *PathError. @@ -347,12 +355,16 @@ func (f *File) SetWriteDeadline(t time.Time) error { // SyscallConn returns a raw file. // This implements the syscall.Conn interface. func (f *File) SyscallConn() (syscall.RawConn, error) { - if err := f.checkValid("SyscallConn"); err != nil { - return nil, err - } - return newRawConn(f) + /* + if err := f.checkValid("SyscallConn"); err != nil { + return nil, err + } + return newRawConn(f) + */ + panic("todo: os.(*File).SyscallConn") } +/* TODO(xsw): // DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir. // // Note that DirFS("/prefix") only guarantees that the Open calls it makes to the diff --git a/internal/lib/os/file_posix.go b/internal/lib/os/file_posix.go new file mode 100644 index 00000000..7877a6aa --- /dev/null +++ b/internal/lib/os/file_posix.go @@ -0,0 +1,243 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix || (js && wasm) || wasip1 || windows + +package os + +import ( + "syscall" + "time" +) + +// Close closes the File, rendering it unusable for I/O. +// On files that support SetDeadline, any pending I/O operations will +// be canceled and return immediately with an ErrClosed error. +// Close will return an error if it has already been called. +func (f *File) Close() error { + /* + if f == nil { + return ErrInvalid + } + return f.file.close() + */ + panic("todo: os.(*File).Close") +} + +// pread reads len(b) bytes from the File starting at byte offset off. +// It returns the number of bytes read and the error, if any. +// EOF is signaled by a zero count with err set to nil. +func (f *File) pread(b []byte, off int64) (n int, err error) { + /* + n, err = f.pfd.Pread(b, off) + runtime.KeepAlive(f) + return n, err + */ + panic("todo: os.(*File).pread") +} + +// pwrite writes len(b) bytes to the File starting at byte offset off. +// It returns the number of bytes written and an error, if any. +func (f *File) pwrite(b []byte, off int64) (n int, err error) { + /* + n, err = f.pfd.Pwrite(b, off) + runtime.KeepAlive(f) + return n, err + */ + panic("todo: os.(*File).pwrite") +} + +/* +// syscallMode returns the syscall-specific mode bits from Go's portable mode bits. +func syscallMode(i FileMode) (o uint32) { + o |= uint32(i.Perm()) + if i&ModeSetuid != 0 { + o |= syscall.S_ISUID + } + if i&ModeSetgid != 0 { + o |= syscall.S_ISGID + } + if i&ModeSticky != 0 { + o |= syscall.S_ISVTX + } + // No mapping for Go's ModeTemporary (plan9 only). + return +} + +// See docs in file.go:Chmod. +func chmod(name string, mode FileMode) error { + longName := fixLongPath(name) + e := ignoringEINTR(func() error { + return syscall.Chmod(longName, syscallMode(mode)) + }) + if e != nil { + return &PathError{Op: "chmod", Path: name, Err: e} + } + return nil +} +*/ + +// See docs in file.go:(*File).Chmod. +func (f *File) chmod(mode FileMode) error { + /* + if err := f.checkValid("chmod"); err != nil { + return err + } + if e := f.pfd.Fchmod(syscallMode(mode)); e != nil { + return f.wrapErr("chmod", e) + } + return nil + */ + panic("todo: os.(*File).chmod") +} + +// Chown changes the numeric uid and gid of the named file. +// If there is an error, it will be of type *PathError. +// +// On Windows, it always returns the syscall.EWINDOWS error, wrapped +// in *PathError. +func (f *File) Chown(uid, gid int) error { + /* + if err := f.checkValid("chown"); err != nil { + return err + } + if e := f.pfd.Fchown(uid, gid); e != nil { + return f.wrapErr("chown", e) + } + return nil + */ + panic("todo: os.(*File).Chown") +} + +// Truncate changes the size of the file. +// It does not change the I/O offset. +// If there is an error, it will be of type *PathError. +func (f *File) Truncate(size int64) error { + /* + if err := f.checkValid("truncate"); err != nil { + return err + } + if e := f.pfd.Ftruncate(size); e != nil { + return f.wrapErr("truncate", e) + } + return nil + */ + panic("todo: os.(*File).Truncate") +} + +// Sync commits the current contents of the file to stable storage. +// Typically, this means flushing the file system's in-memory copy +// of recently written data to disk. +func (f *File) Sync() error { + /* + if err := f.checkValid("sync"); err != nil { + return err + } + if e := f.pfd.Fsync(); e != nil { + return f.wrapErr("sync", e) + } + return nil + */ + panic("todo: os.(*File).Sync") +} + +/* +// Chtimes changes the access and modification times of the named +// file, similar to the Unix utime() or utimes() functions. +// A zero time.Time value will leave the corresponding file time unchanged. +// +// The underlying filesystem may truncate or round the values to a +// less precise time unit. +// If there is an error, it will be of type *PathError. +func Chtimes(name string, atime time.Time, mtime time.Time) error { + var utimes [2]syscall.Timespec + set := func(i int, t time.Time) { + if t.IsZero() { + utimes[i] = syscall.Timespec{Sec: _UTIME_OMIT, Nsec: _UTIME_OMIT} + } else { + utimes[i] = syscall.NsecToTimespec(t.UnixNano()) + } + } + set(0, atime) + set(1, mtime) + if e := syscall.UtimesNano(fixLongPath(name), utimes[0:]); e != nil { + return &PathError{Op: "chtimes", Path: name, Err: e} + } + return nil +} +*/ + +// Chdir changes the current working directory to the file, +// which must be a directory. +// If there is an error, it will be of type *PathError. +func (f *File) Chdir() error { + /* + if err := f.checkValid("chdir"); err != nil { + return err + } + if e := f.pfd.Fchdir(); e != nil { + return f.wrapErr("chdir", e) + } + return nil + */ + panic("todo: os.(*File).Chdir") +} + +// setDeadline sets the read and write deadline. +func (f *File) setDeadline(t time.Time) error { + /* + if err := f.checkValid("SetDeadline"); err != nil { + return err + } + return f.pfd.SetDeadline(t) + */ + panic("todo: os.(*File).setDeadline") +} + +// setReadDeadline sets the read deadline. +func (f *File) setReadDeadline(t time.Time) error { + /* + if err := f.checkValid("SetReadDeadline"); err != nil { + return err + } + return f.pfd.SetReadDeadline(t) + */ + panic("todo: os.(*File).setReadDeadline") +} + +// setWriteDeadline sets the write deadline. +func (f *File) setWriteDeadline(t time.Time) error { + /* + if err := f.checkValid("SetWriteDeadline"); err != nil { + return err + } + return f.pfd.SetWriteDeadline(t) + */ + panic("todo: os.(*File).setWriteDeadline") +} + +// checkValid checks whether f is valid for use. +// If not, it returns an appropriate error, perhaps incorporating the operation name op. +func (f *File) checkValid(op string) error { + if f == nil { + return ErrInvalid + } + return nil +} + +// ignoringEINTR makes a function call and repeats it if it returns an +// EINTR error. This appears to be required even though we install all +// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846. +// Also #20400 and #36644 are issues in which a signal handler is +// installed without setting SA_RESTART. None of these are the common case, +// but there are enough of them that it seems that we can't avoid +// an EINTR loop. +func ignoringEINTR(fn func() error) error { + for { + err := fn() + if err != syscall.EINTR { + return err + } + } +} diff --git a/internal/lib/os/os.go b/internal/lib/os/os.go index 553eff49..5bb4c9c0 100644 --- a/internal/lib/os/os.go +++ b/internal/lib/os/os.go @@ -120,6 +120,25 @@ func Chown(name string, uid, gid int) error { return toPathErr("chown", name, ret) } +/* TODO(xsw): +// Chown changes the numeric uid and gid of the named file. +// If the file is a symbolic link, it changes the uid and gid of the link's target. +// A uid or gid of -1 means to not change that value. +// If there is an error, it will be of type *PathError. +// +// On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or +// EPLAN9 error, wrapped in *PathError. +func Chown(name string, uid, gid int) error { + e := ignoringEINTR(func() error { + return syscall.Chown(name, uid, gid) + }) + if e != nil { + return &PathError{Op: "chown", Path: name, Err: e} + } + return nil +} +*/ + // TODO(xsw): // func Chtimes(name string, atime time.Time, mtime time.Time) error @@ -195,6 +214,24 @@ func Lchown(name string, uid, gid int) error { return toPathErr("lchown", name, ret) } +/* TODO(xsw): +// Lchown changes the numeric uid and gid of the named file. +// If the file is a symbolic link, it changes the uid and gid of the link itself. +// If there is an error, it will be of type *PathError. +// +// On Windows, it always returns the syscall.EWINDOWS error, wrapped +// in *PathError. +func Lchown(name string, uid, gid int) error { + e := ignoringEINTR(func() error { + return syscall.Lchown(name, uid, gid) + }) + if e != nil { + return &PathError{Op: "lchown", Path: name, Err: e} + } + return nil +} +*/ + func Link(oldname, newname string) error { ret := os.Link(c.AllocaCStr(oldname), c.AllocaCStr(newname)) if ret == 0 { diff --git a/internal/lib/os/types.go b/internal/lib/os/types.go index cfce32b0..5c311568 100644 --- a/internal/lib/os/types.go +++ b/internal/lib/os/types.go @@ -47,6 +47,16 @@ func (f *File) write(b []byte) (int, error) { return 0, syscall.Errno(os.Errno) } +/* TODO(xsw): +// write writes len(b) bytes to the File. +// It returns the number of bytes written and an error, if any. +func (f *File) write(b []byte) (n int, err error) { + n, err = f.pfd.Write(b) + runtime.KeepAlive(f) + return n, err +} +*/ + // read reads up to len(b) bytes from the File. // It returns the number of bytes read and an error, if any. func (f *File) read(b []byte) (int, error) { @@ -60,14 +70,15 @@ func (f *File) read(b []byte) (int, error) { return 0, syscall.Errno(os.Errno) } -// checkValid checks whether f is valid for use. -// If not, it returns an appropriate error, perhaps incorporating the operation name op. -func (f *File) checkValid(op string) error { - if f == nil { - return ErrInvalid - } - return nil +/* TODO(xsw): +// read reads up to len(b) bytes from the File. +// It returns the number of bytes read and an error, if any. +func (f *File) read(b []byte) (n int, err error) { + n, err = f.pfd.Read(b) + runtime.KeepAlive(f) + return n, err } +*/ // A FileInfo describes a file and is returned by Stat and Lstat. type FileInfo = fs.FileInfo