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

View as plain text