github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/os/dir_gccgo.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  	"io"
     9  	"runtime"
    10  	"sync/atomic"
    11  	"syscall"
    12  	"unsafe"
    13  )
    14  
    15  // FIXME: pathconf returns long, not int.
    16  //extern pathconf
    17  func libc_pathconf(*byte, int32) int
    18  
    19  //extern dup
    20  func libc_dup(int32) int32
    21  
    22  func clen(n []byte) int {
    23  	for i := 0; i < len(n); i++ {
    24  		if n[i] == 0 {
    25  			return i
    26  		}
    27  	}
    28  	return len(n)
    29  }
    30  
    31  var nameMax int32
    32  
    33  func (file *File) readdirnames(n int) (names []string, err error) {
    34  	if file.dirinfo == nil {
    35  		p, err := syscall.BytePtrFromString(file.name)
    36  		if err != nil {
    37  			return nil, err
    38  		}
    39  
    40  		elen := int(atomic.LoadInt32(&nameMax))
    41  		if elen == 0 {
    42  			syscall.Entersyscall()
    43  			plen := libc_pathconf(p, syscall.PC_NAME_MAX)
    44  			syscall.Exitsyscall()
    45  			if plen < 1024 {
    46  				plen = 1024
    47  			}
    48  			var dummy syscall.Dirent
    49  			elen = int(unsafe.Offsetof(dummy.Name)) + plen + 1
    50  			atomic.StoreInt32(&nameMax, int32(elen))
    51  		}
    52  
    53  		syscall.Entersyscall()
    54  		fd := libc_dup(int32(file.pfd.Sysfd))
    55  		errno := syscall.GetErrno()
    56  		syscall.Exitsyscall()
    57  		if fd < 0 {
    58  			return nil, &PathError{"dup", file.name, errno}
    59  		}
    60  
    61  		syscall.Entersyscall()
    62  		r := libc_fdopendir(fd)
    63  		errno = syscall.GetErrno()
    64  		syscall.Exitsyscall()
    65  		if r == nil {
    66  			return nil, &PathError{"fdopendir", file.name, errno}
    67  		}
    68  
    69  		file.dirinfo = new(dirInfo)
    70  		file.dirinfo.buf = make([]byte, elen)
    71  		file.dirinfo.dir = r
    72  	}
    73  
    74  	entryDirent := (*syscall.Dirent)(unsafe.Pointer(&file.dirinfo.buf[0]))
    75  
    76  	size := n
    77  	if size <= 0 {
    78  		size = 100
    79  		n = -1
    80  	}
    81  
    82  	names = make([]string, 0, size) // Empty with room to grow.
    83  
    84  	for n != 0 {
    85  		var dirent *syscall.Dirent
    86  		pr := &dirent
    87  		syscall.Entersyscall()
    88  		i := libc_readdir_r(file.dirinfo.dir, entryDirent, pr)
    89  		syscall.Exitsyscall()
    90  		// On AIX when readdir_r hits EOF it sets dirent to nil and returns 9.
    91  		//  https://www.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.basetrf2/readdir_r.htm
    92  		if runtime.GOOS == "aix" && i == 9 && dirent == nil {
    93  			break
    94  		}
    95  		if i != 0 {
    96  			return names, NewSyscallError("readdir_r", i)
    97  		}
    98  		if dirent == nil {
    99  			break // EOF
   100  		}
   101  		bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
   102  		var name = string(bytes[0:clen(bytes[:])])
   103  		if name == "." || name == ".." { // Useless names
   104  			continue
   105  		}
   106  		names = append(names, name)
   107  		n--
   108  	}
   109  	if n >= 0 && len(names) == 0 {
   110  		return names, io.EOF
   111  	}
   112  	return names, nil
   113  }
   114  
   115  func (f *File) seekInvalidate() {
   116  	if f.file.dirinfo != nil {
   117  		syscall.Entersyscall()
   118  		libc_closedir(f.file.dirinfo.dir)
   119  		syscall.Exitsyscall()
   120  		f.file.dirinfo = nil
   121  	}
   122  }