Commit b07e4d95 authored by Alex Brainman's avatar Alex Brainman Committed by Russ Cox
Browse files

os: mingw version of Readdir() and Stat() implemented

R=rsc
CC=golang-dev
https://golang.org/cl/851045
parent 30f981d9
master go1.12-nxd go18-fannkuch-entryshift go19 x/sched y/unqotechar-err weekly.2012-03-27 weekly.2012-03-22 weekly.2012-03-13 weekly.2012-03-04 weekly.2012-02-22 weekly.2012-02-14 weekly.2012-02-07 weekly.2012-01-27 weekly.2012-01-20 weekly.2012-01-15 weekly.2011-12-22 weekly.2011-12-14 weekly.2011-12-06 weekly.2011-12-02 weekly.2011-12-01 weekly.2011-11-18 weekly.2011-11-09 weekly.2011-11-08 weekly.2011-11-02 weekly.2011-11-01 weekly.2011-10-26 weekly.2011-10-25 weekly.2011-10-18 weekly.2011-10-06 weekly.2011-09-21 weekly.2011-09-16 weekly.2011-09-07 weekly.2011-09-01 weekly.2011-08-17 weekly.2011-08-10 weekly.2011-07-29 weekly.2011-07-19 weekly.2011-07-07 weekly.2011-06-23 weekly.2011-06-16 weekly.2011-06-09 weekly.2011-06-02 weekly.2011-05-22 weekly.2011-04-27 weekly.2011-04-13 weekly.2011-04-04 weekly.2011-03-28 weekly.2011-03-15 weekly.2011-03-07.1 weekly.2011-03-07 weekly.2011-02-24 weekly.2011-02-15 weekly.2011-02-01.1 weekly.2011-02-01 weekly.2011-01-20 weekly.2011-01-19 weekly.2011-01-12 weekly.2011-01-06 weekly.2010-12-22 weekly.2010-12-15.1 weekly.2010-12-15 weekly.2010-12-08 weekly.2010-12-02 weekly.2010-11-23 weekly.2010-11-10 weekly.2010-11-02 weekly.2010-10-27 weekly.2010-10-20 weekly.2010-10-13.1 weekly.2010-10-13 weekly.2010-09-29 weekly.2010-09-22 weekly.2010-09-15 weekly.2010-09-06 weekly.2010-08-25 weekly.2010-08-11 weekly.2010-08-04 weekly.2010-07-29 weekly.2010-07-14 weekly.2010-07-01 weekly.2010-06-21 weekly.2010-06-09 weekly.2010-05-27 weekly.2010-05-04 weekly.2010-04-27 weekly.2010-04-13 weekly release.r60.3 release.r60.2 release.r60.1 release.r60 release.r59 release.r58.2 release.r58.1 release.r58 release.r57.2 release.r57.1 release.r57 release.r56 go1.9 go1.9rc2 go1.9rc1 go1.9beta2 go1.9beta1 go1.8.3 go1.8.2 go1.8.1 go1.8 go1.8rc3 go1.8rc2 go1.8rc1 go1.8beta2 go1.8beta1 go1.7.6 go1.7.5 go1.7.4 go1.7.3 go1.7.2 go1.7.1 go1.7 go1.7rc6 go1.7rc5 go1.7rc4 go1.7rc3 go1.7rc2 go1.7rc1 go1.7beta2 go1.7beta1 go1.6.4 go1.6.3 go1.6.2 go1.6.1 go1.6 go1.6rc2 go1.6rc1 go1.6beta2 go1.6beta1 go1.5.4 go1.5.3 go1.5.2 go1.5.1 go1.5 go1.5rc1 go1.5beta3 go1.5beta2 go1.5beta1 go1.4.3 go1.4.2 go1.4.1 go1.4 go1.4rc2 go1.4rc1 go1.4beta1 go1.3.3 go1.3.2 go1.3.1 go1.3 go1.3rc2 go1.3rc1 go1.3beta2 go1.3beta1 go1.2.2 go1.2.1 go1.2 go1.2rc5 go1.2rc4 go1.2rc3 go1.2rc2 go1.1.2 go1.1.1 go1.1 go1.1rc3 go1.1rc2 go1.0.3 go1.0.2 go1.0.1 go1
No related merge requests found
Showing with 345 additions and 110 deletions
+345 -110
...@@ -19,4 +19,21 @@ GOFILES=\ ...@@ -19,4 +19,21 @@ GOFILES=\
time.go\ time.go\
types.go\ types.go\
GOFILES_freebsd=\
file_unix.go\
GOFILES_darwin=\
file_unix.go\
GOFILES_linux=\
file_unix.go\
GOFILES_nacl=\
file_unix.go\
GOFILES_mingw=\
file_mingw.go\
GOFILES+=$(GOFILES_$(GOOS))
include ../../Make.pkg include ../../Make.pkg
...@@ -5,5 +5,13 @@ ...@@ -5,5 +5,13 @@
package os package os
func (file *File) Readdirnames(count int) (names []string, err Error) { func (file *File) Readdirnames(count int) (names []string, err Error) {
panic("windows Readdirnames not implemented") fis, e := file.Readdir(count)
if e != nil {
return nil, e
}
names = make([]string, len(fis))
for i, fi := range fis {
names[i] = fi.Name
}
return names, nil
} }
...@@ -11,13 +11,6 @@ import ( ...@@ -11,13 +11,6 @@ import (
"syscall" "syscall"
) )
// Auxiliary information if the File describes a directory
type dirInfo struct {
buf []byte // buffer for directory I/O
nbuf int // length of buf; return value from Getdirentries
bufp int // location of next record in buf.
}
// File represents an open file descriptor. // File represents an open file descriptor.
type File struct { type File struct {
fd int fd int
...@@ -68,41 +61,6 @@ const ( ...@@ -68,41 +61,6 @@ const (
O_CREATE = O_CREAT // create a new file if none exists. O_CREATE = O_CREAT // create a new file if none exists.
) )
// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.)
// if applicable. If successful, methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
func Open(name string, flag int, perm int) (file *File, err Error) {
r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
if e != 0 {
return nil, &PathError{"open", name, Errno(e)}
}
// There's a race here with fork/exec, which we are
// content to live with. See ../syscall/exec.go
if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
syscall.CloseOnExec(r)
}
return NewFile(r, name), nil
}
// Close closes the File, rendering it unusable for I/O.
// It returns an Error, if any.
func (file *File) Close() Error {
if file == nil || file.fd < 0 {
return EINVAL
}
var err Error
if e := syscall.Close(file.fd); e != 0 {
err = &PathError{"close", file.name, Errno(e)}
}
file.fd = -1 // so it can't be closed again
// no need for a finalizer anymore
runtime.SetFinalizer(file, nil)
return err
}
type eofError int type eofError int
func (eofError) String() string { return "EOF" } func (eofError) String() string { return "EOF" }
...@@ -302,34 +260,6 @@ func Lstat(name string) (fi *FileInfo, err Error) { ...@@ -302,34 +260,6 @@ func Lstat(name string) (fi *FileInfo, err Error) {
return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
} }
// Readdir reads the contents of the directory associated with file and
// returns an array of up to count FileInfo structures, as would be returned
// by Stat, in directory order. Subsequent calls on the same file will yield
// further FileInfos.
// A negative count means to read until EOF.
// Readdir returns the array and an Error, if any.
func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
dirname := file.name
if dirname == "" {
dirname = "."
}
dirname += "/"
names, err1 := file.Readdirnames(count)
if err1 != nil {
return nil, err1
}
fi = make([]FileInfo, len(names))
for i, filename := range names {
fip, err := Lstat(dirname + filename)
if fip == nil || err != nil {
fi[i].Name = filename // rest is already zeroed out
} else {
fi[i] = *fip
}
}
return
}
// Chdir changes the current working directory to the named directory. // Chdir changes the current working directory to the named directory.
func Chdir(dir string) Error { func Chdir(dir string) Error {
if e := syscall.Chdir(dir); e != 0 { if e := syscall.Chdir(dir); e != 0 {
......
// 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.
// The os package provides a platform-independent interface to operating
// system functionality. The design is Unix-like.
package os
import (
"runtime"
"syscall"
)
// Auxiliary information if the File describes a directory
type dirInfo struct {
stat syscall.Stat_t
usefirststat bool
}
func (file *File) isdir() bool { return file != nil && file.dirinfo != nil }
func openFile(name string, flag int, perm int) (file *File, err Error) {
r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
if e != 0 {
return nil, &PathError{"open", name, Errno(e)}
}
// There's a race here with fork/exec, which we are
// content to live with. See ../syscall/exec.go
if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
syscall.CloseOnExec(r)
}
return NewFile(r, name), nil
}
func openDir(name string) (file *File, err Error) {
d := new(dirInfo)
r, e := syscall.FindFirstFile(syscall.StringToUTF16Ptr(name+"\\*"), &d.stat.Windata)
if e != 0 {
return nil, &PathError{"open", name, Errno(e)}
}
f := NewFile(int(r), name)
d.usefirststat = true
f.dirinfo = d
return f, nil
}
// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.)
// if applicable. If successful, methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
func Open(name string, flag int, perm int) (file *File, err Error) {
// TODO(brainman): not sure about my logic of assuming it is dir first, then fall back to file
r, e := openDir(name)
if e == nil {
return r, nil
}
r, e = openFile(name, flag|syscall.O_CLOEXEC, perm)
if e == nil {
return r, nil
}
return nil, e
}
// Close closes the File, rendering it unusable for I/O.
// It returns an Error, if any.
func (file *File) Close() Error {
if file == nil || file.fd < 0 {
return EINVAL
}
var e int
if file.isdir() {
_, e = syscall.FindClose(int32(file.fd))
} else {
_, e = syscall.CloseHandle(int32(file.fd))
}
var err Error
if e != 0 {
err = &PathError{"close", file.name, Errno(e)}
}
file.fd = -1 // so it can't be closed again
// no need for a finalizer anymore
runtime.SetFinalizer(file, nil)
return err
}
// Readdir reads the contents of the directory associated with file and
// returns an array of up to count FileInfo structures, as would be returned
// by Stat, in directory order. Subsequent calls on the same file will yield
// further FileInfos.
// A negative count means to read until EOF.
// Readdir returns the array and an Error, if any.
func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
di := file.dirinfo
size := count
if size < 0 {
size = 100
}
fi = make([]FileInfo, 0, size) // Empty with room to grow.
for count != 0 {
if di.usefirststat {
di.usefirststat = false
} else {
_, e := syscall.FindNextFile(int32(file.fd), &di.stat.Windata)
if e != 0 {
if e == syscall.ERROR_NO_MORE_FILES {
break
} else {
return nil, &PathError{"FindNextFile", file.name, Errno(e)}
}
}
}
var f FileInfo
fileInfoFromStat("", &f, &di.stat, &di.stat)
if f.Name == "." || f.Name == ".." { // Useless names
continue
}
count--
if len(fi) == cap(fi) {
nfi := make([]FileInfo, len(fi), 2*len(fi))
for i := 0; i < len(fi); i++ {
nfi[i] = fi[i]
}
fi = nfi
}
fi = fi[0 : len(fi)+1]
fi[len(fi)-1] = f
}
return fi, nil
}
// 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.
// The os package provides a platform-independent interface to operating
// system functionality. The design is Unix-like.
package os
import (
"runtime"
"syscall"
)
// Auxiliary information if the File describes a directory
type dirInfo struct {
buf []byte // buffer for directory I/O
nbuf int // length of buf; return value from Getdirentries
bufp int // location of next record in buf.
}
// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.)
// if applicable. If successful, methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
func Open(name string, flag int, perm int) (file *File, err Error) {
r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
if e != 0 {
return nil, &PathError{"open", name, Errno(e)}
}
// There's a race here with fork/exec, which we are
// content to live with. See ../syscall/exec.go
if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
syscall.CloseOnExec(r)
}
return NewFile(r, name), nil
}
// Close closes the File, rendering it unusable for I/O.
// It returns an Error, if any.
func (file *File) Close() Error {
if file == nil || file.fd < 0 {
return EINVAL
}
var err Error
if e := syscall.Close(file.fd); e != 0 {
err = &PathError{"close", file.name, Errno(e)}
}
file.fd = -1 // so it can't be closed again
// no need for a finalizer anymore
runtime.SetFinalizer(file, nil)
return err
}
// Readdir reads the contents of the directory associated with file and
// returns an array of up to count FileInfo structures, as would be returned
// by Stat, in directory order. Subsequent calls on the same file will yield
// further FileInfos.
// A negative count means to read until EOF.
// Readdir returns the array and an Error, if any.
func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
dirname := file.name
if dirname == "" {
dirname = "."
}
dirname += "/"
names, err1 := file.Readdirnames(count)
if err1 != nil {
return nil, err1
}
fi = make([]FileInfo, len(names))
for i, filename := range names {
fip, err := Lstat(dirname + filename)
if fip == nil || err != nil {
fi[i].Name = filename // rest is already zeroed out
} else {
fi[i] = *fip
}
}
return
}
...@@ -6,10 +6,25 @@ package os ...@@ -6,10 +6,25 @@ package os
import "syscall" import "syscall"
func isSymlink(stat *syscall.Stat_t) bool {
panic("windows isSymlink not implemented")
}
func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo { func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
panic("windows fileInfoFromStat not implemented") fi.Mode = 0
if stat.Windata.FileAttributes == syscall.FILE_ATTRIBUTE_DIRECTORY {
fi.Mode = fi.Mode | syscall.S_IFDIR
}
if stat.Windata.FileAttributes == syscall.FILE_ATTRIBUTE_NORMAL {
fi.Mode = fi.Mode | syscall.S_IFREG
}
if stat.Windata.FileAttributes == syscall.FILE_ATTRIBUTE_READONLY {
fi.Mode = fi.Mode | 0444
} else {
fi.Mode = fi.Mode | 0666
}
fi.Size = uint64(stat.Windata.FileSizeHigh)<<32 + uint64(stat.Windata.FileSizeLow)
fi.Name = string(syscall.UTF16ToString(stat.Windata.FileName[0:]))
fi.FollowedSymlink = false
// TODO(brainman): use CreationTime LastAccessTime LastWriteTime to prime following Dir fields
fi.Atime_ns = 0
fi.Mtime_ns = 0
fi.Ctime_ns = 0
return fi
} }
...@@ -57,8 +57,11 @@ func StringToUTF16(s string) []uint16 { return utf16.Encode([]int(s + "\x00")) } ...@@ -57,8 +57,11 @@ func StringToUTF16(s string) []uint16 { return utf16.Encode([]int(s + "\x00")) }
// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s, // UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
// with a terminating NUL removed. // with a terminating NUL removed.
func UTF16ToString(s []uint16) string { func UTF16ToString(s []uint16) string {
if n := len(s); n > 0 && s[n-1] == 0 { for i, v := range s {
s = s[0 : n-1] if v == 0 {
s = s[0:i]
break
}
} }
return string(utf16.Decode(s)) return string(utf16.Decode(s))
} }
...@@ -105,6 +108,9 @@ func getSysProcAddr(m uint32, pname string) uintptr { ...@@ -105,6 +108,9 @@ func getSysProcAddr(m uint32, pname string) uintptr {
//sys SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) [failretval=0xffffffff] //sys SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) [failretval=0xffffffff]
//sys CloseHandle(handle int32) (ok bool, errno int) //sys CloseHandle(handle int32) (ok bool, errno int)
//sys GetStdHandle(stdhandle int32) (handle int32, errno int) [failretval=-1] //sys GetStdHandle(stdhandle int32) (handle int32, errno int) [failretval=-1]
//sys FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int) [failretval=-1] = FindFirstFileW
//sys FindNextFile(handle int32, data *Win32finddata) (ok bool, errno int) = FindNextFileW
//sys FindClose(handle int32) (ok bool, errno int)
// syscall interface implementation for other packages // syscall interface implementation for other packages
...@@ -117,7 +123,7 @@ func Errstr(errno int) string { ...@@ -117,7 +123,7 @@ func Errstr(errno int) string {
if err != 0 { if err != 0 {
return "error " + str(errno) + " (FormatMessage failed with err=" + str(err) + ")" return "error " + str(errno) + " (FormatMessage failed with err=" + str(err) + ")"
} }
return UTF16ToString(b[0 : n-1]) return string(utf16.Decode(b[0 : n-1]))
} }
func Exit(code int) { ExitProcess(uint32(code)) } func Exit(code int) { ExitProcess(uint32(code)) }
...@@ -253,20 +259,31 @@ func getStdHandle(h int32) (fd int) { ...@@ -253,20 +259,31 @@ func getStdHandle(h int32) (fd int) {
return int(r) return int(r)
} }
func Stat(path string, stat *Stat_t) (errno int) {
h, e := FindFirstFile(StringToUTF16Ptr(path), &stat.Windata)
if e != 0 {
return e
}
defer FindClose(h)
stat.Mode = 0
return 0
}
func Lstat(path string, stat *Stat_t) (errno int) {
// no links on windows, just call Stat
return Stat(path, stat)
}
// TODO(brainman): fix all needed for os // TODO(brainman): fix all needed for os
const ( const (
SIGTRAP = 5 SIGTRAP = 5
) )
func Getdents(fd int, buf []byte) (n int, errno int) { return 0, EMINGW }
func Getpid() (pid int) { return -1 } func Getpid() (pid int) { return -1 }
func Getppid() (ppid int) { return -1 } func Getppid() (ppid int) { return -1 }
func Mkdir(path string, mode int) (errno int) { return EMINGW } func Mkdir(path string, mode int) (errno int) { return EMINGW }
func Lstat(path string, stat *Stat_t) (errno int) { return EMINGW }
func Stat(path string, stat *Stat_t) (errno int) { return EMINGW }
func Fstat(fd int, stat *Stat_t) (errno int) { return EMINGW } func Fstat(fd int, stat *Stat_t) (errno int) { return EMINGW }
func Chdir(path string) (errno int) { return EMINGW } func Chdir(path string) (errno int) { return EMINGW }
func Fchdir(fd int) (errno int) { return EMINGW } func Fchdir(fd int) (errno int) { return EMINGW }
......
...@@ -4,6 +4,4 @@ ...@@ -4,6 +4,4 @@
package syscall package syscall
// TODO(brainman): check Getpagesize
func Getpagesize() int { return 4096 } func Getpagesize() int { return 4096 }
...@@ -7,6 +7,7 @@ package syscall ...@@ -7,6 +7,7 @@ package syscall
const ( const (
ERROR_FILE_NOT_FOUND = 2 ERROR_FILE_NOT_FOUND = 2
ERROR_NO_MORE_FILES = 18
ERROR_INSUFFICIENT_BUFFER = 122 ERROR_INSUFFICIENT_BUFFER = 122
ERROR_MOD_NOT_FOUND = 126 ERROR_MOD_NOT_FOUND = 126
ERROR_PROC_NOT_FOUND = 127 ERROR_PROC_NOT_FOUND = 127
......
...@@ -20,6 +20,9 @@ var ( ...@@ -20,6 +20,9 @@ var (
procSetFilePointer = getSysProcAddr(modKERNEL32, "SetFilePointer") procSetFilePointer = getSysProcAddr(modKERNEL32, "SetFilePointer")
procCloseHandle = getSysProcAddr(modKERNEL32, "CloseHandle") procCloseHandle = getSysProcAddr(modKERNEL32, "CloseHandle")
procGetStdHandle = getSysProcAddr(modKERNEL32, "GetStdHandle") procGetStdHandle = getSysProcAddr(modKERNEL32, "GetStdHandle")
procFindFirstFileW = getSysProcAddr(modKERNEL32, "FindFirstFileW")
procFindNextFileW = getSysProcAddr(modKERNEL32, "FindNextFileW")
procFindClose = getSysProcAddr(modKERNEL32, "FindClose")
) )
func GetLastError() (lasterrno int) { func GetLastError() (lasterrno int) {
...@@ -165,3 +168,36 @@ func GetStdHandle(stdhandle int32) (handle int32, errno int) { ...@@ -165,3 +168,36 @@ func GetStdHandle(stdhandle int32) (handle int32, errno int) {
} }
return return
} }
func FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int) {
r0, _, e1 := Syscall(procFindFirstFileW, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0)
handle = int32(r0)
if handle == -1 {
errno = int(e1)
} else {
errno = 0
}
return
}
func FindNextFile(handle int32, data *Win32finddata) (ok bool, errno int) {
r0, _, e1 := Syscall(procFindNextFileW, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
ok = bool(r0 != 0)
if !ok {
errno = int(e1)
} else {
errno = 0
}
return
}
func FindClose(handle int32) (ok bool, errno int) {
r0, _, e1 := Syscall(procFindClose, uintptr(handle), 0, 0)
ok = bool(r0 != 0)
if !ok {
errno = int(e1)
} else {
errno = 0
}
return
}
...@@ -78,6 +78,8 @@ const ( ...@@ -78,6 +78,8 @@ const (
FORMAT_MESSAGE_FROM_SYSTEM = 4096 FORMAT_MESSAGE_FROM_SYSTEM = 4096
FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192 FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192
FORMAT_MESSAGE_MAX_WIDTH_MASK = 255 FORMAT_MESSAGE_MAX_WIDTH_MASK = 255
MAX_PATH = 260
) )
// Types // Types
...@@ -103,6 +105,29 @@ type Overlapped struct { ...@@ -103,6 +105,29 @@ type Overlapped struct {
HEvent *byte HEvent *byte
} }
type Filetime struct {
LowDateTime uint32
HighDateTime uint32
}
type Win32finddata struct {
FileAttributes uint32
CreationTime Filetime
LastAccessTime Filetime
LastWriteTime Filetime
FileSizeHigh uint32
FileSizeLow uint32
Reserved0 uint32
Reserved1 uint32
FileName [MAX_PATH - 1]uint16
AlternateFileName [13]uint16
}
type Stat_t struct {
Windata Win32finddata
Mode uint32
}
// TODO(brainman): fix all needed for os // TODO(brainman): fix all needed for os
const ( const (
...@@ -135,28 +160,3 @@ const ( ...@@ -135,28 +160,3 @@ const (
S_IWUSR = 0x80 S_IWUSR = 0x80
S_IXUSR = 0x40 S_IXUSR = 0x40
) )
type Stat_t struct {
Dev int64
Ino uint32
Mode uint32
Nlink uint32
Uid uint32
Gid uint32
__padding int32
Rdev int64
Size int32
Blksize int32
Blocks int32
Atime int32
Mtime int32
Ctime int32
}
type Dirent struct {
Ino uint32
Off int32
Reclen uint16
Name [256]int8
Pad0 [2]byte
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment