Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / golang.org / x / tools / internal / fastwalk / fastwalk_unix.go
1 // Copyright 2016 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 // +build linux darwin freebsd openbsd netbsd
6 // +build !appengine
7
8 package fastwalk
9
10 import (
11         "fmt"
12         "os"
13         "syscall"
14         "unsafe"
15 )
16
17 const blockSize = 8 << 10
18
19 // unknownFileMode is a sentinel (and bogus) os.FileMode
20 // value used to represent a syscall.DT_UNKNOWN Dirent.Type.
21 const unknownFileMode os.FileMode = os.ModeNamedPipe | os.ModeSocket | os.ModeDevice
22
23 func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error {
24         fd, err := syscall.Open(dirName, 0, 0)
25         if err != nil {
26                 return &os.PathError{Op: "open", Path: dirName, Err: err}
27         }
28         defer syscall.Close(fd)
29
30         // The buffer must be at least a block long.
31         buf := make([]byte, blockSize) // stack-allocated; doesn't escape
32         bufp := 0                      // starting read position in buf
33         nbuf := 0                      // end valid data in buf
34         skipFiles := false
35         for {
36                 if bufp >= nbuf {
37                         bufp = 0
38                         nbuf, err = syscall.ReadDirent(fd, buf)
39                         if err != nil {
40                                 return os.NewSyscallError("readdirent", err)
41                         }
42                         if nbuf <= 0 {
43                                 return nil
44                         }
45                 }
46                 consumed, name, typ := parseDirEnt(buf[bufp:nbuf])
47                 bufp += consumed
48                 if name == "" || name == "." || name == ".." {
49                         continue
50                 }
51                 // Fallback for filesystems (like old XFS) that don't
52                 // support Dirent.Type and have DT_UNKNOWN (0) there
53                 // instead.
54                 if typ == unknownFileMode {
55                         fi, err := os.Lstat(dirName + "/" + name)
56                         if err != nil {
57                                 // It got deleted in the meantime.
58                                 if os.IsNotExist(err) {
59                                         continue
60                                 }
61                                 return err
62                         }
63                         typ = fi.Mode() & os.ModeType
64                 }
65                 if skipFiles && typ.IsRegular() {
66                         continue
67                 }
68                 if err := fn(dirName, name, typ); err != nil {
69                         if err == SkipFiles {
70                                 skipFiles = true
71                                 continue
72                         }
73                         return err
74                 }
75         }
76 }
77
78 func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) {
79         // golang.org/issue/15653
80         dirent := (*syscall.Dirent)(unsafe.Pointer(&buf[0]))
81         if v := unsafe.Offsetof(dirent.Reclen) + unsafe.Sizeof(dirent.Reclen); uintptr(len(buf)) < v {
82                 panic(fmt.Sprintf("buf size of %d smaller than dirent header size %d", len(buf), v))
83         }
84         if len(buf) < int(dirent.Reclen) {
85                 panic(fmt.Sprintf("buf size %d < record length %d", len(buf), dirent.Reclen))
86         }
87         consumed = int(dirent.Reclen)
88         if direntInode(dirent) == 0 { // File absent in directory.
89                 return
90         }
91         switch dirent.Type {
92         case syscall.DT_REG:
93                 typ = 0
94         case syscall.DT_DIR:
95                 typ = os.ModeDir
96         case syscall.DT_LNK:
97                 typ = os.ModeSymlink
98         case syscall.DT_BLK:
99                 typ = os.ModeDevice
100         case syscall.DT_FIFO:
101                 typ = os.ModeNamedPipe
102         case syscall.DT_SOCK:
103                 typ = os.ModeSocket
104         case syscall.DT_UNKNOWN:
105                 typ = unknownFileMode
106         default:
107                 // Skip weird things.
108                 // It's probably a DT_WHT (http://lwn.net/Articles/325369/)
109                 // or something. Revisit if/when this package is moved outside
110                 // of goimports. goimports only cares about regular files,
111                 // symlinks, and directories.
112                 return
113         }
114
115         nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0]))
116         nameLen := direntNamlen(dirent)
117
118         // Special cases for common things:
119         if nameLen == 1 && nameBuf[0] == '.' {
120                 name = "."
121         } else if nameLen == 2 && nameBuf[0] == '.' && nameBuf[1] == '.' {
122                 name = ".."
123         } else {
124                 name = string(nameBuf[:nameLen])
125         }
126         return
127 }