Source file src/os/file_posix.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build unix || (js && wasm) || wasip1 || windows
     6  
     7  package os
     8  
     9  import (
    10  	"internal/testlog"
    11  	"runtime"
    12  	"syscall"
    13  	"time"
    14  )
    15  
    16  // Close closes the [File], rendering it unusable for I/O.
    17  // On files that support [File.SetDeadline], any pending I/O operations will
    18  // be canceled and return immediately with an [ErrClosed] error.
    19  // Close will return an error if it has already been called.
    20  func (f *File) Close() error {
    21  	if f == nil {
    22  		return ErrInvalid
    23  	}
    24  	return f.file.close()
    25  }
    26  
    27  // read reads up to len(b) bytes from the File.
    28  // It returns the number of bytes read and an error, if any.
    29  func (f *File) read(b []byte) (n int, err error) {
    30  	n, err = f.pfd.Read(b)
    31  	runtime.KeepAlive(f)
    32  	return n, err
    33  }
    34  
    35  // pread reads len(b) bytes from the File starting at byte offset off.
    36  // It returns the number of bytes read and the error, if any.
    37  // EOF is signaled by a zero count with err set to nil.
    38  func (f *File) pread(b []byte, off int64) (n int, err error) {
    39  	n, err = f.pfd.Pread(b, off)
    40  	runtime.KeepAlive(f)
    41  	return n, err
    42  }
    43  
    44  // write writes len(b) bytes to the File.
    45  // It returns the number of bytes written and an error, if any.
    46  func (f *File) write(b []byte) (n int, err error) {
    47  	n, err = f.pfd.Write(b)
    48  	runtime.KeepAlive(f)
    49  	return n, err
    50  }
    51  
    52  // pwrite writes len(b) bytes to the File starting at byte offset off.
    53  // It returns the number of bytes written and an error, if any.
    54  func (f *File) pwrite(b []byte, off int64) (n int, err error) {
    55  	n, err = f.pfd.Pwrite(b, off)
    56  	runtime.KeepAlive(f)
    57  	return n, err
    58  }
    59  
    60  // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
    61  func syscallMode(i FileMode) (o uint32) {
    62  	o |= uint32(i.Perm())
    63  	if i&ModeSetuid != 0 {
    64  		o |= syscall.S_ISUID
    65  	}
    66  	if i&ModeSetgid != 0 {
    67  		o |= syscall.S_ISGID
    68  	}
    69  	if i&ModeSticky != 0 {
    70  		o |= syscall.S_ISVTX
    71  	}
    72  	// No mapping for Go's ModeTemporary (plan9 only).
    73  	return
    74  }
    75  
    76  // See docs in file.go:Chmod.
    77  func chmod(name string, mode FileMode) error {
    78  	longName := fixLongPath(name)
    79  	e := ignoringEINTR(func() error {
    80  		return syscall.Chmod(longName, syscallMode(mode))
    81  	})
    82  	if e != nil {
    83  		return &PathError{Op: "chmod", Path: name, Err: e}
    84  	}
    85  	return nil
    86  }
    87  
    88  // See docs in file.go:(*File).Chmod.
    89  func (f *File) chmod(mode FileMode) error {
    90  	if err := f.checkValid("chmod"); err != nil {
    91  		return err
    92  	}
    93  	if e := f.pfd.Fchmod(syscallMode(mode)); e != nil {
    94  		return f.wrapErr("chmod", e)
    95  	}
    96  	return nil
    97  }
    98  
    99  // Chown changes the numeric uid and gid of the named file.
   100  // If the file is a symbolic link, it changes the uid and gid of the link's target.
   101  // A uid or gid of -1 means to not change that value.
   102  // If there is an error, it will be of type [*PathError].
   103  //
   104  // On Windows or Plan 9, Chown always returns the [syscall.EWINDOWS] or
   105  // [syscall.EPLAN9] error, wrapped in [*PathError].
   106  func Chown(name string, uid, gid int) error {
   107  	e := ignoringEINTR(func() error {
   108  		return syscall.Chown(name, uid, gid)
   109  	})
   110  	if e != nil {
   111  		return &PathError{Op: "chown", Path: name, Err: e}
   112  	}
   113  	return nil
   114  }
   115  
   116  // Lchown changes the numeric uid and gid of the named file.
   117  // If the file is a symbolic link, it changes the uid and gid of the link itself.
   118  // If there is an error, it will be of type [*PathError].
   119  //
   120  // On Windows, it always returns the [syscall.EWINDOWS] error, wrapped
   121  // in [*PathError].
   122  func Lchown(name string, uid, gid int) error {
   123  	e := ignoringEINTR(func() error {
   124  		return syscall.Lchown(name, uid, gid)
   125  	})
   126  	if e != nil {
   127  		return &PathError{Op: "lchown", Path: name, Err: e}
   128  	}
   129  	return nil
   130  }
   131  
   132  // Chown changes the numeric uid and gid of the named file.
   133  // If there is an error, it will be of type [*PathError].
   134  //
   135  // On Windows, it always returns the [syscall.EWINDOWS] error, wrapped
   136  // in [*PathError].
   137  func (f *File) Chown(uid, gid int) error {
   138  	if err := f.checkValid("chown"); err != nil {
   139  		return err
   140  	}
   141  	if e := f.pfd.Fchown(uid, gid); e != nil {
   142  		return f.wrapErr("chown", e)
   143  	}
   144  	return nil
   145  }
   146  
   147  // Truncate changes the size of the file.
   148  // It does not change the I/O offset.
   149  // If there is an error, it will be of type [*PathError].
   150  func (f *File) Truncate(size int64) error {
   151  	if err := f.checkValid("truncate"); err != nil {
   152  		return err
   153  	}
   154  	if e := f.pfd.Ftruncate(size); e != nil {
   155  		return f.wrapErr("truncate", e)
   156  	}
   157  	return nil
   158  }
   159  
   160  // Sync commits the current contents of the file to stable storage.
   161  // Typically, this means flushing the file system's in-memory copy
   162  // of recently written data to disk.
   163  func (f *File) Sync() error {
   164  	if err := f.checkValid("sync"); err != nil {
   165  		return err
   166  	}
   167  	if e := f.pfd.Fsync(); e != nil {
   168  		return f.wrapErr("sync", e)
   169  	}
   170  	return nil
   171  }
   172  
   173  // Chtimes changes the access and modification times of the named
   174  // file, similar to the Unix utime() or utimes() functions.
   175  // A zero [time.Time] value will leave the corresponding file time unchanged.
   176  //
   177  // The underlying filesystem may truncate or round the values to a
   178  // less precise time unit.
   179  // If there is an error, it will be of type [*PathError].
   180  func Chtimes(name string, atime time.Time, mtime time.Time) error {
   181  	utimes := chtimesUtimes(atime, mtime)
   182  	if e := syscall.UtimesNano(fixLongPath(name), utimes[0:]); e != nil {
   183  		return &PathError{Op: "chtimes", Path: name, Err: e}
   184  	}
   185  	return nil
   186  }
   187  
   188  func chtimesUtimes(atime, mtime time.Time) [2]syscall.Timespec {
   189  	var utimes [2]syscall.Timespec
   190  	set := func(i int, t time.Time) {
   191  		if t.IsZero() {
   192  			utimes[i] = syscall.Timespec{Sec: _UTIME_OMIT, Nsec: _UTIME_OMIT}
   193  		} else {
   194  			utimes[i] = syscall.NsecToTimespec(t.UnixNano())
   195  		}
   196  	}
   197  	set(0, atime)
   198  	set(1, mtime)
   199  	return utimes
   200  }
   201  
   202  // Chdir changes the current working directory to the file,
   203  // which must be a directory.
   204  // If there is an error, it will be of type [*PathError].
   205  func (f *File) Chdir() error {
   206  	if err := f.checkValid("chdir"); err != nil {
   207  		return err
   208  	}
   209  	if e := f.pfd.Fchdir(); e != nil {
   210  		return f.wrapErr("chdir", e)
   211  	}
   212  	if log := testlog.Logger(); log != nil {
   213  		wd, err := Getwd()
   214  		if err == nil {
   215  			log.Chdir(wd)
   216  		}
   217  	}
   218  	return nil
   219  }
   220  
   221  // setDeadline sets the read and write deadline.
   222  func (f *File) setDeadline(t time.Time) error {
   223  	if err := f.checkValid("SetDeadline"); err != nil {
   224  		return err
   225  	}
   226  	return f.pfd.SetDeadline(t)
   227  }
   228  
   229  // setReadDeadline sets the read deadline.
   230  func (f *File) setReadDeadline(t time.Time) error {
   231  	if err := f.checkValid("SetReadDeadline"); err != nil {
   232  		return err
   233  	}
   234  	return f.pfd.SetReadDeadline(t)
   235  }
   236  
   237  // setWriteDeadline sets the write deadline.
   238  func (f *File) setWriteDeadline(t time.Time) error {
   239  	if err := f.checkValid("SetWriteDeadline"); err != nil {
   240  		return err
   241  	}
   242  	return f.pfd.SetWriteDeadline(t)
   243  }
   244  
   245  // checkValid checks whether f is valid for use.
   246  // If not, it returns an appropriate error, perhaps incorporating the operation name op.
   247  func (f *File) checkValid(op string) error {
   248  	if f == nil {
   249  		return ErrInvalid
   250  	}
   251  	return nil
   252  }
   253  
   254  // ignoringEINTR makes a function call and repeats it if it returns an
   255  // EINTR error. This appears to be required even though we install all
   256  // signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
   257  // Also #20400 and #36644 are issues in which a signal handler is
   258  // installed without setting SA_RESTART. None of these are the common case,
   259  // but there are enough of them that it seems that we can't avoid
   260  // an EINTR loop.
   261  func ignoringEINTR(fn func() error) error {
   262  	for {
   263  		err := fn()
   264  		if err != syscall.EINTR {
   265  			return err
   266  		}
   267  	}
   268  }
   269  
   270  // ignoringEINTR2 is ignoringEINTR, but returning an additional value.
   271  func ignoringEINTR2[T any](fn func() (T, error)) (T, error) {
   272  	for {
   273  		v, err := fn()
   274  		if err != syscall.EINTR {
   275  			return v, err
   276  		}
   277  	}
   278  }
   279  

View as plain text