Skip to content

Commit

Permalink
chmod
Browse files Browse the repository at this point in the history
  • Loading branch information
gjenkins8 committed Jan 19, 2025
1 parent 5298379 commit 8aa62f5
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/tinygo-org/tinygo

go 1.19
go 1.23

require (
github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c
Expand Down
24 changes: 24 additions & 0 deletions src/os/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package os

import (
"errors"
"internal/poll"
"io"
"io/fs"
"runtime"
Expand Down Expand Up @@ -61,6 +62,25 @@ func fixCount(n int, err error) (int, error) {
return n, err
}

// checkWrapErr is the test hook to enable checking unexpected wrapped errors of poll.ErrFileClosing.
// It is set to true in the export_test.go for tests (including fuzz tests).
var checkWrapErr = false

// wrapErr wraps an error that occurred during an operation on an open file.
// It passes io.EOF through unchanged, otherwise converts
// poll.ErrFileClosing to ErrClosed and wraps the error in a PathError.
func (f *File) wrapErr(op string, err error) error {
if err == nil || err == io.EOF {
return err
}
if err == poll.ErrFileClosing {
err = ErrClosed
} else if checkWrapErr && errors.Is(err, poll.ErrFileClosing) {
panic("unexpected error wrapping poll.ErrFileClosing: " + err.Error())
}
return &PathError{Op: op, Path: f.name, Err: err}
}

// Remove removes a file or (empty) directory. If the operation fails, it will
// return an error of type *PathError.
func Remove(path string) error {
Expand Down Expand Up @@ -257,6 +277,10 @@ func (f *File) SyscallConn() (conn syscall.RawConn, err error) {
return
}

// Chmod changes the mode of the file to mode.
// If there is an error, it will be of type *PathError.
func (f *File) Chmod(mode FileMode) error { return f.chmod(mode) }

// SetDeadline sets the read and write deadlines for a File.
// Calls to SetDeadline for files that do not support deadlines will return ErrNoDeadline
// This stub always returns ErrNoDeadline.
Expand Down
20 changes: 20 additions & 0 deletions src/os/file_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,23 @@ func (f *File) setWriteDeadline(t time.Time) error {
}
return ErrNotImplemented
}

// 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
}

// 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(_ string) error {
if f == nil {
return ErrInvalid
}
return nil
}
2 changes: 2 additions & 0 deletions src/os/file_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package os

import (
"internal/poll"
"io"
"syscall"
_ "unsafe"
Expand Down Expand Up @@ -42,6 +43,7 @@ type file struct {
name string
dirinfo *dirInfo // nil unless directory being read
appendMode bool
pfd poll.FD
}

func (f *file) close() (err error) {
Expand Down
123 changes: 123 additions & 0 deletions src/syscall/tables_wasip1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2023 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 wasip1

package syscall

import "runtime"

// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
var errorstr = [...]string{
E2BIG: "Argument list too long",
EACCES: "Permission denied",
EADDRINUSE: "Address already in use",
EADDRNOTAVAIL: "Address not available",
EAFNOSUPPORT: "Address family not supported by protocol family",
EAGAIN: "Try again",
EALREADY: "Socket already connected",
EBADF: "Bad file number",
//EBADFD: "file descriptor in bad state",
EBADMSG: "Trying to read unreadable message",
EBUSY: "Device or resource busy",
ECANCELED: "Operation canceled.",
ECHILD: "No child processes",
ECONNABORTED: "Connection aborted",
ECONNREFUSED: "Connection refused",
ECONNRESET: "Connection reset by peer",
EDEADLK: "Deadlock condition",
EDESTADDRREQ: "Destination address required",
EDOM: "Math arg out of domain of func",
EDQUOT: "Quota exceeded",
EEXIST: "File exists",
EFAULT: "Bad address",
EFBIG: "File too large",
EHOSTUNREACH: "Host is unreachable",
EIDRM: "Identifier removed",
EILSEQ: "EILSEQ",
EINPROGRESS: "Connection already in progress",
EINTR: "Interrupted system call",
EINVAL: "Invalid argument",
EIO: "I/O error",
EISCONN: "Socket is already connected",
EISDIR: "Is a directory",
ELOOP: "Too many symbolic links",
EMFILE: "Too many open files",
EMLINK: "Too many links",
EMSGSIZE: "Message too long",
EMULTIHOP: "Multihop attempted",
ENAMETOOLONG: "File name too long",
ENETDOWN: "Network interface is not configured",
ENETRESET: "Network dropped connection on reset",
ENETUNREACH: "Network is unreachable",
ENFILE: "File table overflow",
ENOBUFS: "No buffer space available",
ENODEV: "No such device",
ENOENT: "No such file or directory",
ENOEXEC: "Exec format error",
ENOLCK: "No record locks available",
ENOLINK: "The link has been severed",
ENOMEM: "Out of memory",
ENOMSG: "No message of desired type",
ENOPROTOOPT: "Protocol not available",
ENOSPC: "No space left on device",
ENOSYS: "Not implemented on " + runtime.GOOS,
ENOTCONN: "Socket is not connected",
ENOTDIR: "Not a directory",
ENOTEMPTY: "Directory not empty",
ENOTRECOVERABLE: "State not recoverable",
ENOTSOCK: "Socket operation on non-socket",
ENOTSUP: "Not supported",
ENOTTY: "Not a typewriter",
ENXIO: "No such device or address",
EOVERFLOW: "Value too large for defined data type",
//EOWNERDEAD: "Owner died",
EPERM: "Operation not permitted",
EPIPE: "Broken pipe",
EPROTO: "Protocol error",
EPROTONOSUPPORT: "Unknown protocol",
EPROTOTYPE: "Protocol wrong type for socket",
ERANGE: "Math result not representable",
EROFS: "Read-only file system",
ESPIPE: "Illegal seek",
ESRCH: "No such process",
ESTALE: "Stale file handle",
ETIMEDOUT: "Connection timed out",
ETXTBSY: "Text file busy",
EXDEV: "Cross-device link",
ENOTCAPABLE: "Capabilities insufficient",
}

// Do the interface allocations only once for common
// Errno values.
var (
errEAGAIN error = EAGAIN
errEINVAL error = EINVAL
errENOENT error = ENOENT
)

// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
//
// We set both noinline and nosplit to reduce code size, this function has many
// call sites in the syscall package, inlining it causes a significant increase
// of the compiled code; the function call ultimately does not make a difference
// in the performance of syscall functions since the time is dominated by calls
// to the imports and path resolution.
//
//go:noinline
//go:nosplit
func errnoErr(e Errno) error {
switch e {
case 0:
return nil
case EAGAIN:
return errEAGAIN
case EINVAL:
return errEINVAL
case ENOENT:
return errENOENT
}
return e
}

0 comments on commit 8aa62f5

Please sign in to comment.