]> 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 f026a56d8b2934e50979f743c1f4fe48cf6662b1..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
@@ -53,7 +42,7 @@ func nametomib(name string) (mib []_C_int, err error) {
 
        // NOTE(rsc): It seems strange to set the buffer to have
        // size CTL_MAXNAME+2 but use only CTL_MAXNAME
-       // as the size.  I don't know why the +2 is here, but the
+       // as the size. I don't know why the +2 is here, but the
        // kernel uses +2 for its own implementation of this function.
        // I am scared that if we don't include the +2 here, the kernel
        // will silently write 2 words farther than we specify
@@ -75,116 +64,33 @@ func nametomib(name string) (mib []_C_int, err error) {
        return buf[0 : n/siz], nil
 }
 
-// ParseDirent parses up to max directory entries in buf,
-// appending the names to names.  It returns the number
-// bytes consumed from buf, the number of entries added
-// to names, and the new names slice.
-func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
-       origlen := len(buf)
-       for max != 0 && len(buf) > 0 {
-               dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
-               if dirent.Reclen == 0 {
-                       buf = nil
-                       break
-               }
-               buf = buf[dirent.Reclen:]
-               if dirent.Ino == 0 { // File absent in directory.
-                       continue
-               }
-               bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
-               var name = string(bytes[0:dirent.Namlen])
-               if name == "." || name == ".." { // Useless names
-                       continue
-               }
-               max--
-               count++
-               names = append(names, name)
-       }
-       return origlen - len(buf), count, names
+func direntIno(buf []byte) (uint64, bool) {
+       return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
 }
 
-//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
-       attrCmnFullpath = 0x08000000
-)
-
-type attrList struct {
-       bitmapCount uint16
-       _           uint16
-       CommonAttr  uint32
-       VolAttr     uint32
-       DirAttr     uint32
-       FileAttr    uint32
-       Forkattr    uint32
+func direntReclen(buf []byte) (uint64, bool) {
+       return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
 }
 
-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,
-       )
-       use(unsafe.Pointer(_p0))
-       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
+func direntNamlen(buf []byte) (uint64, bool) {
+       return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
 }
 
-//sysnb pipe() (r int, w int, 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) }
+
+//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
 }
 
@@ -195,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
@@ -203,6 +109,12 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
        return
 }
 
+func libc_getfsstat_trampoline()
+
+//go:cgo_import_dynamic libc_getfsstat getfsstat "/usr/lib/libSystem.B.dylib"
+
+//sys  utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error)
+
 /*
  * Wrapped
  */
@@ -222,21 +134,19 @@ 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)
-//sysnb        Dup(fd int) (nfd int, err error)
-//sysnb        Dup2(from int, to 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)
-//sys  Exit(code int)
 //sys  Fchdir(fd int) (err error)
 //sys  Fchflags(fd int, flags int) (err error)
 //sys  Fchmod(fd int, mode uint32) (err error)
 //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)
@@ -255,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)
@@ -284,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)
@@ -298,212 +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)
 
