// Copyright 2021 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package lisafs

import (
	"fmt"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/sys/unix"
	"gvisor.dev/gvisor/pkg/flipcall"
	"gvisor.dev/gvisor/pkg/fspath"
	"gvisor.dev/gvisor/pkg/log"
	"gvisor.dev/gvisor/pkg/marshal/primitive"
)

const (
	allowedOpenFlags     = unix.O_ACCMODE | unix.O_TRUNC
	setStatSupportedMask = unix.STATX_MODE | unix.STATX_UID | unix.STATX_GID | unix.STATX_SIZE | unix.STATX_ATIME | unix.STATX_MTIME
)

// RPCHandler defines a handler that is invoked when the associated message is
// received. The handler is responsible for:
//
// * Unmarshalling the request from the passed payload and interpreting it.
// * Marshalling the response into the communicator's payload buffer.
// * Return the number of payload bytes written.
// * Donate any FDs (if needed) to comm which will in turn donate it to client.
type RPCHandler func(c *Connection, comm Communicator, payloadLen uint32) (uint32, error)

var handlers = [...]RPCHandler{
	Error:        ErrorHandler,
	Mount:        MountHandler,
	Channel:      ChannelHandler,
	FStat:        FStatHandler,
	SetStat:      SetStatHandler,
	Walk:         WalkHandler,
	WalkStat:     WalkStatHandler,
	OpenAt:       OpenAtHandler,
	OpenCreateAt: OpenCreateAtHandler,
	Close:        CloseHandler,
	FSync:        FSyncHandler,
	PWrite:       PWriteHandler,
	PRead:        PReadHandler,
	MkdirAt:      MkdirAtHandler,
	MknodAt:      MknodAtHandler,
	SymlinkAt:    SymlinkAtHandler,
	LinkAt:       LinkAtHandler,
	FStatFS:      FStatFSHandler,
	FAllocate:    FAllocateHandler,
	ReadLinkAt:   ReadLinkAtHandler,
	Flush:        FlushHandler,
	Connect:      ConnectHandler,
	UnlinkAt:     UnlinkAtHandler,
	RenameAt:     RenameAtHandler,
	Getdents64:   Getdents64Handler,
	FGetXattr:    FGetXattrHandler,
	FSetXattr:    FSetXattrHandler,
	FListXattr:   FListXattrHandler,
	FRemoveXattr: FRemoveXattrHandler,
}

// ErrorHandler handles Error message.
func ErrorHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	// Client should never send Error.
	return 0, unix.EINVAL
}

// MountHandler handles the Mount RPC. Note that there can not be concurrent
// executions of MountHandler on a connection because the connection enforces
// that Mount is the first message on the connection. Only after the connection
// has been successfully mounted can other channels be created.
func MountHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req MountReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	mountPath := path.Clean(string(req.MountPath))
	if !filepath.IsAbs(mountPath) {
		log.Warningf("mountPath %q is not absolute", mountPath)
		return 0, unix.EINVAL
	}

	if c.mounted {
		log.Warningf("connection has already been mounted at %q", mountPath)
		return 0, unix.EBUSY
	}

	rootFD, rootIno, err := c.ServerImpl().Mount(c, mountPath)
	if err != nil {
		return 0, err
	}

	c.server.addMountPoint(rootFD.FD())
	c.mounted = true
	resp := MountResp{
		Root:           rootIno,
		SupportedMs:    c.ServerImpl().SupportedMessages(),
		MaxMessageSize: primitive.Uint32(c.ServerImpl().MaxMessageSize()),
	}
	respPayloadLen := uint32(resp.SizeBytes())
	resp.MarshalBytes(comm.PayloadBuf(respPayloadLen))
	return respPayloadLen, nil
}

// ChannelHandler handles the Channel RPC.
func ChannelHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	ch, desc, fdSock, err := c.createChannel(c.ServerImpl().MaxMessageSize())
	if err != nil {
		return 0, err
	}

	// Start servicing the channel in a separate goroutine.
	c.activeWg.Add(1)
	go func() {
		if err := c.service(ch); err != nil {
			// Don't log shutdown error which is expected during server shutdown.
			if _, ok := err.(flipcall.ShutdownError); !ok {
				log.Warningf("lisafs.Connection.service(channel = @%p): %v", ch, err)
			}
		}
		c.activeWg.Done()
	}()

	clientDataFD, err := unix.Dup(desc.FD)
	if err != nil {
		unix.Close(fdSock)
		ch.shutdown()
		return 0, err
	}

	// Respond to client with successful channel creation message.
	if err := comm.DonateFD(clientDataFD); err != nil {
		return 0, err
	}
	if err := comm.DonateFD(fdSock); err != nil {
		return 0, err
	}
	resp := ChannelResp{
		dataOffset: desc.Offset,
		dataLength: uint64(desc.Length),
	}
	respLen := uint32(resp.SizeBytes())
	resp.MarshalUnsafe(comm.PayloadBuf(respLen))
	return respLen, nil
}

