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 }