Spracherkennung für: .go vermutete Sprache: Abap {ABAP[38] Fortran[34] C[30]} [Methode: maximale Elemente, drei Dimensionen]
// Copyright
2017 Google Inc. All rights reserved.
//
// Licensed
under the Apache License, Version
2.
0 (the
"License");
// you may not use this
file except
in compliance with the License.
// You may obtain a
copy of the License
at
//
//
http://www.apache.org/licenses/LICENSE-2.
0
//
// Unless required
by applicable law
or agreed
to in writing, software
// distributed
under the License
is distributed
on an
"AS IS" BASIS,
// WITHOUT WARRANTIES
OR CONDITIONS
OF ANY KIND, either express
or implied.
// See the License
for the specific
language governing permissions
and
// limitations
under the License.
package fs
// This
is based
on the readdir
implementation from Go
1.
9:
// Copyright
2009 The Go Authors. All rights reserved.
// Use
of this source
code is governed
by a BSD-style
// license that can be found
in the LICENSE
file.
import (
"os"
"syscall"
"unsafe"
)
const (
blockSize =
4096
)
func readdir(path
string) ([]DirEntryInfo, error) {
f, err := os.
Open(path)
defer f.
Close()
if err != nil {
return nil, err
}
// This implicitly switches the fd
to non-blocking mode, which
is less efficient than what
//
file.ReadDir does since it will keep a thread blocked
and not just a goroutine.
fd := int(f.Fd())
buf := make([]byte, blockSize)
entries := make([]
*dirEntryInfo, 0, 100)
for {
n, errno := syscall.ReadDirent(fd, buf)
if errno != nil {
err = os.NewSyscallError(
"readdirent", errno)
break
}
if n <=
0 {
break // EOF
}
entries = parseDirent(buf[:n], entries)
}
ret := make([]DirEntryInfo,
0, len(entries))
for _, entry := range entries {
if !entry.modeExists {
mode, lerr := lstatFileMode(path +
"/" + entry.name)
if os.IsNotExist(lerr) {
//
File disappeared
between readdir + stat.
// Just treat it
as if it didn
't exist.
continue
}
if lerr != nil {
return ret, lerr
}
entry.mode = mode
entry.modeExists = true
}
ret =
append(ret, entry)
}
return ret, err
}
func parseDirent(buf []byte, entries []
*dirEntryInfo) []*dirEntryInfo {
for len(buf) >
0 {
reclen, ok := direntReclen(buf)
if !ok || reclen > uint64(len(buf)) {
return entries
}
rec := buf[:reclen]
buf = buf[reclen:]
ino, ok := direntIno(rec)
if !ok {
break
}
if ino ==
0 { //
File absent
in directory.
continue
}
typ, ok := direntType(rec)
if !ok {
break
}
const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name))
namlen, ok := direntNamlen(rec)
if !ok || namoff+namlen > uint64(len(rec)) {
break
}
name := rec[namoff : namoff+namlen]
for i, c := range name {
if c ==
0 {
name = name[:i]
break
}
}
//
Check for useless names before allocating a
string.
if string(name) ==
"." ||
string(name) ==
".." {
continue
}
mode, modeExists := direntTypeToFileMode(typ)
entries =
append(entries, &dirEntryInfo{
string(name), mode, modeExists})
}
return entries
}
func direntIno(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Ino), unsafe.Sizeof(syscall.Di
rent{}.Ino))
}
func direntType(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Type), unsafe.Sizeof(syscall.Dirent{}.Type))
}
func direntReclen(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Reclen), unsafe.Sizeof(syscall.Dirent{}.Reclen))
}
func direntNamlen(buf []byte) (uint64, bool) {
reclen, ok := direntReclen(buf)
if !ok {
return 0, false
}
return reclen - uint64(unsafe.Offsetof(syscall.Dirent{}.Name)), true
}
// readInt returns the size-bytes unsigned integer in native byte order at offset off.
func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
if len(b) < int(off+size) {
return 0, false
}
return readIntLE(b[off:], size), true
}
func readIntLE(b []byte, size uintptr) uint64 {
switch size {
case 1:
return uint64(b[0])
case 2:
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8
case 4:
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
case 8:
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
default:
panic("syscall: readInt with unsupported size")
}
}
// If the directory entry doesn't specify the type, fall back to using lstat to get the type.
func lstatFileMode(name string) (os.FileMode, error) {
stat, err := os.Lstat(name)
if err != nil {
return 0, err
}
return stat.Mode() & (os.ModeType | os.ModeCharDevice), nil
}
// from Linux and Darwin dirent.h
const (
DT_UNKNOWN = 0
DT_FIFO = 1
DT_CHR = 2
DT_DIR = 4
DT_BLK = 6
DT_REG = 8
DT_LNK = 10
DT_SOCK = 12
)
func direntTypeToFileMode(typ uint64) (os.FileMode, bool) {
exists := true
var mode os.FileMode
switch typ {
case DT_UNKNOWN:
exists = false
case DT_FIFO:
mode = os.ModeNamedPipe
case DT_CHR:
mode = os.ModeDevice | os.ModeCharDevice
case DT_DIR:
mode = os.ModeDir
case DT_BLK:
mode = os.ModeDevice
case DT_REG:
mode = 0
case DT_LNK:
mode = os.ModeSymlink
case DT_SOCK:
mode = os.ModeSocket
default:
exists = false
}
return mode, exists
}