2009-06-04 13:33:57 -07:00
|
|
|
// 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.
|
|
|
|
|
|
2023-03-25 10:18:26 -07:00
|
|
|
//go:build aix || dragonfly || freebsd || (js && wasm) || wasip1 || linux || netbsd || openbsd || solaris
|
build: add build comments to core packages
The go/build package already recognizes
system-specific file names like
mycode_darwin.go
mycode_darwin_386.go
mycode_386.s
However, it is also common to write files that
apply to multiple architectures, so a recent CL added
to go/build the ability to process comments
listing a set of conditions for building. For example:
// +build darwin freebsd openbsd/386
says that this file should be compiled only on
OS X, FreeBSD, or 32-bit x86 OpenBSD systems.
These conventions are not yet documented
(hence this long CL description).
This CL adds build comments to the multi-system
files in the core library, a step toward making it
possible to use go/build to build them.
With this change go/build can handle crypto/rand,
exec, net, path/filepath, os/user, and time.
os and syscall need additional adjustments.
R=golang-dev, r, gri, r, gustavo
CC=golang-dev
https://golang.org/cl/5011046
2011-09-15 16:48:57 -04:00
|
|
|
|
2009-06-04 13:33:57 -07:00
|
|
|
package os
|
|
|
|
|
|
|
|
|
|
import (
|
2024-05-14 13:22:07 +02:00
|
|
|
"internal/byteorder"
|
2024-03-05 10:54:22 +01:00
|
|
|
"internal/goarch"
|
2011-11-01 21:49:08 -04:00
|
|
|
"io"
|
2017-02-10 15:17:38 -08:00
|
|
|
"runtime"
|
2021-03-16 12:35:35 +10:30
|
|
|
"sync"
|
2009-12-15 15:40:16 -08:00
|
|
|
"syscall"
|
2020-10-09 11:49:59 -04:00
|
|
|
"unsafe"
|
2009-06-04 13:33:57 -07:00
|
|
|
)
|
|
|
|
|
|
2018-12-08 16:45:29 +01:00
|
|
|
// Auxiliary information if the File describes a directory
|
|
|
|
|
type dirInfo struct {
|
2024-04-12 16:08:22 -04:00
|
|
|
mu sync.Mutex
|
2021-03-16 12:35:35 +10:30
|
|
|
buf *[]byte // buffer for directory I/O
|
|
|
|
|
nbuf int // length of buf; return value from Getdirentries
|
|
|
|
|
bufp int // location of next record in buf.
|
2018-12-08 16:45:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-06-04 13:33:57 -07:00
|
|
|
const (
|
2018-06-29 14:38:56 -07:00
|
|
|
// More than 5760 to work around https://golang.org/issue/24015.
|
|
|
|
|
blockSize = 8192
|
2009-06-04 13:33:57 -07:00
|
|
|
)
|
|
|
|
|
|
2021-03-16 12:35:35 +10:30
|
|
|
var dirBufPool = sync.Pool{
|
2021-12-01 12:15:45 -05:00
|
|
|
New: func() any {
|
2021-03-16 12:35:35 +10:30
|
|
|
// The buffer must be at least a block long.
|
|
|
|
|
buf := make([]byte, blockSize)
|
|
|
|
|
return &buf
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *dirInfo) close() {
|
|
|
|
|
if d.buf != nil {
|
|
|
|
|
dirBufPool.Put(d.buf)
|
|
|
|
|
d.buf = nil
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-08-15 01:39:00 +09:00
|
|
|
|
2020-10-09 11:49:59 -04:00
|
|
|
func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
|
2024-04-12 16:08:22 -04:00
|
|
|
// If this file has no dirInfo, create one.
|
2025-02-03 05:56:31 +00:00
|
|
|
var d *dirInfo
|
|
|
|
|
for {
|
|
|
|
|
d = f.dirinfo.Load()
|
|
|
|
|
if d != nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
newD := new(dirInfo)
|
|
|
|
|
if f.dirinfo.CompareAndSwap(nil, newD) {
|
|
|
|
|
d = newD
|
|
|
|
|
break
|
|
|
|
|
}
|
2009-06-04 13:33:57 -07:00
|
|
|
}
|
2025-02-03 05:56:31 +00:00
|
|
|
|
2024-04-12 16:08:22 -04:00
|
|
|
d.mu.Lock()
|
|
|
|
|
defer d.mu.Unlock()
|
2024-03-25 12:19:47 +01:00
|
|
|
if d.buf == nil {
|
2024-04-12 16:08:22 -04:00
|
|
|
d.buf = dirBufPool.Get().(*[]byte)
|
2024-03-25 12:19:47 +01:00
|
|
|
}
|
2011-05-16 09:26:16 -07:00
|
|
|
|
2020-11-04 11:52:43 -08:00
|
|
|
// Change the meaning of n for the implementation below.
|
|
|
|
|
//
|
|
|
|
|
// The n above was for the public interface of "if n <= 0,
|
|
|
|
|
// Readdir returns all the FileInfo from the directory in a
|
|
|
|
|
// single slice".
|
|
|
|
|
//
|
|
|
|
|
// But below, we use only negative to mean looping until the
|
|
|
|
|
// end and positive to mean bounded, with positive
|
|
|
|
|
// terminating at 0.
|
|
|
|
|
if n == 0 {
|
2011-05-27 12:58:59 -07:00
|
|
|
n = -1
|
2009-06-04 13:33:57 -07:00
|
|
|
}
|
2011-05-16 09:26:16 -07:00
|
|
|
|
|
|
|
|
for n != 0 {
|
2009-06-04 13:33:57 -07:00
|
|
|
// Refill the buffer if necessary
|
|
|
|
|
if d.bufp >= d.nbuf {
|
2009-12-15 15:40:16 -08:00
|
|
|
d.bufp = 0
|
2011-11-13 22:44:52 -05:00
|
|
|
var errno error
|
2021-03-16 12:35:35 +10:30
|
|
|
d.nbuf, errno = f.pfd.ReadDirent(*d.buf)
|
2017-02-10 15:17:38 -08:00
|
|
|
runtime.KeepAlive(f)
|
2011-11-13 22:44:52 -05:00
|
|
|
if errno != nil {
|
2020-07-03 12:25:49 -04:00
|
|
|
return names, dirents, infos, &PathError{Op: "readdirent", Path: f.name, Err: errno}
|
2009-06-04 13:33:57 -07:00
|
|
|
}
|
2009-06-25 20:24:55 -07:00
|
|
|
if d.nbuf <= 0 {
|
2024-03-25 12:19:47 +01:00
|
|
|
// Optimization: we can return the buffer to the pool, there is nothing else to read.
|
|
|
|
|
dirBufPool.Put(d.buf)
|
|
|
|
|
d.buf = nil
|
2009-12-15 15:40:16 -08:00
|
|
|
break // EOF
|
2009-06-04 13:33:57 -07:00
|
|
|
}
|
|
|
|
|
}
|
2011-04-06 15:44:40 -04:00
|
|
|
|
2009-06-04 13:33:57 -07:00
|
|
|
// Drain the buffer
|
2021-03-16 12:35:35 +10:30
|
|
|
buf := (*d.buf)[d.bufp:d.nbuf]
|
2020-10-09 11:49:59 -04:00
|
|
|
reclen, ok := direntReclen(buf)
|
|
|
|
|
if !ok || reclen > uint64(len(buf)) {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
rec := buf[:reclen]
|
|
|
|
|
d.bufp += int(reclen)
|
|
|
|
|
ino, ok := direntIno(rec)
|
|
|
|
|
if !ok {
|
|
|
|
|
break
|
|
|
|
|
}
|
2023-07-04 18:15:58 -07:00
|
|
|
// When building to wasip1, the host runtime might be running on Windows
|
|
|
|
|
// or might expose a remote file system which does not have the concept
|
|
|
|
|
// of inodes. Therefore, we cannot make the assumption that it is safe
|
|
|
|
|
// to skip entries with zero inodes.
|
2025-11-24 22:04:34 -05:00
|
|
|
// Some Linux filesystems (old XFS, FUSE) can return valid files with zero inodes.
|
|
|
|
|
if ino == 0 && runtime.GOOS != "linux" && runtime.GOOS != "wasip1" {
|
2020-10-09 11:49:59 -04:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name))
|
|
|
|
|
namlen, ok := direntNamlen(rec)
|
|
|
|
|
if !ok || namoff+namlen > uint64(len(rec)) {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
name := rec[namoff : namoff+namlen]
|
|
|
|
|
for i, c := range name {
|
|
|
|
|
if c == 0 {
|
|
|
|
|
name = name[:i]
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Check for useless names before allocating a string.
|
|
|
|
|
if string(name) == "." || string(name) == ".." {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2020-11-04 11:52:43 -08:00
|
|
|
if n > 0 { // see 'n == 0' comment above
|
|
|
|
|
n--
|
|
|
|
|
}
|
2020-10-09 11:49:59 -04:00
|
|
|
if mode == readdirName {
|
|
|
|
|
names = append(names, string(name))
|
|
|
|
|
} else if mode == readdirDirEntry {
|
|
|
|
|
de, err := newUnixDirent(f.name, string(name), direntType(rec))
|
|
|
|
|
if IsNotExist(err) {
|
|
|
|
|
// File disappeared between readdir and stat.
|
|
|
|
|
// Treat as if it didn't exist.
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, dirents, nil, err
|
|
|
|
|
}
|
|
|
|
|
dirents = append(dirents, de)
|
|
|
|
|
} else {
|
|
|
|
|
info, err := lstat(f.name + "/" + string(name))
|
|
|
|
|
if IsNotExist(err) {
|
|
|
|
|
// File disappeared between readdir + stat.
|
|
|
|
|
// Treat as if it didn't exist.
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nil, infos, err
|
|
|
|
|
}
|
|
|
|
|
infos = append(infos, info)
|
|
|
|
|
}
|
2011-05-16 09:26:16 -07:00
|
|
|
}
|
2020-10-09 11:49:59 -04:00
|
|
|
|
|
|
|
|
if n > 0 && len(names)+len(dirents)+len(infos) == 0 {
|
|
|
|
|
return nil, nil, nil, io.EOF
|
|
|
|
|
}
|
|
|
|
|
return names, dirents, infos, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// readInt returns the size-bytes unsigned integer in native byte order at offset off.
|
|
|
|
|
func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
|
|
|
|
|
if len(b) < int(off+size) {
|
|
|
|
|
return 0, false
|
|
|
|
|
}
|
2024-03-05 10:54:22 +01:00
|
|
|
if goarch.BigEndian {
|
2020-10-09 11:49:59 -04:00
|
|
|
return readIntBE(b[off:], size), true
|
|
|
|
|
}
|
|
|
|
|
return readIntLE(b[off:], size), true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func readIntBE(b []byte, size uintptr) uint64 {
|
|
|
|
|
switch size {
|
|
|
|
|
case 1:
|
|
|
|
|
return uint64(b[0])
|
|
|
|
|
case 2:
|
2024-11-12 23:39:27 +01:00
|
|
|
return uint64(byteorder.BEUint16(b))
|
2020-10-09 11:49:59 -04:00
|
|
|
case 4:
|
2024-11-12 23:39:27 +01:00
|
|
|
return uint64(byteorder.BEUint32(b))
|
2020-10-09 11:49:59 -04:00
|
|
|
case 8:
|
2024-11-12 23:39:27 +01:00
|
|
|
return uint64(byteorder.BEUint64(b))
|
2020-10-09 11:49:59 -04:00
|
|
|
default:
|
|
|
|
|
panic("syscall: readInt with unsupported size")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func readIntLE(b []byte, size uintptr) uint64 {
|
|
|
|
|
switch size {
|
|
|
|
|
case 1:
|
|
|
|
|
return uint64(b[0])
|
|
|
|
|
case 2:
|
2024-11-12 23:39:27 +01:00
|
|
|
return uint64(byteorder.LEUint16(b))
|
2020-10-09 11:49:59 -04:00
|
|
|
case 4:
|
2024-11-12 23:39:27 +01:00
|
|
|
return uint64(byteorder.LEUint32(b))
|
2020-10-09 11:49:59 -04:00
|
|
|
case 8:
|
2024-11-12 23:39:27 +01:00
|
|
|
return uint64(byteorder.LEUint64(b))
|
2020-10-09 11:49:59 -04:00
|
|
|
default:
|
|
|
|
|
panic("syscall: readInt with unsupported size")
|
2009-06-04 13:33:57 -07:00
|
|
|
}
|
|
|
|
|
}
|