| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- // +build !windows
- package godirwalk
- import (
- "os"
- "syscall"
- "unsafe"
- )
- // MinimumScratchBufferSize specifies the minimum size of the scratch buffer
- // that ReadDirents, ReadDirnames, Scanner, and Walk will use when reading file
- // entries from the operating system. During program startup it is initialized
- // to the result from calling `os.Getpagesize()` for non Windows environments,
- // and 0 for Windows.
- var MinimumScratchBufferSize = os.Getpagesize()
- func newScratchBuffer() []byte { return make([]byte, MinimumScratchBufferSize) }
- func readDirents(osDirname string, scratchBuffer []byte) ([]*Dirent, error) {
- var entries []*Dirent
- var workBuffer []byte
- dh, err := os.Open(osDirname)
- if err != nil {
- return nil, err
- }
- fd := int(dh.Fd())
- if len(scratchBuffer) < MinimumScratchBufferSize {
- scratchBuffer = newScratchBuffer()
- }
- var sde syscall.Dirent
- for {
- if len(workBuffer) == 0 {
- n, err := syscall.ReadDirent(fd, scratchBuffer)
- // n, err := unix.ReadDirent(fd, scratchBuffer)
- if err != nil {
- if err == syscall.EINTR /* || err == unix.EINTR */ {
- continue
- }
- _ = dh.Close()
- return nil, err
- }
- if n <= 0 { // end of directory: normal exit
- if err = dh.Close(); err != nil {
- return nil, err
- }
- return entries, nil
- }
- workBuffer = scratchBuffer[:n] // trim work buffer to number of bytes read
- }
- copy((*[unsafe.Sizeof(syscall.Dirent{})]byte)(unsafe.Pointer(&sde))[:], workBuffer)
- workBuffer = workBuffer[reclen(&sde):] // advance buffer for next iteration through loop
- if inoFromDirent(&sde) == 0 {
- continue // inode set to 0 indicates an entry that was marked as deleted
- }
- nameSlice := nameFromDirent(&sde)
- nameLength := len(nameSlice)
- if nameLength == 0 || (nameSlice[0] == '.' && (nameLength == 1 || (nameLength == 2 && nameSlice[1] == '.'))) {
- continue
- }
- childName := string(nameSlice)
- mt, err := modeTypeFromDirent(&sde, osDirname, childName)
- if err != nil {
- _ = dh.Close()
- return nil, err
- }
- entries = append(entries, &Dirent{name: childName, path: osDirname, modeType: mt})
- }
- }
- func readDirnames(osDirname string, scratchBuffer []byte) ([]string, error) {
- var entries []string
- var workBuffer []byte
- var sde *syscall.Dirent
- dh, err := os.Open(osDirname)
- if err != nil {
- return nil, err
- }
- fd := int(dh.Fd())
- if len(scratchBuffer) < MinimumScratchBufferSize {
- scratchBuffer = newScratchBuffer()
- }
- for {
- if len(workBuffer) == 0 {
- n, err := syscall.ReadDirent(fd, scratchBuffer)
- // n, err := unix.ReadDirent(fd, scratchBuffer)
- if err != nil {
- if err == syscall.EINTR /* || err == unix.EINTR */ {
- continue
- }
- _ = dh.Close()
- return nil, err
- }
- if n <= 0 { // end of directory: normal exit
- if err = dh.Close(); err != nil {
- return nil, err
- }
- return entries, nil
- }
- workBuffer = scratchBuffer[:n] // trim work buffer to number of bytes read
- }
- sde = (*syscall.Dirent)(unsafe.Pointer(&workBuffer[0])) // point entry to first syscall.Dirent in buffer
- // Handle first entry in the work buffer.
- workBuffer = workBuffer[reclen(sde):] // advance buffer for next iteration through loop
- if inoFromDirent(sde) == 0 {
- continue // inode set to 0 indicates an entry that was marked as deleted
- }
- nameSlice := nameFromDirent(sde)
- nameLength := len(nameSlice)
- if nameLength == 0 || (nameSlice[0] == '.' && (nameLength == 1 || (nameLength == 2 && nameSlice[1] == '.'))) {
- continue
- }
- entries = append(entries, string(nameSlice))
- }
- }
|