1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage fs 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Worker// This is based on the readdir implementation from Go 1.9: 18*333d2b36SAndroid Build Coastguard Worker// Copyright 2009 The Go Authors. All rights reserved. 19*333d2b36SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style 20*333d2b36SAndroid Build Coastguard Worker// license that can be found in the LICENSE file. 21*333d2b36SAndroid Build Coastguard Worker 22*333d2b36SAndroid Build Coastguard Workerimport ( 23*333d2b36SAndroid Build Coastguard Worker "os" 24*333d2b36SAndroid Build Coastguard Worker "syscall" 25*333d2b36SAndroid Build Coastguard Worker "unsafe" 26*333d2b36SAndroid Build Coastguard Worker) 27*333d2b36SAndroid Build Coastguard Worker 28*333d2b36SAndroid Build Coastguard Workerconst ( 29*333d2b36SAndroid Build Coastguard Worker blockSize = 4096 30*333d2b36SAndroid Build Coastguard Worker) 31*333d2b36SAndroid Build Coastguard Worker 32*333d2b36SAndroid Build Coastguard Workerfunc readdir(path string) ([]DirEntryInfo, error) { 33*333d2b36SAndroid Build Coastguard Worker f, err := os.Open(path) 34*333d2b36SAndroid Build Coastguard Worker defer f.Close() 35*333d2b36SAndroid Build Coastguard Worker 36*333d2b36SAndroid Build Coastguard Worker if err != nil { 37*333d2b36SAndroid Build Coastguard Worker return nil, err 38*333d2b36SAndroid Build Coastguard Worker } 39*333d2b36SAndroid Build Coastguard Worker // This implicitly switches the fd to non-blocking mode, which is less efficient than what 40*333d2b36SAndroid Build Coastguard Worker // file.ReadDir does since it will keep a thread blocked and not just a goroutine. 41*333d2b36SAndroid Build Coastguard Worker fd := int(f.Fd()) 42*333d2b36SAndroid Build Coastguard Worker 43*333d2b36SAndroid Build Coastguard Worker buf := make([]byte, blockSize) 44*333d2b36SAndroid Build Coastguard Worker entries := make([]*dirEntryInfo, 0, 100) 45*333d2b36SAndroid Build Coastguard Worker 46*333d2b36SAndroid Build Coastguard Worker for { 47*333d2b36SAndroid Build Coastguard Worker n, errno := syscall.ReadDirent(fd, buf) 48*333d2b36SAndroid Build Coastguard Worker if errno != nil { 49*333d2b36SAndroid Build Coastguard Worker err = os.NewSyscallError("readdirent", errno) 50*333d2b36SAndroid Build Coastguard Worker break 51*333d2b36SAndroid Build Coastguard Worker } 52*333d2b36SAndroid Build Coastguard Worker if n <= 0 { 53*333d2b36SAndroid Build Coastguard Worker break // EOF 54*333d2b36SAndroid Build Coastguard Worker } 55*333d2b36SAndroid Build Coastguard Worker 56*333d2b36SAndroid Build Coastguard Worker entries = parseDirent(buf[:n], entries) 57*333d2b36SAndroid Build Coastguard Worker } 58*333d2b36SAndroid Build Coastguard Worker 59*333d2b36SAndroid Build Coastguard Worker ret := make([]DirEntryInfo, 0, len(entries)) 60*333d2b36SAndroid Build Coastguard Worker 61*333d2b36SAndroid Build Coastguard Worker for _, entry := range entries { 62*333d2b36SAndroid Build Coastguard Worker if !entry.modeExists { 63*333d2b36SAndroid Build Coastguard Worker mode, lerr := lstatFileMode(path + "/" + entry.name) 64*333d2b36SAndroid Build Coastguard Worker if os.IsNotExist(lerr) { 65*333d2b36SAndroid Build Coastguard Worker // File disappeared between readdir + stat. 66*333d2b36SAndroid Build Coastguard Worker // Just treat it as if it didn't exist. 67*333d2b36SAndroid Build Coastguard Worker continue 68*333d2b36SAndroid Build Coastguard Worker } 69*333d2b36SAndroid Build Coastguard Worker if lerr != nil { 70*333d2b36SAndroid Build Coastguard Worker return ret, lerr 71*333d2b36SAndroid Build Coastguard Worker } 72*333d2b36SAndroid Build Coastguard Worker entry.mode = mode 73*333d2b36SAndroid Build Coastguard Worker entry.modeExists = true 74*333d2b36SAndroid Build Coastguard Worker } 75*333d2b36SAndroid Build Coastguard Worker ret = append(ret, entry) 76*333d2b36SAndroid Build Coastguard Worker } 77*333d2b36SAndroid Build Coastguard Worker 78*333d2b36SAndroid Build Coastguard Worker return ret, err 79*333d2b36SAndroid Build Coastguard Worker} 80*333d2b36SAndroid Build Coastguard Worker 81*333d2b36SAndroid Build Coastguard Workerfunc parseDirent(buf []byte, entries []*dirEntryInfo) []*dirEntryInfo { 82*333d2b36SAndroid Build Coastguard Worker for len(buf) > 0 { 83*333d2b36SAndroid Build Coastguard Worker reclen, ok := direntReclen(buf) 84*333d2b36SAndroid Build Coastguard Worker if !ok || reclen > uint64(len(buf)) { 85*333d2b36SAndroid Build Coastguard Worker return entries 86*333d2b36SAndroid Build Coastguard Worker } 87*333d2b36SAndroid Build Coastguard Worker rec := buf[:reclen] 88*333d2b36SAndroid Build Coastguard Worker buf = buf[reclen:] 89*333d2b36SAndroid Build Coastguard Worker ino, ok := direntIno(rec) 90*333d2b36SAndroid Build Coastguard Worker if !ok { 91*333d2b36SAndroid Build Coastguard Worker break 92*333d2b36SAndroid Build Coastguard Worker } 93*333d2b36SAndroid Build Coastguard Worker if ino == 0 { // File absent in directory. 94*333d2b36SAndroid Build Coastguard Worker continue 95*333d2b36SAndroid Build Coastguard Worker } 96*333d2b36SAndroid Build Coastguard Worker typ, ok := direntType(rec) 97*333d2b36SAndroid Build Coastguard Worker if !ok { 98*333d2b36SAndroid Build Coastguard Worker break 99*333d2b36SAndroid Build Coastguard Worker } 100*333d2b36SAndroid Build Coastguard Worker const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name)) 101*333d2b36SAndroid Build Coastguard Worker namlen, ok := direntNamlen(rec) 102*333d2b36SAndroid Build Coastguard Worker if !ok || namoff+namlen > uint64(len(rec)) { 103*333d2b36SAndroid Build Coastguard Worker break 104*333d2b36SAndroid Build Coastguard Worker } 105*333d2b36SAndroid Build Coastguard Worker name := rec[namoff : namoff+namlen] 106*333d2b36SAndroid Build Coastguard Worker 107*333d2b36SAndroid Build Coastguard Worker for i, c := range name { 108*333d2b36SAndroid Build Coastguard Worker if c == 0 { 109*333d2b36SAndroid Build Coastguard Worker name = name[:i] 110*333d2b36SAndroid Build Coastguard Worker break 111*333d2b36SAndroid Build Coastguard Worker } 112*333d2b36SAndroid Build Coastguard Worker } 113*333d2b36SAndroid Build Coastguard Worker // Check for useless names before allocating a string. 114*333d2b36SAndroid Build Coastguard Worker if string(name) == "." || string(name) == ".." { 115*333d2b36SAndroid Build Coastguard Worker continue 116*333d2b36SAndroid Build Coastguard Worker } 117*333d2b36SAndroid Build Coastguard Worker 118*333d2b36SAndroid Build Coastguard Worker mode, modeExists := direntTypeToFileMode(typ) 119*333d2b36SAndroid Build Coastguard Worker 120*333d2b36SAndroid Build Coastguard Worker entries = append(entries, &dirEntryInfo{string(name), mode, modeExists}) 121*333d2b36SAndroid Build Coastguard Worker } 122*333d2b36SAndroid Build Coastguard Worker return entries 123*333d2b36SAndroid Build Coastguard Worker} 124*333d2b36SAndroid Build Coastguard Worker 125*333d2b36SAndroid Build Coastguard Workerfunc direntIno(buf []byte) (uint64, bool) { 126*333d2b36SAndroid Build Coastguard Worker return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Ino), unsafe.Sizeof(syscall.Dirent{}.Ino)) 127*333d2b36SAndroid Build Coastguard Worker} 128*333d2b36SAndroid Build Coastguard Worker 129*333d2b36SAndroid Build Coastguard Workerfunc direntType(buf []byte) (uint64, bool) { 130*333d2b36SAndroid Build Coastguard Worker return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Type), unsafe.Sizeof(syscall.Dirent{}.Type)) 131*333d2b36SAndroid Build Coastguard Worker} 132*333d2b36SAndroid Build Coastguard Worker 133*333d2b36SAndroid Build Coastguard Workerfunc direntReclen(buf []byte) (uint64, bool) { 134*333d2b36SAndroid Build Coastguard Worker return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Reclen), unsafe.Sizeof(syscall.Dirent{}.Reclen)) 135*333d2b36SAndroid Build Coastguard Worker} 136*333d2b36SAndroid Build Coastguard Worker 137*333d2b36SAndroid Build Coastguard Workerfunc direntNamlen(buf []byte) (uint64, bool) { 138*333d2b36SAndroid Build Coastguard Worker reclen, ok := direntReclen(buf) 139*333d2b36SAndroid Build Coastguard Worker if !ok { 140*333d2b36SAndroid Build Coastguard Worker return 0, false 141*333d2b36SAndroid Build Coastguard Worker } 142*333d2b36SAndroid Build Coastguard Worker return reclen - uint64(unsafe.Offsetof(syscall.Dirent{}.Name)), true 143*333d2b36SAndroid Build Coastguard Worker} 144*333d2b36SAndroid Build Coastguard Worker 145*333d2b36SAndroid Build Coastguard Worker// readInt returns the size-bytes unsigned integer in native byte order at offset off. 146*333d2b36SAndroid Build Coastguard Workerfunc readInt(b []byte, off, size uintptr) (u uint64, ok bool) { 147*333d2b36SAndroid Build Coastguard Worker if len(b) < int(off+size) { 148*333d2b36SAndroid Build Coastguard Worker return 0, false 149*333d2b36SAndroid Build Coastguard Worker } 150*333d2b36SAndroid Build Coastguard Worker return readIntLE(b[off:], size), true 151*333d2b36SAndroid Build Coastguard Worker} 152*333d2b36SAndroid Build Coastguard Worker 153*333d2b36SAndroid Build Coastguard Workerfunc readIntLE(b []byte, size uintptr) uint64 { 154*333d2b36SAndroid Build Coastguard Worker switch size { 155*333d2b36SAndroid Build Coastguard Worker case 1: 156*333d2b36SAndroid Build Coastguard Worker return uint64(b[0]) 157*333d2b36SAndroid Build Coastguard Worker case 2: 158*333d2b36SAndroid Build Coastguard Worker _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 159*333d2b36SAndroid Build Coastguard Worker return uint64(b[0]) | uint64(b[1])<<8 160*333d2b36SAndroid Build Coastguard Worker case 4: 161*333d2b36SAndroid Build Coastguard Worker _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 162*333d2b36SAndroid Build Coastguard Worker return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 163*333d2b36SAndroid Build Coastguard Worker case 8: 164*333d2b36SAndroid Build Coastguard Worker _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 165*333d2b36SAndroid Build Coastguard Worker return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | 166*333d2b36SAndroid Build Coastguard Worker uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 167*333d2b36SAndroid Build Coastguard Worker default: 168*333d2b36SAndroid Build Coastguard Worker panic("syscall: readInt with unsupported size") 169*333d2b36SAndroid Build Coastguard Worker } 170*333d2b36SAndroid Build Coastguard Worker} 171*333d2b36SAndroid Build Coastguard Worker 172*333d2b36SAndroid Build Coastguard Worker// If the directory entry doesn't specify the type, fall back to using lstat to get the type. 173*333d2b36SAndroid Build Coastguard Workerfunc lstatFileMode(name string) (os.FileMode, error) { 174*333d2b36SAndroid Build Coastguard Worker stat, err := os.Lstat(name) 175*333d2b36SAndroid Build Coastguard Worker if err != nil { 176*333d2b36SAndroid Build Coastguard Worker return 0, err 177*333d2b36SAndroid Build Coastguard Worker } 178*333d2b36SAndroid Build Coastguard Worker 179*333d2b36SAndroid Build Coastguard Worker return stat.Mode() & (os.ModeType | os.ModeCharDevice), nil 180*333d2b36SAndroid Build Coastguard Worker} 181*333d2b36SAndroid Build Coastguard Worker 182*333d2b36SAndroid Build Coastguard Worker// from Linux and Darwin dirent.h 183*333d2b36SAndroid Build Coastguard Workerconst ( 184*333d2b36SAndroid Build Coastguard Worker DT_UNKNOWN = 0 185*333d2b36SAndroid Build Coastguard Worker DT_FIFO = 1 186*333d2b36SAndroid Build Coastguard Worker DT_CHR = 2 187*333d2b36SAndroid Build Coastguard Worker DT_DIR = 4 188*333d2b36SAndroid Build Coastguard Worker DT_BLK = 6 189*333d2b36SAndroid Build Coastguard Worker DT_REG = 8 190*333d2b36SAndroid Build Coastguard Worker DT_LNK = 10 191*333d2b36SAndroid Build Coastguard Worker DT_SOCK = 12 192*333d2b36SAndroid Build Coastguard Worker) 193*333d2b36SAndroid Build Coastguard Worker 194*333d2b36SAndroid Build Coastguard Workerfunc direntTypeToFileMode(typ uint64) (os.FileMode, bool) { 195*333d2b36SAndroid Build Coastguard Worker exists := true 196*333d2b36SAndroid Build Coastguard Worker var mode os.FileMode 197*333d2b36SAndroid Build Coastguard Worker switch typ { 198*333d2b36SAndroid Build Coastguard Worker case DT_UNKNOWN: 199*333d2b36SAndroid Build Coastguard Worker exists = false 200*333d2b36SAndroid Build Coastguard Worker case DT_FIFO: 201*333d2b36SAndroid Build Coastguard Worker mode = os.ModeNamedPipe 202*333d2b36SAndroid Build Coastguard Worker case DT_CHR: 203*333d2b36SAndroid Build Coastguard Worker mode = os.ModeDevice | os.ModeCharDevice 204*333d2b36SAndroid Build Coastguard Worker case DT_DIR: 205*333d2b36SAndroid Build Coastguard Worker mode = os.ModeDir 206*333d2b36SAndroid Build Coastguard Worker case DT_BLK: 207*333d2b36SAndroid Build Coastguard Worker mode = os.ModeDevice 208*333d2b36SAndroid Build Coastguard Worker case DT_REG: 209*333d2b36SAndroid Build Coastguard Worker mode = 0 210*333d2b36SAndroid Build Coastguard Worker case DT_LNK: 211*333d2b36SAndroid Build Coastguard Worker mode = os.ModeSymlink 212*333d2b36SAndroid Build Coastguard Worker case DT_SOCK: 213*333d2b36SAndroid Build Coastguard Worker mode = os.ModeSocket 214*333d2b36SAndroid Build Coastguard Worker default: 215*333d2b36SAndroid Build Coastguard Worker exists = false 216*333d2b36SAndroid Build Coastguard Worker } 217*333d2b36SAndroid Build Coastguard Worker 218*333d2b36SAndroid Build Coastguard Worker return mode, exists 219*333d2b36SAndroid Build Coastguard Worker} 220