github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/os/dir_darwin.go (about)

     1  // Copyright 2009 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  package os
     6  
     7  import (
     8  	"github.com/x04/go/src/io"
     9  	"github.com/x04/go/src/runtime"
    10  	"github.com/x04/go/src/syscall"
    11  	"github.com/x04/go/src/unsafe"
    12  )
    13  
    14  // Auxiliary information if the File describes a directory
    15  type dirInfo struct {
    16  	dir uintptr	// Pointer to DIR structure from dirent.h
    17  }
    18  
    19  func (d *dirInfo) close() {
    20  	if d.dir == 0 {
    21  		return
    22  	}
    23  	closedir(d.dir)
    24  	d.dir = 0
    25  }
    26  
    27  func (f *File) seekInvalidate() {
    28  	if f.dirinfo == nil {
    29  		return
    30  	}
    31  	// Free cached dirinfo, so we allocate a new one if we
    32  	// access this file as a directory again. See #35767.
    33  	f.dirinfo.close()
    34  	f.dirinfo = nil
    35  }
    36  
    37  func (f *File) readdirnames(n int) (names []string, err error) {
    38  	if f.dirinfo == nil {
    39  		dir, call, errno := f.pfd.OpenDir()
    40  		if errno != nil {
    41  			return nil, wrapSyscallError(call, errno)
    42  		}
    43  		f.dirinfo = &dirInfo{
    44  			dir: dir,
    45  		}
    46  	}
    47  	d := f.dirinfo
    48  
    49  	size := n
    50  	if size <= 0 {
    51  		size = 100
    52  		n = -1
    53  	}
    54  
    55  	names = make([]string, 0, size)
    56  	var dirent syscall.Dirent
    57  	var entptr *syscall.Dirent
    58  	for len(names) < size || n == -1 {
    59  		if res := readdir_r(d.dir, &dirent, &entptr); res != 0 {
    60  			return names, wrapSyscallError("readdir", syscall.Errno(res))
    61  		}
    62  		if entptr == nil {	// EOF
    63  			break
    64  		}
    65  		if dirent.Ino == 0 {
    66  			continue
    67  		}
    68  		name := (*[len(syscall.Dirent{}.Name)]byte)(unsafe.Pointer(&dirent.Name))[:]
    69  		for i, c := range name {
    70  			if c == 0 {
    71  				name = name[:i]
    72  				break
    73  			}
    74  		}
    75  		// Check for useless names before allocating a string.
    76  		if string(name) == "." || string(name) == ".." {
    77  			continue
    78  		}
    79  		names = append(names, string(name))
    80  		runtime.KeepAlive(f)
    81  	}
    82  	if n >= 0 && len(names) == 0 {
    83  		return names, io.EOF
    84  	}
    85  	return names, nil
    86  }
    87  
    88  // Implemented in syscall/syscall_darwin.go.
    89  
    90  //go:linkname closedir syscall.closedir
    91  func closedir(dir uintptr) (err error)
    92  
    93  //go:linkname readdir_r syscall.readdir_r
    94  func readdir_r(dir uintptr, entry *syscall.Dirent, result **syscall.Dirent) (res int)