// FStatHandler handles the FStat RPC.
func FStatHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req StatReq
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	fd, err := c.lookupFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)

	switch t := fd.(type) {
	case *ControlFD:
		return t.impl.Stat(c, comm)
	case *OpenFD:
		return t.impl.Stat(c, comm)
	default:
		panic(fmt.Sprintf("unknown fd type %T", t))
	}
}

// SetStatHandler handles the SetStat RPC.
func SetStatHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}

	var req SetStatReq
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupControlFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)

	if req.Mask&^setStatSupportedMask != 0 {
		return 0, unix.EPERM
	}

	return fd.impl.SetStat(c, comm, req)
}

// WalkHandler handles the Walk RPC.
func WalkHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req WalkReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupControlFD(req.DirFD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.IsDir() {
		return 0, unix.ENOTDIR
	}
	for _, name := range req.Path {
		if err := checkSafeName(name); err != nil {
			return 0, err
		}
	}

	return fd.impl.Walk(c, comm, req.Path)
}

// WalkStatHandler handles the WalkStat RPC.
func WalkStatHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req WalkReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupControlFD(req.DirFD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)

	// Note that this fd is allowed to not actually be a directory when the
	// only path component to walk is "" (self).
	if !fd.IsDir() {
		if len(req.Path) > 1 || (len(req.Path) == 1 && len(req.Path[0]) > 0) {
			return 0, unix.ENOTDIR
		}
	}
	for i, name := range req.Path {
		// First component is allowed to be "".
		if i == 0 && len(name) == 0 {
			continue
		}
		if err := checkSafeName(name); err != nil {
			return 0, err
		}
	}

	return fd.impl.WalkStat(c, comm, req.Path)
}

// OpenAtHandler handles the OpenAt RPC.
func OpenAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req OpenAtReq
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	// Only keep allowed open flags.
	if allowedFlags := req.Flags & allowedOpenFlags; allowedFlags != req.Flags {
		log.Debugf("discarding open flags that are not allowed: old open flags = %d, new open flags = %d", req.Flags, allowedFlags)
		req.Flags = allowedFlags
	}

	accessMode := req.Flags & unix.O_ACCMODE
	trunc := req.Flags&unix.O_TRUNC != 0
	if c.readonly && (accessMode != unix.O_RDONLY || trunc) {
		return 0, unix.EROFS
	}

	fd, err := c.LookupControlFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if fd.IsDir() {
		// Directory is not truncatable and must be opened with O_RDONLY.
		if accessMode != unix.O_RDONLY || trunc {
			return 0, unix.EISDIR
		}
	}

	return fd.impl.Open(c, comm, req.Flags)
}

// OpenCreateAtHandler handles the OpenCreateAt RPC.
func OpenCreateAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req OpenCreateAtReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	// Only keep allowed open flags.
	if allowedFlags := req.Flags & allowedOpenFlags; allowedFlags != req.Flags {
		log.Debugf("discarding open flags that are not allowed: old open flags = %d, new open flags = %d", req.Flags, allowedFlags)
		req.Flags = allowedFlags
	}

	name := string(req.Name)
	if err := checkSafeName(name); err != nil {
		return 0, err
	}

	fd, err := c.LookupControlFD(req.DirFD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.IsDir() {
		return 0, unix.ENOTDIR
	}

	return fd.impl.OpenCreate(c, comm, req.Mode, req.UID, req.GID, name, uint32(req.Flags))
}

// CloseHandler handles the Close RPC.
func CloseHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req CloseReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))
	for _, fd := range req.FDs {
		c.RemoveFD(fd)
	}

	// There is no response message for this.
	return 0, nil
}

