]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/syscall/syscall_darwin.go
syscall: provide and use ioctlPtr for all BSD platforms
[gostls13.git] / src / syscall / syscall_darwin.go
index 4d6aa4fcf23e482c7dd6233f91d2d3e13026f8e6..2e13b57cd32e759a0df6476185af22da2c84e80b 100644 (file)
 package syscall
 
 import (
-       errorspkg "errors"
+       "internal/abi"
        "unsafe"
 )
 
-const ImplementsGetwd = true
-
-func Getwd() (string, error) {
-       buf := make([]byte, 2048)
-       attrs, err := getAttrList(".", attrList{CommonAttr: attrCmnFullpath}, buf, 0)
-       if err == nil && len(attrs) == 1 && len(attrs[0]) >= 2 {
-               wd := string(attrs[0])
-               // Sanity check that it's an absolute path and ends
-               // in a null byte, which we then strip.
-               if wd[0] == '/' && wd[len(wd)-1] == 0 {
-                       return wd[:len(wd)-1], nil
-               }
-       }
-       // If pkg/os/getwd.go gets ENOTSUP, it will fall back to the
-       // slow algorithm.
-       return "", ENOTSUP
-}
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+
+var dupTrampoline = abi.FuncPCABI0(libc_dup2_trampoline)
 
 type SockaddrDatalink struct {
        Len    uint8
@@ -87,89 +76,21 @@ func direntNamlen(buf []byte) (uint64, bool) {
        return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
 }
 
-//sys   ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
 func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) }
 func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) }
 
-const (
-       attrBitMapCount = 5
-       attrCmnModtime  = 0x00000400
-       attrCmnAcctime  = 0x00001000
-       attrCmnFullpath = 0x08000000
-)
-
-type attrList struct {
-       bitmapCount uint16
-       _           uint16
-       CommonAttr  uint32
-       VolAttr     uint32
-       DirAttr     uint32
-       FileAttr    uint32
-       Forkattr    uint32
-}
-
-func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) (attrs [][]byte, err error) {
-       if len(attrBuf) < 4 {
-               return nil, errorspkg.New("attrBuf too small")
-       }
-       attrList.bitmapCount = attrBitMapCount
-
-       var _p0 *byte
-       _p0, err = BytePtrFromString(path)
-       if err != nil {
-               return nil, err
-       }
-
-       _, _, e1 := Syscall6(
-               SYS_GETATTRLIST,
-               uintptr(unsafe.Pointer(_p0)),
-               uintptr(unsafe.Pointer(&attrList)),
-               uintptr(unsafe.Pointer(&attrBuf[0])),
-               uintptr(len(attrBuf)),
-               uintptr(options),
-               0,
-       )
-       if e1 != 0 {
-               return nil, e1
-       }
-       size := *(*uint32)(unsafe.Pointer(&attrBuf[0]))
-
-       // dat is the section of attrBuf that contains valid data,
-       // without the 4 byte length header. All attribute offsets
-       // are relative to dat.
-       dat := attrBuf
-       if int(size) < len(attrBuf) {
-               dat = dat[:size]
-       }
-       dat = dat[4:] // remove length prefix
-
-       for i := uint32(0); int(i) < len(dat); {
-               header := dat[i:]
-               if len(header) < 8 {
-                       return attrs, errorspkg.New("truncated attribute header")
-               }
-               datOff := *(*int32)(unsafe.Pointer(&header[0]))
-               attrLen := *(*uint32)(unsafe.Pointer(&header[4]))
-               if datOff < 0 || uint32(datOff)+attrLen > uint32(len(dat)) {
-                       return attrs, errorspkg.New("truncated results; attrBuf too small")
-               }
-               end := uint32(datOff) + attrLen
-               attrs = append(attrs, dat[datOff:end])
-               i = end
-               if r := i % 4; r != 0 {
-                       i += (4 - r)
-               }
-       }
-       return
-}
-
-//sysnb pipe() (r int, w int, err error)
+//sysnb pipe(p *[2]int32) (err error)
 
 func Pipe(p []int) (err error) {
        if len(p) != 2 {
                return EINVAL
        }
-       p[0], p[1], err = pipe()
+       var q [2]int32
+       err = pipe(&q)
+       if err == nil {
+               p[0] = int(q[0])
+               p[1] = int(q[1])
+       }
        return
 }
 
