// 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 {
	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.
	if .dirinfo == nil {
		.dirinfo = new(dirInfo)
		.dirinfo.buf = dirBufPool.Get().(*[]byte)
	}
	 := .dirinfo

	// 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 {
				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 isBigEndian {
		return readIntBE([:], ), true
	}
	return readIntLE([:], ), true
}

func readIntBE( []byte,  uintptr) uint64 {
	switch  {
	case 1:
		return uint64([0])
	case 2:
		_ = [1] // bounds check hint to compiler; see golang.org/issue/14808
		return uint64([1]) | uint64([0])<<8
	case 4:
		_ = [3] // bounds check hint to compiler; see golang.org/issue/14808
		return uint64([3]) | uint64([2])<<8 | uint64([1])<<16 | uint64([0])<<24
	case 8:
		_ = [7] // bounds check hint to compiler; see golang.org/issue/14808
		return uint64([7]) | uint64([6])<<8 | uint64([5])<<16 | uint64([4])<<24 |
			uint64([3])<<32 | uint64([2])<<40 | uint64([1])<<48 | uint64([0])<<56
	default:
		panic("syscall: readInt with unsupported size")
	}
}

func readIntLE( []byte,  uintptr) uint64 {
	switch  {
	case 1:
		return uint64([0])
	case 2:
		_ = [1] // bounds check hint to compiler; see golang.org/issue/14808
		return uint64([0]) | uint64([1])<<8
	case 4:
		_ = [3] // bounds check hint to compiler; see golang.org/issue/14808
		return uint64([0]) | uint64([1])<<8 | uint64([2])<<16 | uint64([3])<<24
	case 8:
		_ = [7] // bounds check hint to compiler; see golang.org/issue/14808
		return uint64([0]) | uint64([1])<<8 | uint64([2])<<16 | uint64([3])<<24 |
			uint64([4])<<32 | uint64([5])<<40 | uint64([6])<<48 | uint64([7])<<56
	default:
		panic("syscall: readInt with unsupported size")
	}
}