// FSyncHandler handles the FSync RPC.
func FSyncHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req FsyncReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	// Return the first error we encounter, but sync everything we can
	// regardless.
	var retErr error
	for _, fdid := range req.FDs {
		if err := c.fsyncFD(fdid); err != nil && retErr == nil {
			retErr = err
		}
	}

	// There is no response message for this.
	return 0, retErr
}

func (c *Connection) fsyncFD(id FDID) error {
	fd, err := c.LookupOpenFD(id)
	if err != nil {
		return err
	}
	return fd.impl.Sync(c)
}

// PWriteHandler handles the PWrite RPC.
func PWriteHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req PWriteReq
	// Note that it is an optimized Unmarshal operation which avoids any buffer
	// allocation and copying. req.Buf just points to payload. This is safe to do
	// as the handler owns payload and req's lifetime is limited to the handler.
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))
	fd, err := c.LookupOpenFD(req.FD)
	if err != nil {
		return 0, err
	}
	if !fd.writable {
		return 0, unix.EBADF
	}
	return fd.impl.Write(c, comm, req.Buf, uint64(req.Offset))
}

// PReadHandler handles the PRead RPC.
func PReadHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req PReadReq
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupOpenFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.readable {
		return 0, unix.EBADF
	}
	return fd.impl.Read(c, comm, req.Offset, req.Count)
}

// MkdirAtHandler handles the MkdirAt RPC.
func MkdirAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req MkdirAtReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	name := string(req.Name)
	if err := checkSafeName(name); err != nil {
		return 0, err
	}

	fd, err := c.LookupControlFD(req.DirFD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.IsDir() {
		return 0, unix.ENOTDIR
	}
	return fd.impl.Mkdir(c, comm, req.Mode, req.UID, req.GID, name)
}

// MknodAtHandler handles the MknodAt RPC.
func MknodAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req MknodAtReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	name := string(req.Name)
	if err := checkSafeName(name); err != nil {
		return 0, err
	}

	fd, err := c.LookupControlFD(req.DirFD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.IsDir() {
		return 0, unix.ENOTDIR
	}
	return fd.impl.Mknod(c, comm, req.Mode, req.UID, req.GID, name, uint32(req.Minor), uint32(req.Major))
}

// SymlinkAtHandler handles the SymlinkAt RPC.
func SymlinkAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req SymlinkAtReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	name := string(req.Name)
	if err := checkSafeName(name); err != nil {
		return 0, err
	}

	fd, err := c.LookupControlFD(req.DirFD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.IsDir() {
		return 0, unix.ENOTDIR
	}
	return fd.impl.Symlink(c, comm, name, string(req.Target), req.UID, req.GID)
}

// LinkAtHandler handles the LinkAt RPC.
func LinkAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req LinkAtReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	name := string(req.Name)
	if err := checkSafeName(name); err != nil {
		return 0, err
	}

	fd, err := c.LookupControlFD(req.DirFD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.IsDir() {
		return 0, unix.ENOTDIR
	}

	targetFD, err := c.LookupControlFD(req.Target)
	if err != nil {
		return 0, err
	}
	return targetFD.impl.Link(c, comm, fd.impl, name)
}

// FStatFSHandler handles the FStatFS RPC.
func FStatFSHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req FStatFSReq
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupControlFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	return fd.impl.StatFS(c, comm)
}

// FAllocateHandler handles the FAllocate RPC.
func FAllocateHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req FAllocateReq
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupOpenFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.writable {
		return 0, unix.EBADF
	}
	return 0, fd.impl.Allocate(c, req.Mode, req.Offset, req.Length)
}

// ReadLinkAtHandler handles the ReadLinkAt RPC.
func ReadLinkAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req ReadLinkAtReq
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupControlFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.IsSymlink() {
		return 0, unix.EINVAL
	}
	return fd.impl.Readlink(c, comm)
}

// FlushHandler handles the Flush RPC.
func FlushHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req FlushReq
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupOpenFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)

	return 0, fd.impl.Flush(c)
}

// ConnectHandler handles the Connect RPC.
func ConnectHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req ConnectReq
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupControlFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.IsSocket() {
		return 0, unix.ENOTSOCK
	}
	return 0, fd.impl.Connect(c, comm, req.SockType)
}

// UnlinkAtHandler handles the UnlinkAt RPC.
func UnlinkAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req UnlinkAtReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	name := string(req.Name)
	if err := checkSafeName(name); err != nil {
		return 0, err
	}

	fd, err := c.LookupControlFD(req.DirFD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.IsDir() {
		return 0, unix.ENOTDIR
	}
	return 0, fd.impl.Unlink(c, name, uint32(req.Flags))
}

