Source file src/syscall/syscall_solaris.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Solaris system calls.
     6  // This file is compiled as ordinary Go code,
     7  // but it is also input to mksyscall,
     8  // which parses the //sys lines and generates system call stubs.
     9  // Note that sometimes we use a lowercase //sys name and wrap
    10  // it in our own nicer implementation, either here or in
    11  // syscall_solaris.go or syscall_unix.go.
    12  
    13  package syscall
    14  
    15  import "unsafe"
    16  
    17  const _F_DUP2FD_CLOEXEC = F_DUP2FD_CLOEXEC
    18  
    19  func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
    20  func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
    21  func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
    22  func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
    23  
    24  // Implemented in asm_solaris_amd64.s.
    25  func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
    26  func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
    27  
    28  type SockaddrDatalink struct {
    29  	Family uint16
    30  	Index  uint16
    31  	Type   uint8
    32  	Nlen   uint8
    33  	Alen   uint8
    34  	Slen   uint8
    35  	Data   [244]int8
    36  	raw    RawSockaddrDatalink
    37  }
    38  
    39  func direntIno(buf []byte) (uint64, bool) {
    40  	return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
    41  }
    42  
    43  func direntReclen(buf []byte) (uint64, bool) {
    44  	return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
    45  }
    46  
    47  func direntNamlen(buf []byte) (uint64, bool) {
    48  	reclen, ok := direntReclen(buf)
    49  	if !ok {
    50  		return 0, false
    51  	}
    52  	return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
    53  }
    54  
    55  func Pipe(p []int) (err error) {
    56  	return Pipe2(p, 0)
    57  }
    58  
    59  //sysnb	pipe2(p *[2]_C_int, flags int) (err error)
    60  
    61  func Pipe2(p []int, flags int) error {
    62  	if len(p) != 2 {
    63  		return EINVAL
    64  	}
    65  	var pp [2]_C_int
    66  	err := pipe2(&pp, flags)
    67  	if err == nil {
    68  		p[0] = int(pp[0])
    69  		p[1] = int(pp[1])
    70  	}
    71  	return err
    72  }
    73  
    74  //sys   accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) = libsocket.accept4
    75  
    76  func Accept4(fd int, flags int) (int, Sockaddr, error) {
    77  	var rsa RawSockaddrAny
    78  	var addrlen _Socklen = SizeofSockaddrAny
    79  	nfd, err := accept4(fd, &rsa, &addrlen, flags)
    80  	if err != nil {
    81  		return 0, nil, err
    82  	}
    83  	if addrlen > SizeofSockaddrAny {
    84  		panic("RawSockaddrAny too small")
    85  	}
    86  	sa, err := anyToSockaddr(&rsa)
    87  	if err != nil {
    88  		Close(nfd)
    89  		return 0, nil, err
    90  	}
    91  	return nfd, sa, nil
    92  }
    93  
    94  func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
    95  	if sa.Port < 0 || sa.Port > 0xFFFF {
    96  		return nil, 0, EINVAL
    97  	}
    98  	sa.raw.Family = AF_INET
    99  	p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
   100  	p[0] = byte(sa.Port >> 8)
   101  	p[1] = byte(sa.Port)
   102  	sa.raw.Addr = sa.Addr
   103  	return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
   104  }
   105  
   106  func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
   107  	if sa.Port < 0 || sa.Port > 0xFFFF {
   108  		return nil, 0, EINVAL
   109  	}
   110  	sa.raw.Family = AF_INET6
   111  	p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
   112  	p[0] = byte(sa.Port >> 8)
   113  	p[1] = byte(sa.Port)
   114  	sa.raw.Scope_id = sa.ZoneId
   115  	sa.raw.Addr = sa.Addr
   116  	return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
   117  }
   118  
   119  func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
   120  	name := sa.Name
   121  	n := len(name)
   122  	if n >= len(sa.raw.Path) {
   123  		return nil, 0, EINVAL
   124  	}
   125  	sa.raw.Family = AF_UNIX
   126  	for i := 0; i < n; i++ {
   127  		sa.raw.Path[i] = int8(name[i])
   128  	}
   129  	// length is family (uint16), name, NUL.
   130  	sl := _Socklen(2)
   131  	if n > 0 {
   132  		sl += _Socklen(n) + 1
   133  	}
   134  	if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) {
   135  		// Check sl > 3 so we don't change unnamed socket behavior.
   136  		sa.raw.Path[0] = 0
   137  		// Don't count trailing NUL for abstract address.
   138  		sl--
   139  	}
   140  
   141  	return unsafe.Pointer(&sa.raw), sl, nil
   142  }
   143  
   144  func Getsockname(fd int) (sa Sockaddr, err error) {
   145  	var rsa RawSockaddrAny
   146  	var len _Socklen = SizeofSockaddrAny
   147  	if err = getsockname(fd, &rsa, &len); err != nil {
   148  		return
   149  	}
   150  	return anyToSockaddr(&rsa)
   151  }
   152  
   153  const ImplementsGetwd = true
   154  
   155  //sys	Getcwd(buf []byte) (n int, err error)
   156  
   157  func Getwd() (wd string, err error) {
   158  	var buf [PathMax]byte
   159  	// Getcwd will return an error if it failed for any reason.
   160  	_, err = Getcwd(buf[0:])
   161  	if err != nil {
   162  		return "", err
   163  	}
   164  	n := clen(buf[:])
   165  	if n < 1 {
   166  		return "", EINVAL
   167  	}
   168  	return string(buf[:n]), nil
   169  }
   170  
   171  /*
   172   * Wrapped
   173   */
   174  
   175  //sysnb	getgroups(ngid int, gid *_Gid_t) (n int, err error)
   176  //sysnb	setgroups(ngid int, gid *_Gid_t) (err error)
   177  
   178  func Getgroups() (gids []int, err error) {
   179  	n, err := getgroups(0, nil)
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  	if n == 0 {
   184  		return nil, nil
   185  	}
   186  
   187  	// Sanity check group count. Max is 16 on BSD.
   188  	if n < 0 || n > 1000 {
   189  		return nil, EINVAL
   190  	}
   191  
   192  	a := make([]_Gid_t, n)
   193  	n, err = getgroups(n, &a[0])
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	gids = make([]int, n)
   198  	for i, v := range a[0:n] {
   199  		gids[i] = int(v)
   200  	}
   201  	return
   202  }
   203  
   204  func Setgroups(gids []int) (err error) {
   205  	if len(gids) == 0 {
   206  		return setgroups(0, nil)
   207  	}
   208  
   209  	a := make([]_Gid_t, len(gids))
   210  	for i, v := range gids {
   211  		a[i] = _Gid_t(v)
   212  	}
   213  	return setgroups(len(a), &a[0])
   214  }
   215  
   216  func ReadDirent(fd int, buf []byte) (n int, err error) {
   217  	// Final argument is (basep *uintptr) and the syscall doesn't take nil.
   218  	// TODO(rsc): Can we use a single global basep for all calls?
   219  	return Getdents(fd, buf, new(uintptr))
   220  }
   221  
   222  // Wait status is 7 bits at bottom, either 0 (exited),
   223  // 0x7F (stopped), or a signal number that caused an exit.
   224  // The 0x80 bit is whether there was a core dump.
   225  // An extra number (exit code, signal causing a stop)
   226  // is in the high bits.
   227  
   228  type WaitStatus uint32
   229  
   230  const (
   231  	mask  = 0x7F
   232  	core  = 0x80
   233  	shift = 8
   234  
   235  	exited  = 0
   236  	stopped = 0x7F
   237  )
   238  
   239  func (w WaitStatus) Exited() bool { return w&mask == exited }
   240  
   241  func (w WaitStatus) ExitStatus() int {
   242  	if w&mask != exited {
   243  		return -1
   244  	}
   245  	return int(w >> shift)
   246  }
   247  
   248  func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }
   249  
   250  func (w WaitStatus) Signal() Signal {
   251  	sig := Signal(w & mask)
   252  	if sig == stopped || sig == 0 {
   253  		return -1
   254  	}
   255  	return sig
   256  }
   257  
   258  func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
   259  
   260  func (w WaitStatus) Stopped() bool { return w&mask == stopped && Signal(w>>shift) != SIGSTOP }
   261  
   262  func (w WaitStatus) Continued() bool { return w&mask == stopped && Signal(w>>shift) == SIGSTOP }
   263  
   264  func (w WaitStatus) StopSignal() Signal {
   265  	if !w.Stopped() {
   266  		return -1
   267  	}
   268  	return Signal(w>>shift) & 0xFF
   269  }
   270  
   271  func (w WaitStatus) TrapCause() int { return -1 }
   272  
   273  func wait4(pid uintptr, wstatus *WaitStatus, options uintptr, rusage *Rusage) (wpid uintptr, err uintptr)
   274  
   275  func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
   276  	r0, e1 := wait4(uintptr(pid), wstatus, uintptr(options), rusage)
   277  	if e1 != 0 {
   278  		err = Errno(e1)
   279  	}
   280  	return int(r0), err
   281  }
   282  
   283  func gethostname() (name string, err uintptr)
   284  
   285  func Gethostname() (name string, err error) {
   286  	name, e1 := gethostname()
   287  	if e1 != 0 {
   288  		err = Errno(e1)
   289  	}
   290  	return name, err
   291  }
   292  
   293  func UtimesNano(path string, ts []Timespec) error {
   294  	if len(ts) != 2 {
   295  		return EINVAL
   296  	}
   297  	return utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
   298  }
   299  
   300  //sys	fcntl(fd int, cmd int, arg int) (val int, err error)
   301  
   302  // FcntlFlock performs a fcntl syscall for the [F_GETLK], [F_SETLK] or [F_SETLKW] command.
   303  func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
   304  	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
   305  	if e1 != 0 {
   306  		return e1
   307  	}
   308  	return nil
   309  }
   310  
   311  func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
   312  	switch rsa.Addr.Family {
   313  	case AF_UNIX:
   314  		pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
   315  		sa := new(SockaddrUnix)
   316  		// Assume path ends at NUL.
   317  		// This is not technically the Solaris semantics for
   318  		// abstract Unix domain sockets -- they are supposed
   319  		// to be uninterpreted fixed-size binary blobs -- but
   320  		// everyone uses this convention.
   321  		n := 0
   322  		for n < len(pp.Path) && pp.Path[n] != 0 {
   323  			n++
   324  		}
   325  		sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
   326  		return sa, nil
   327  
   328  	case AF_INET:
   329  		pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
   330  		sa := new(SockaddrInet4)
   331  		p := (*[2]byte)(unsafe.Pointer(&pp.Port))
   332  		sa.Port = int(p[0])<<8 + int(p[1])
   333  		sa.Addr = pp.Addr
   334  		return sa, nil
   335  
   336  	case AF_INET6:
   337  		pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
   338  		sa := new(SockaddrInet6)
   339  		p := (*[2]byte)(unsafe.Pointer(&pp.Port))
   340  		sa.Port = int(p[0])<<8 + int(p[1])
   341  		sa.ZoneId = pp.Scope_id
   342  		sa.Addr = pp.Addr
   343  		return sa, nil
   344  	}
   345  	return nil, EAFNOSUPPORT
   346  }
   347  
   348  //sys	accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) = libsocket.accept
   349  
   350  func Accept(fd int) (nfd int, sa Sockaddr, err error) {
   351  	var rsa RawSockaddrAny
   352  	var len _Socklen = SizeofSockaddrAny
   353  	nfd, err = accept(fd, &rsa, &len)
   354  	if err != nil {
   355  		return
   356  	}
   357  	sa, err = anyToSockaddr(&rsa)
   358  	if err != nil {
   359  		Close(nfd)
   360  		nfd = 0
   361  	}
   362  	return
   363  }
   364  
   365  func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
   366  	var msg Msghdr
   367  	msg.Name = (*byte)(unsafe.Pointer(rsa))
   368  	msg.Namelen = uint32(SizeofSockaddrAny)
   369  	var iov Iovec
   370  	if len(p) > 0 {
   371  		iov.Base = (*int8)(unsafe.Pointer(&p[0]))
   372  		iov.SetLen(len(p))
   373  	}
   374  	var dummy int8
   375  	if len(oob) > 0 {
   376  		// receive at least one normal byte
   377  		if len(p) == 0 {
   378  			iov.Base = &dummy
   379  			iov.SetLen(1)
   380  		}
   381  		msg.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
   382  		msg.Accrightslen = int32(len(oob))
   383  	}
   384  	msg.Iov = &iov
   385  	msg.Iovlen = 1
   386  	if n, err = recvmsg(fd, &msg, flags); err != nil {
   387  		return
   388  	}
   389  	oobn = int(msg.Accrightslen)
   390  	return
   391  }
   392  
   393  //sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_sendmsg
   394  
   395  func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
   396  	var msg Msghdr
   397  	msg.Name = (*byte)(unsafe.Pointer(ptr))
   398  	msg.Namelen = uint32(salen)
   399  	var iov Iovec
   400  	if len(p) > 0 {
   401  		iov.Base = (*int8)(unsafe.Pointer(&p[0]))
   402  		iov.SetLen(len(p))
   403  	}
   404  	var dummy int8
   405  	if len(oob) > 0 {
   406  		// send at least one normal byte
   407  		if len(p) == 0 {
   408  			iov.Base = &dummy
   409  			iov.SetLen(1)
   410  		}
   411  		msg.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
   412  		msg.Accrightslen = int32(len(oob))
   413  	}
   414  	msg.Iov = &iov
   415  	msg.Iovlen = 1
   416  	if n, err = sendmsg(fd, &msg, flags); err != nil {
   417  		return 0, err
   418  	}
   419  	if len(oob) > 0 && len(p) == 0 {
   420  		n = 0
   421  	}
   422  	return n, nil
   423  }
   424  
   425  /*
   426   * Exposed directly
   427   */
   428  //sys	Access(path string, mode uint32) (err error)
   429  //sys	Adjtime(delta *Timeval, olddelta *Timeval) (err error)
   430  //sys	Chdir(path string) (err error)
   431  //sys	Chmod(path string, mode uint32) (err error)
   432  //sys	Chown(path string, uid int, gid int) (err error)
   433  //sys	Chroot(path string) (err error)
   434  //sys	Close(fd int) (err error)
   435  //sys	Dup(fd int) (nfd int, err error)
   436  //sys	Fchdir(fd int) (err error)
   437  //sys	Fchmod(fd int, mode uint32) (err error)
   438  //sys	Fchown(fd int, uid int, gid int) (err error)
   439  //sys	Fpathconf(fd int, name int) (val int, err error)
   440  //sys	Fstat(fd int, stat *Stat_t) (err error)
   441  //sys	Getdents(fd int, buf []byte, basep *uintptr) (n int, err error)
   442  //sysnb	Getgid() (gid int)
   443  //sysnb	Getpid() (pid int)
   444  //sys	Geteuid() (euid int)
   445  //sys	Getegid() (egid int)
   446  //sys	Getppid() (ppid int)
   447  //sys	Getpriority(which int, who int) (n int, err error)
   448  //sysnb	Getrlimit(which int, lim *Rlimit) (err error)
   449  //sysnb	Getrusage(who int, rusage *Rusage) (err error)
   450  //sysnb	Gettimeofday(tv *Timeval) (err error)
   451  //sysnb	Getuid() (uid int)
   452  //sys	Kill(pid int, signum Signal) (err error)
   453  //sys	Lchown(path string, uid int, gid int) (err error)
   454  //sys	Link(path string, link string) (err error)
   455  //sys	Listen(s int, backlog int) (err error) = libsocket.__xnet_listen
   456  //sys	Lstat(path string, stat *Stat_t) (err error)
   457  //sys	Mkdir(path string, mode uint32) (err error)
   458  //sys	Mknod(path string, mode uint32, dev int) (err error)
   459  //sys	Nanosleep(time *Timespec, leftover *Timespec) (err error)
   460  //sys	Open(path string, mode int, perm uint32) (fd int, err error)
   461  //sys	Pathconf(path string, name int) (val int, err error)
   462  //sys	pread(fd int, p []byte, offset int64) (n int, err error)
   463  //sys	pwrite(fd int, p []byte, offset int64) (n int, err error)
   464  //sys	read(fd int, p []byte) (n int, err error)
   465  //sys	Readlink(path string, buf []byte) (n int, err error)
   466  //sys	Rename(from string, to string) (err error)
   467  //sys	Rmdir(path string) (err error)
   468  //sys	Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
   469  //sys	sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = libsendfile.sendfile
   470  //sysnb	Setegid(egid int) (err error)
   471  //sysnb	Seteuid(euid int) (err error)
   472  //sysnb	Setgid(gid int) (err error)
   473  //sysnb	Setpgid(pid int, pgid int) (err error)
   474  //sys	Setpriority(which int, who int, prio int) (err error)
   475  //sysnb	Setregid(rgid int, egid int) (err error)
   476  //sysnb	Setreuid(ruid int, euid int) (err error)
   477  //sysnb	setrlimit(which int, lim *Rlimit) (err error)
   478  //sysnb	Setsid() (pid int, err error)
   479  //sysnb	Setuid(uid int) (err error)
   480  //sys	Shutdown(s int, how int) (err error) = libsocket.shutdown
   481  //sys	Stat(path string, stat *Stat_t) (err error)
   482  //sys	Symlink(path string, link string) (err error)
   483  //sys	Sync() (err error)
   484  //sys	Truncate(path string, length int64) (err error)
   485  //sys	Fsync(fd int) (err error)
   486  //sys	Ftruncate(fd int, length int64) (err error)
   487  //sys	Umask(newmask int) (oldmask int)
   488  //sys	Unlink(path string) (err error)
   489  //sys	utimes(path string, times *[2]Timeval) (err error)
   490  //sys	bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_bind
   491  //sys	connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_connect
   492  //sys	mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
   493  //sys	munmap(addr uintptr, length uintptr) (err error)
   494  //sys	sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_sendto
   495  //sys	socket(domain int, typ int, proto int) (fd int, err error) = libsocket.__xnet_socket
   496  //sysnb	socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.__xnet_socketpair
   497  //sys	write(fd int, p []byte) (n int, err error)
   498  //sys	writev(fd int, iovecs []Iovec) (n uintptr, err error)
   499  //sys	getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) = libsocket.__xnet_getsockopt
   500  //sysnb	getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getpeername
   501  //sys	getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getsockname
   502  //sys	setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) = libsocket.setsockopt
   503  //sys	recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) = libsocket.recvfrom
   504  //sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_recvmsg
   505  //sys	getexecname() (path unsafe.Pointer, err error) = libc.getexecname
   506  //sys	utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error)
   507  
   508  func Getexecname() (path string, err error) {
   509  	ptr, err := getexecname()
   510  	if err != nil {
   511  		return "", err
   512  	}
   513  	bytes := (*[1 << 29]byte)(ptr)[:]
   514  	for i, b := range bytes {
   515  		if b == 0 {
   516  			return string(bytes[:i]), nil
   517  		}
   518  	}
   519  	panic("unreachable")
   520  }
   521  
   522  func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
   523  	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_read)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
   524  	n = int(r0)
   525  	if e1 != 0 {
   526  		err = e1
   527  	}
   528  	return
   529  }
   530  
   531  var mapper = &mmapper{
   532  	active: make(map[*byte][]byte),
   533  	mmap:   mmap,
   534  	munmap: munmap,
   535  }
   536  
   537  func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
   538  	return mapper.Mmap(fd, offset, length, prot, flags)
   539  }
   540  
   541  func Munmap(b []byte) (err error) {
   542  	return mapper.Munmap(b)
   543  }
   544  
   545  func Utimes(path string, tv []Timeval) error {
   546  	if len(tv) != 2 {
   547  		return EINVAL
   548  	}
   549  	return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
   550  }
   551  

View as plain text