github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libgo/go/os/dir.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  	"sync/atomic"
    10  	"syscall"
    11  	"unsafe"
    12  )
    13  
    14  //extern opendir
    15  func libc_opendir(*byte) *syscall.DIR
    16  
    17  //extern closedir
    18  func libc_closedir(*syscall.DIR) int
    19  
    20  // FIXME: pathconf returns long, not int.
    21  //extern pathconf
    22  func libc_pathconf(*byte, int) int
    23  
    24  func clen(n []byte) int {
    25  	for i := 0; i < len(n); i++ {
    26  		if n[i] == 0 {
    27  			return i
    28  		}
    29  	}
    30  	return len(n)
    31  }
    32  
    33  var nameMax int32
    34  
    35  func (file *File) readdirnames(n int) (names []string, err error) {
    36  	if file.dirinfo == nil {
    37  		p, err := syscall.BytePtrFromString(file.name)
    38  		if err != nil {
    39  			return nil, err
    40  		}
    41  
    42  		elen := int(atomic.LoadInt32(&nameMax))
    43  		if elen == 0 {
    44  			syscall.Entersyscall()
    45  			plen := libc_pathconf(p, syscall.PC_NAME_MAX)
    46  			syscall.Exitsyscall()
    47  			if plen < 1024 {
    48  				plen = 1024
    49  			}
    50  			var dummy syscall.Dirent
    51  			elen = int(unsafe.Offsetof(dummy.Name)) + plen + 1
    52  			atomic.StoreInt32(&nameMax, int32(elen))
    53  		}
    54  
    55  		syscall.Entersyscall()
    56  		r := libc_opendir(p)
    57  		errno := syscall.GetErrno()
    58  		syscall.Exitsyscall()
    59  		if r == nil {
    60  			return nil, &PathError{"opendir", file.name, errno}
    61  		}
    62  
    63  		file.dirinfo = new(dirInfo)
    64  		file.dirinfo.buf = make([]byte, elen)
    65  		file.dirinfo.dir = r
    66  	}
    67  
    68  	entryDirent := (*syscall.Dirent)(unsafe.Pointer(&file.dirinfo.buf[0]))
    69  
    70  	size := n
    71  	if size <= 0 {
    72  		size = 100
    73  		n = -1
    74  	}
    75  
    76  	names = make([]string, 0, size) // Empty with room to grow.
    77  
    78  	for n != 0 {
    79  		var dirent *syscall.Dirent
    80  		pr := &dirent
    81  		syscall.Entersyscall()
    82  		i := libc_readdir_r(file.dirinfo.dir, entryDirent, pr)
    83  		syscall.Exitsyscall()
    84  		if i != 0 {
    85  			return names, NewSyscallError("readdir_r", i)
    86  		}
    87  		if dirent == nil {
    88  			break // EOF
    89  		}
    90  		bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
    91  		var name = string(bytes[0:clen(bytes[:])])
    92  		if name == "." || name == ".." { // Useless names
    93  			continue
    94  		}
    95  		names = append(names, name)
    96  		n--
    97  	}
    98  	if n >= 0 && len(names) == 0 {
    99  		return names, io.EOF
   100  	}
   101  	return names, nil
   102  }