-/*
- * Unimplemented
- */
-// Profil
-// Sigaction
-// Sigprocmask
-// Getlogin
-// Sigpending
-// Sigaltstack
-// Ioctl
-// Reboot
-// Execve
-// Vfork
-// Sbrk
-// Sstk
-// Ovadvise
-// Mincore
-// Setitimer
-// Swapon
-// Select
-// Sigsuspend
-// Readv
-// Writev
-// Nfssvc
-// Getfh
-// Quotactl
-// Mount
-// Csops
-// Waitid
-// Add_profil
-// Kdebug_trace
-// Sigreturn
-// Mmap
-// Mlock
-// Munlock
-// Atsocket
-// Kqueue_from_portset_np
-// Kqueue_portset
-// Getattrlist
-// Setattrlist
-// Getdirentriesattr
-// Searchfs
-// Delete
-// Copyfile
-// Poll
-// Watchevent
-// Waitevent
-// Modwatch
-// Getxattr
-// Fgetxattr
-// Setxattr
-// Fsetxattr
-// Removexattr
-// Fremovexattr
-// Listxattr
-// Flistxattr
-// Fsctl
-// Initgroups
-// Posix_spawn
-// Nfsclnt
-// Fhopen
-// Minherit
-// Semsys
-// Msgsys
-// Shmsys
-// Semctl
-// Semget
-// Semop
-// Msgctl
-// Msgget
-// Msgsnd
-// Msgrcv
-// Shmat
-// Shmctl
-// Shmdt
-// Shmget
-// Shm_open
-// Shm_unlink
-// Sem_open
-// Sem_close
-// Sem_unlink
-// Sem_wait
-// Sem_trywait
-// Sem_post
-// Sem_getvalue
-// Sem_init
-// Sem_destroy
-// Open_extended
-// Umask_extended
-// Stat_extended
-// Lstat_extended
-// Fstat_extended
-// Chmod_extended
-// Fchmod_extended
-// Access_extended
-// Settid
-// Gettid
-// Setsgroups
-// Getsgroups
-// Setwgroups
-// Getwgroups
-// Mkfifo_extended
-// Mkdir_extended
-// Identitysvc
-// Shared_region_check_np
-// Shared_region_map_np
-// __pthread_mutex_destroy
-// __pthread_mutex_init
-// __pthread_mutex_lock
-// __pthread_mutex_trylock
-// __pthread_mutex_unlock
-// __pthread_cond_init
-// __pthread_cond_destroy
-// __pthread_cond_broadcast
-// __pthread_cond_signal
-// Setsid_with_pid
-// __pthread_cond_timedwait
-// Aio_fsync
-// Aio_return
-// Aio_suspend
-// Aio_cancel
-// Aio_error
-// Aio_read
-// Aio_write
-// Lio_listio
-// __pthread_cond_wait
-// Iopolicysys
-// Mlockall
-// Munlockall
-// __pthread_kill
-// __pthread_sigmask
-// __sigwait
-// __disable_threadsignal
-// __pthread_markcancel
-// __pthread_canceled
-// __semwait_signal
-// Proc_info
-// sendfile
-// Stat64_extended
-// Lstat64_extended
-// Fstat64_extended
-// __pthread_chdir
-// __pthread_fchdir
-// Audit
-// Auditon
-// Getauid
-// Setauid
-// Getaudit
-// Setaudit
-// Getaudit_addr
-// Setaudit_addr
-// Auditctl
-// Bsdthread_create
-// Bsdthread_terminate
-// Stack_snapshot
-// Bsdthread_register
-// Workq_open
-// Workq_ops
-// __mac_execve
-// __mac_syscall
-// __mac_get_file
-// __mac_set_file
-// __mac_get_link
-// __mac_set_link
-// __mac_get_proc
-// __mac_set_proc
-// __mac_get_fd
-// __mac_set_fd
-// __mac_get_pid
-// __mac_get_lcid
-// __mac_get_lctx
-// __mac_set_lctx
-// Setlcid
-// Read_nocancel
-// Write_nocancel
-// Open_nocancel
-// Close_nocancel
-// Wait4_nocancel
-// Recvmsg_nocancel
-// Sendmsg_nocancel
-// Recvfrom_nocancel
-// Accept_nocancel
-// Msync_nocancel
-// Fcntl_nocancel
-// Select_nocancel
-// Fsync_nocancel
-// Connect_nocancel
-// Sigsuspend_nocancel
-// Readv_nocancel
-// Writev_nocancel
-// Sendto_nocancel
-// Pread_nocancel
-// Pwrite_nocancel
-// Waitid_nocancel
-// Poll_nocancel
-// Msgsnd_nocancel
-// Msgrcv_nocancel
-// Sem_wait_nocancel
-// Aio_suspend_nocancel
-// __sigwait_nocancel
-// __semwait_signal_nocancel
-// __mac_mount
-// __mac_get_mount
-// __mac_getfsstat
+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)