Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/finder/fs/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 5 kB image not shown  

Quelle  readdir.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs 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, 0100)

 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.Dirent{}.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
}

[Dauer der Verarbeitung: 0.28 Sekunden, vorverarbeitet 2026-06-28]