Source file src/os/root_noopenat.go

     1  // Copyright 2024 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 (js && wasm) || plan9
     6  
     7  package os
     8  
     9  import (
    10  	"errors"
    11  	"sync/atomic"
    12  )
    13  
    14  // root implementation for platforms with no openat.
    15  // Currently plan9 and js.
    16  type root struct {
    17  	name   string
    18  	closed atomic.Bool
    19  }
    20  
    21  // openRootNolog is OpenRoot.
    22  func openRootNolog(name string) (*Root, error) {
    23  	r, err := newRoot(name)
    24  	if err != nil {
    25  		return nil, &PathError{Op: "open", Path: name, Err: err}
    26  	}
    27  	return r, nil
    28  }
    29  
    30  // openRootInRoot is Root.OpenRoot.
    31  func openRootInRoot(r *Root, name string) (*Root, error) {
    32  	if err := checkPathEscapes(r, name); err != nil {
    33  		return nil, &PathError{Op: "openat", Path: name, Err: err}
    34  	}
    35  	r, err := newRoot(joinPath(r.root.name, name))
    36  	if err != nil {
    37  		return nil, &PathError{Op: "openat", Path: name, Err: err}
    38  	}
    39  	return r, nil
    40  }
    41  
    42  // newRoot returns a new Root.
    43  // If fd is not a directory, it closes it and returns an error.
    44  func newRoot(name string) (*Root, error) {
    45  	fi, err := Stat(name)
    46  	if err != nil {
    47  		return nil, err.(*PathError).Err
    48  	}
    49  	if !fi.IsDir() {
    50  		return nil, errors.New("not a directory")
    51  	}
    52  	return &Root{root{name: name}}, nil
    53  }
    54  
    55  func (r *root) Close() error {
    56  	// For consistency with platforms where Root.Close closes a handle,
    57  	// mark the Root as closed and return errors from future calls.
    58  	r.closed.Store(true)
    59  	return nil
    60  }
    61  
    62  func (r *root) Name() string {
    63  	return r.name
    64  }
    65  
    66  // rootOpenFileNolog is Root.OpenFile.
    67  func rootOpenFileNolog(r *Root, name string, flag int, perm FileMode) (*File, error) {
    68  	if err := checkPathEscapes(r, name); err != nil {
    69  		return nil, &PathError{Op: "openat", Path: name, Err: err}
    70  	}
    71  	f, err := openFileNolog(joinPath(r.root.name, name), flag, perm)
    72  	if err != nil {
    73  		return nil, &PathError{Op: "openat", Path: name, Err: underlyingError(err)}
    74  	}
    75  	return f, nil
    76  }
    77  
    78  func rootStat(r *Root, name string, lstat bool) (FileInfo, error) {
    79  	var fi FileInfo
    80  	var err error
    81  	if lstat {
    82  		err = checkPathEscapesLstat(r, name)
    83  		if err == nil {
    84  			fi, err = Lstat(joinPath(r.root.name, name))
    85  		}
    86  	} else {
    87  		err = checkPathEscapes(r, name)
    88  		if err == nil {
    89  			fi, err = Stat(joinPath(r.root.name, name))
    90  		}
    91  	}
    92  	if err != nil {
    93  		return nil, &PathError{Op: "statat", Path: name, Err: underlyingError(err)}
    94  	}
    95  	return fi, nil
    96  }
    97  
    98  func rootMkdir(r *Root, name string, perm FileMode) error {
    99  	if err := checkPathEscapes(r, name); err != nil {
   100  		return &PathError{Op: "mkdirat", Path: name, Err: err}
   101  	}
   102  	if err := Mkdir(joinPath(r.root.name, name), perm); err != nil {
   103  		return &PathError{Op: "mkdirat", Path: name, Err: underlyingError(err)}
   104  	}
   105  	return nil
   106  }
   107  
   108  func rootRemove(r *Root, name string) error {
   109  	if err := checkPathEscapesLstat(r, name); err != nil {
   110  		return &PathError{Op: "removeat", Path: name, Err: err}
   111  	}
   112  	if err := Remove(joinPath(r.root.name, name)); err != nil {
   113  		return &PathError{Op: "removeat", Path: name, Err: underlyingError(err)}
   114  	}
   115  	return nil
   116  }
   117  

View as plain text