132 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			132 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
// +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))
 | 
						|
	}
 | 
						|
}
 |