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

//go:build aix || dragonfly || freebsd || (js && wasm) || wasip1 || linux || netbsd || openbsd || solaris

package os

import (
	
	
	
	
	
	
	
)

// Auxiliary information if the File describes a directory
type dirInfo struct {
	mu   sync.Mutex
	buf  *[]byte // buffer for directory I/O
	nbuf int     // length of buf; return value from Getdirentries
	bufp int     // location of next record in buf.
}

const (
	// More than 5760 to work around https://golang.org/issue/24015.
	blockSize = 8192
)

var dirBufPool = sync.Pool{
	New: func() any {
		// The buffer must be at least a block long.
		 := make([]byte, blockSize)
		return &
	},
}

func ( *dirInfo) () {
	if .buf != nil {
		dirBufPool.Put(.buf)
		.buf = nil
	}
}

func ( *File) ( int,  readdirMode) ( []string,  []DirEntry,  []FileInfo,  error) {
	// If this file has no dirInfo, create one.
	 := .dirinfo.Load()
	if  == nil {
		 = new(dirInfo)
		.dirinfo.Store()
	}
	.mu.Lock()
	defer .mu.Unlock()
	if .buf == nil {
		.buf = dirBufPool.Get().(*[]byte)
	}

	// 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  == 0 {
		 = -1
	}

	for  != 0 {
		// Refill the buffer if necessary
		if .bufp >= .nbuf {
			.bufp = 0
			var  error
			.nbuf,  = .pfd.ReadDirent(*.buf)
			runtime.KeepAlive()
			if  != nil {
				return , , , &PathError{Op: "readdirent", Path: .name, Err: }
			}
			if .nbuf <= 0 {
				// Optimization: we can return the buffer to the pool, there is nothing else to read.
				dirBufPool.Put(.buf)
				.buf = nil
				break // EOF
			}
		}

		// Drain the buffer
		 := (*.buf)[.bufp:.nbuf]
		,  := direntReclen()
		if ! ||  > uint64(len()) {
			break
		}
		 := [:]
		.bufp += int()
		,  := direntIno()
		if ! {
			break
		}
		// 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.
		if  == 0 && runtime.GOOS != "wasip1" {
			continue
		}
		const  = uint64(unsafe.Offsetof(syscall.Dirent{}.Name))
		,  := direntNamlen()
		if ! || + > uint64(len()) {
			break
		}
		 := [ : +]
		for ,  := range  {
			if  == 0 {
				 = [:]
				break
			}
		}
		// Check for useless names before allocating a string.
		if string() == "." || string() == ".." {
			continue
		}
		if  > 0 { // see 'n == 0' comment above
			--
		}
		if  == readdirName {
			 = append(, string())
		} else if  == readdirDirEntry {
			,  := newUnixDirent(.name, string(), direntType())
			if IsNotExist() {
				// File disappeared between readdir and stat.
				// Treat as if it didn't exist.
				continue
			}
			if  != nil {
				return nil, , nil, 
			}
			 = append(, )
		} else {
			,  := lstat(.name + "/" + string())
			if IsNotExist() {
				// File disappeared between readdir + stat.
				// Treat as if it didn't exist.
				continue
			}
			if  != nil {
				return nil, nil, , 
			}
			 = append(, )
		}
	}

	if  > 0 && len()+len()+len() == 0 {
		return nil, nil, nil, io.EOF
	}
	return , , , nil
}

// readInt returns the size-bytes unsigned integer in native byte order at offset off.
func readInt( []byte, ,  uintptr) ( uint64,  bool) {
	if len() < int(+) {
		return 0, false
	}
	if goarch.BigEndian {
		return readIntBE([:], ), true
	}
	return readIntLE([:], ), true
}

func readIntBE( []byte,  uintptr) uint64 {
	switch  {
	case 1:
		return uint64([0])
	case 2:
		return uint64(byteorder.BeUint16())
	case 4:
		return uint64(byteorder.BeUint32())
	case 8:
		return uint64(byteorder.BeUint64())
	default:
		panic("syscall: readInt with unsupported size")
	}
}

func readIntLE( []byte,  uintptr) uint64 {
	switch  {
	case 1:
		return uint64([0])
	case 2:
		return uint64(byteorder.LeUint16())
	case 4:
		return uint64(byteorder.LeUint32())
	case 8:
		return uint64(byteorder.LeUint64())
	default:
		panic("syscall: readInt with unsupported size")
	}
}