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

// +build darwin,go1.13

package unix

import (
	

	
)

//sys	closedir(dir uintptr) (err error)
//sys	readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)

func ( int) ( uintptr,  error) {
	, ,  := syscall_syscallPtr(funcPC(libc_fdopendir_trampoline), uintptr(), 0, 0)
	 = uintptr()
	if  != 0 {
		 = errnoErr()
	}
	return
}

func ()

//go:linkname libc_fdopendir libc_fdopendir
//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"

func ( int,  []byte,  *uintptr) ( int,  error) {
	// Simulate Getdirentries using fdopendir/readdir_r/closedir.
	// We store the number of entries to skip in the seek
	// offset of fd. See issue #31368.
	// It's not the full required semantics, but should handle the case
	// of calling Getdirentries or ReadDirent repeatedly.
	// It won't handle assigning the results of lseek to *basep, or handle
	// the directory being edited underfoot.
	,  := Seek(, 0, 1 /* SEEK_CUR */)
	if  != nil {
		return 0, 
	}

	// We need to duplicate the incoming file descriptor
	// because the caller expects to retain control of it, but
	// fdopendir expects to take control of its argument.
	// Just Dup'ing the file descriptor is not enough, as the
	// result shares underlying state. Use Openat to make a really
	// new file descriptor referring to the same directory.
	,  := Openat(, ".", O_RDONLY, 0)
	if  != nil {
		return 0, 
	}
	,  := fdopendir()
	if  != nil {
		Close()
		return 0, 
	}
	defer closedir()

	var  int64
	for {
		var  Dirent
		var  *Dirent
		 := readdir_r(, &, &)
		if  != 0 {
			return , errnoErr()
		}
		if  == nil {
			break
		}
		if  > 0 {
			--
			++
			continue
		}

		 := int(.Reclen)
		if  > len() {
			// Not enough room. Return for now.
			// The counter will let us know where we should start up again.
			// Note: this strategy for suspending in the middle and
			// restarting is O(n^2) in the length of the directory. Oh well.
			break
		}

		// Copy entry into return buffer.
		var  []byte
		 := (*unsafeheader.Slice)(unsafe.Pointer(&))
		.Data = unsafe.Pointer(&)
		.Cap = 
		.Len = 
		copy(, )

		 = [:]
		 += 
		++
	}
	// Set the seek offset of the input fd to record
	// how many files we've already returned.
	_,  = Seek(, , 0 /* SEEK_SET */)
	if  != nil {
		return , 
	}

	return , nil
}