@@ -180,7 +101,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
                _p0 = unsafe.Pointer(&buf[0])
                bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
        }
-       r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags))
+       r0, _, e1 := syscall(abi.FuncPCABI0(libc_getfsstat_trampoline), uintptr(_p0), bufsize, uintptr(flags))
        n = int(r0)
        if e1 != 0 {
                err = e1
@@ -188,38 +109,11 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
        return
 }
 
-func setattrlistTimes(path string, times []Timespec) error {
-       _p0, err := BytePtrFromString(path)
-       if err != nil {
-               return err
-       }
+func libc_getfsstat_trampoline()
 
-       var attrList attrList
-       attrList.bitmapCount = attrBitMapCount
-       attrList.CommonAttr = attrCmnModtime | attrCmnAcctime
-
-       // order is mtime, atime: the opposite of Chtimes
-       attributes := [2]Timespec{times[1], times[0]}
-       const options = 0
-       _, _, e1 := Syscall6(
-               SYS_SETATTRLIST,
-               uintptr(unsafe.Pointer(_p0)),
-               uintptr(unsafe.Pointer(&attrList)),
-               uintptr(unsafe.Pointer(&attributes)),
-               uintptr(unsafe.Sizeof(attributes)),
-               uintptr(options),
-               0,
-       )
-       if e1 != 0 {
-               return e1
-       }
-       return nil
-}
+//go:cgo_import_dynamic libc_getfsstat getfsstat "/usr/lib/libSystem.B.dylib"
 