// RenameAtHandler handles the RenameAt RPC.
func RenameAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req RenameAtReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	newName := string(req.NewName)
	if err := checkSafeName(newName); err != nil {
		return 0, err
	}

	renamed, err := c.LookupControlFD(req.Renamed)
	if err != nil {
		return 0, err
	}
	defer renamed.DecRef(nil)

	newDir, err := c.LookupControlFD(req.NewDir)
	if err != nil {
		return 0, err
	}
	defer newDir.DecRef(nil)
	if !newDir.IsDir() {
		return 0, unix.ENOTDIR
	}

	// Hold RenameMu for writing during rename, this is important.
	c.server.RenameMu.Lock()
	defer c.server.RenameMu.Unlock()

	if renamed.parent == nil {
		// renamed is root.
		return 0, unix.EBUSY
	}

	oldParentPath := renamed.parent.FilePathLocked()
	oldPath := oldParentPath + "/" + renamed.name
	if newName == renamed.name && oldParentPath == newDir.FilePathLocked() {
		// Nothing to do.
		return 0, nil
	}

	updateControlFD, cleanUp, err := renamed.impl.RenameLocked(c, newDir.impl, newName)
	if err != nil {
		return 0, err
	}

	c.server.forEachMountPoint(func(root *ControlFD) {
		if !strings.HasPrefix(oldPath, root.name) {
			return
		}
		pit := fspath.Parse(oldPath[len(root.name):]).Begin
		root.renameRecursiveLocked(newDir, newName, pit, updateControlFD)
	})

	if cleanUp != nil {
		cleanUp()
	}
	return 0, nil
}

// Precondition: rename mutex must be locked for writing.
func (fd *ControlFD) renameRecursiveLocked(newDir *ControlFD, newName string, pit fspath.Iterator, updateControlFD func(ControlFDImpl)) {
	if !pit.Ok() {
		// fd should be renamed.
		fd.clearParentLocked()
		fd.setParentLocked(newDir)
		fd.name = newName
		if updateControlFD != nil {
			updateControlFD(fd.impl)
		}
		return
	}

	cur := pit.String()
	next := pit.Next()
	// No need to hold fd.childrenMu because RenameMu is locked for writing.
	for child := fd.children.Front(); child != nil; child = child.Next() {
		if child.name == cur {
			child.renameRecursiveLocked(newDir, newName, next, updateControlFD)
		}
	}
}

// Getdents64Handler handles the Getdents64 RPC.
func Getdents64Handler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req Getdents64Req
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupOpenFD(req.DirFD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	if !fd.controlFD.IsDir() {
		return 0, unix.ENOTDIR
	}

	seek0 := false
	if req.Count < 0 {
		seek0 = true
		req.Count = -req.Count
	}
	return fd.impl.Getdent64(c, comm, uint32(req.Count), seek0)
}

// FGetXattrHandler handles the FGetXattr RPC.
func FGetXattrHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req FGetXattrReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupControlFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	return fd.impl.GetXattr(c, comm, string(req.Name), uint32(req.BufSize))
}

// FSetXattrHandler handles the FSetXattr RPC.
func FSetXattrHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req FSetXattrReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupControlFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	return 0, fd.impl.SetXattr(c, string(req.Name), string(req.Value), uint32(req.Flags))
}

// FListXattrHandler handles the FListXattr RPC.
func FListXattrHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	var req FListXattrReq
	req.UnmarshalUnsafe(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupControlFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	return fd.impl.ListXattr(c, comm, req.Size)
}

// FRemoveXattrHandler handles the FRemoveXattr RPC.
func FRemoveXattrHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) {
	if c.readonly {
		return 0, unix.EROFS
	}
	var req FRemoveXattrReq
	req.UnmarshalBytes(comm.PayloadBuf(payloadLen))

	fd, err := c.LookupControlFD(req.FD)
	if err != nil {
		return 0, err
	}
	defer fd.DecRef(nil)
	return 0, fd.impl.RemoveXattr(c, comm, string(req.Name))
}

// checkSafeName validates the name and returns nil or returns an error.
func checkSafeName(name string) error {
	if name != "" && !strings.Contains(name, "/") && name != "." && name != ".." {
		return nil
	}
	return unix.EINVAL
}