-func utimensat(dirfd int, path string, times *[2]Timespec, flag int) error {
-       // Darwin doesn't support SYS_UTIMENSAT
-       return ENOSYS
-}
+//sys  utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error)
 
 /*
  * Wrapped
@@ -240,6 +134,7 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
 //sys  Chown(path string, uid int, gid int) (err error)
 //sys  Chroot(path string) (err error)
 //sys  Close(fd int) (err error)
+//sys  closedir(dir uintptr) (err error)
 //sys  Dup(fd int) (nfd int, err error)
 //sys  Dup2(from int, to int) (err error)
 //sys  Exchangedata(path1 string, path2 string, options int) (err error)
@@ -249,11 +144,9 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
 //sys  Fchown(fd int, uid int, gid int) (err error)
 //sys  Flock(fd int, how int) (err error)
 //sys  Fpathconf(fd int, name int) (val int, err error)
-//sys  Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
-//sys  Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
 //sys  Fsync(fd int) (err error)
+//  Fsync is not called for os.File.Sync(). Please see internal/poll/fd_fsync_darwin.go
 //sys  Ftruncate(fd int, length int64) (err error)
-//sys  Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
 //sys  Getdtablesize() (size int)
 //sysnb        Getegid() (egid int)
 //sysnb        Geteuid() (uid int)
@@ -272,25 +165,26 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
 //sys  Lchown(path string, uid int, gid int) (err error)
 //sys  Link(path string, link string) (err error)
 //sys  Listen(s int, backlog int) (err error)
-//sys  Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
 //sys  Mkdir(path string, mode uint32) (err error)
 //sys  Mkfifo(path string, mode uint32) (err error)
 //sys  Mknod(path string, mode uint32, dev int) (err error)
 //sys  Mlock(b []byte) (err error)
 //sys  Mlockall(flags int) (err error)
 //sys  Mprotect(b []byte, prot int) (err error)
+//sys  msync(b []byte, flags int) (err error)
 //sys  Munlock(b []byte) (err error)
 //sys  Munlockall() (err error)
 //sys  Open(path string, mode int, perm uint32) (fd int, err error)
 //sys  Pathconf(path string, name int) (val int, err error)
-//sys  Pread(fd int, p []byte, offset int64) (n int, err error)
-//sys  Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys  pread(fd int, p []byte, offset int64) (n int, err error)
+//sys  pwrite(fd int, p []byte, offset int64) (n int, err error)
 //sys  read(fd int, p []byte) (n int, err error)
+//sys  readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
 //sys  Readlink(path string, buf []byte) (n int, err error)
 //sys  Rename(from string, to string) (err error)
 //sys  Revoke(path string) (err error)
 //sys  Rmdir(path string) (err error)
-//sys  Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
+//sys  Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_lseek
 //sys  Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
 //sys  Setegid(egid int) (err error)
 //sysnb        Seteuid(euid int) (err error)
@@ -301,12 +195,10 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
 //sys  Setprivexec(flag int) (err error)
 //sysnb        Setregid(rgid int, egid int) (err error)
 //sysnb        Setreuid(ruid int, euid int) (err error)
-//sysnb        Setrlimit(which int, lim *Rlimit) (err error)
+//sysnb        setrlimit(which int, lim *Rlimit) (err error)
 //sysnb        Setsid() (pid int, err error)
 //sysnb        Settimeofday(tp *Timeval) (err error)
 //sysnb        Setuid(uid int) (err error)
-//sys  Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
-//sys  Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
 //sys  Symlink(path string, link string) (err error)
 //sys  Sync() (err error)
 //sys  Truncate(path string, length int64) (err error)
@@ -315,7 +207,117 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
 //sys  Unlink(path string) (err error)
 //sys  Unmount(path string, flags int) (err error)
 //sys  write(fd int, p []byte) (n int, err error)
+//sys  writev(fd int, iovecs []Iovec) (cnt uintptr, err error)
 //sys   mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
 //sys   munmap(addr uintptr, length uintptr) (err error)
-//sys  readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
-//sys  writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
+//sysnb fork() (pid int, err error)
+//sysnb execve(path *byte, argv **byte, envp **byte) (err error)
+//sysnb exit(res int) (err error)
+//sys  sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error)
+//sys   unlinkat(fd int, path string, flags int) (err error)
+//sys   openat(fd int, path string, flags int, perm uint32) (fdret int, err error)
+//sys  getcwd(buf []byte) (n int, err error)
+
+func init() {
+       execveDarwin = execve
+}
+
+func fdopendir(fd int) (dir uintptr, err error) {
+       r0, _, e1 := syscallPtr(abi.FuncPCABI0(libc_fdopendir_trampoline), uintptr(fd), 0, 0)
+       dir = r0
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+func libc_fdopendir_trampoline()
+
+//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"
+
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+       r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+       n = int(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+       // Simulate Getdirentries using fdopendir/readdir_r/closedir.
+       // We store the number of entries to skip in the seek
+       // offset of fd. See issue #31368.
+       // It's not the full required semantics, but should handle the case
+       // of calling Getdirentries or ReadDirent repeatedly.
+       // It won't handle assigning the results of lseek to *basep, or handle
+       // the directory being edited underfoot.
+       skip, err := Seek(fd, 0, 1 /* SEEK_CUR */)
+       if err != nil {
+               return 0, err
+       }
+
+       // We need to duplicate the incoming file descriptor
+       // because the caller expects to retain control of it, but
+       // fdopendir expects to take control of its argument.
+       // Just Dup'ing the file descriptor is not enough, as the
+       // result shares underlying state. Use openat to make a really
+       // new file descriptor referring to the same directory.
+       fd2, err := openat(fd, ".", O_RDONLY, 0)
+       if err != nil {
+               return 0, err
+       }
+       d, err := fdopendir(fd2)
+       if err != nil {
+               Close(fd2)
+               return 0, err
+       }
+       defer closedir(d)
+
+       var cnt int64
+       for {
+               var entry Dirent
+               var entryp *Dirent
+               e := readdir_r(d, &entry, &entryp)
+               if e != 0 {
+                       return n, errnoErr(e)
+               }
+               if entryp == nil {
+                       break
+               }
+               if skip > 0 {
+                       skip--
+                       cnt++
+                       continue
+               }
+               reclen := int(entry.Reclen)
+               if reclen > len(buf) {
+                       // Not enough room. Return for now.
+                       // The counter will let us know where we should start up again.
+                       // Note: this strategy for suspending in the middle and
+                       // restarting is O(n^2) in the length of the directory. Oh well.
+                       break
+               }
+               // Copy entry into return buffer.
+               copy(buf, unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen))
+               buf = buf[reclen:]
+               n += reclen
+               cnt++
+       }
+       // Set the seek offset of the input fd to record
+       // how many files we've already returned.
+       _, err = Seek(fd, cnt, 0 /* SEEK_SET */)
+       if err != nil {
+               return n, err
+       }
+
+       return n, nil
+}
+
+// Implemented in the runtime package (runtime/sys_darwin.go)
+func syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)