// OpenAt implements vfs.FilesystemImpl.OpenAt.
OpenAt implements vfs.FilesystemImpl.OpenAt.
// OpenAt implements vfs . FilesystemImpl . OpenAt .
func (fs *filesystem) OpenAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
	if opts.Flags&linux.O_TMPFILE != 0 {
		return nil, syserror.EOPNOTSUPP
	}
	if opts.Flags&linux.O_CREAT == 0 {
		fs.mu.RLock()
		d, err := resolveLocked(ctx, rp)
		if err != nil {
			fs.mu.RUnlock()
			return nil, err
		}
		d.IncRef()
		defer d.DecRef(ctx)
		fs.mu.RUnlock()
		return d.open(ctx, rp, &opts, false )
	}
	mustCreate := opts.Flags&linux.O_EXCL != 0
	start := rp.Start().Impl().(*dentry)
	fs.mu.Lock()
	unlocked := false
	unlock := func() {
		if !unlocked {
			fs.mu.Unlock()
			unlocked = true
		}
	}
	defer unlock()
	if rp.Done() {
		if rp.MustBeDir() {
			return nil, syserror.EISDIR
		}
		if mustCreate {
			return nil, syserror.EEXIST
		}
		start.IncRef()
		defer start.DecRef(ctx)
		unlock()
		return start.open(ctx, rp, &opts, false )
	}
afterTrailingSymlink:
	parentDir, err := walkParentDirLocked(ctx, rp, start)
	if err != nil {
		return nil, err
	}
	if err := parentDir.inode.checkPermissions(rp.Credentials(), vfs.MayExec); err != nil {
		return nil, err
	}
	if rp.MustBeDir() {
		return nil, syserror.EISDIR
	}
	name := rp.Component()
	if name == "." || name == ".." {
		return nil, syserror.EISDIR
	}
	if len(name) > linux.NAME_MAX {
		return nil, syserror.ENAMETOOLONG
	}
	child, ok := parentDir.childMap[name]
	if !ok {
		if err := parentDir.inode.checkPermissions(rp.Credentials(), vfs.MayWrite); err != nil {
			return nil, err
		}
		if err := rp.Mount().CheckBeginWrite(); err != nil {
			return nil, err
		}
		defer rp.Mount().EndWrite()
		creds := rp.Credentials()
		child := fs.newDentry(fs.newRegularFile(creds.EffectiveKUID, creds.EffectiveKGID, opts.Mode, parentDir))
		parentDir.insertChildLocked(child, name)
		child.IncRef()
		defer child.DecRef(ctx)
		unlock()
		fd, err := child.open(ctx, rp, &opts, true)
		if err != nil {
			return nil, err
		}
		parentDir.inode.watches.Notify(ctx, name, linux.IN_CREATE, 0, vfs.PathEvent, false )
		parentDir.inode.touchCMtime()
		return fd, nil
	}
	if mustCreate {
		return nil, syserror.EEXIST
	}
	if err := rp.CheckMount(ctx, &child.vfsd); err != nil {
		return nil, err
	}
	if symlink, ok := child.inode.impl.(*symlink); ok && rp.ShouldFollowSymlink() {
		child.inode.touchAtime(rp.Mount())
		if err := rp.HandleSymlink(symlink.target); err != nil {
			return nil, err
		}
		start = &parentDir.dentry
		goto afterTrailingSymlink
	}
	if rp.MustBeDir() && !child.inode.isDir() {
		return nil, syserror.ENOTDIR
	}
	child.IncRef()
	defer child.DecRef(ctx)
	unlock()
	return child.open(ctx, rp, &opts, false)
}
func ( fs * filesystem ) OpenAt ( ctx context . Context , rp * vfs . ResolvingPath , opts vfs . OpenOptions ) ( * vfs . FileDescription , error ) { if opts . Flags & linux . O_TMPFILE != 0 { return nil , syserror . EOPNOTSUPP } if opts . Flags & linux . O_CREAT == 0 { fs . mu . RLock ( ) d , err := resolveLocked ( ctx , rp ) if err != nil { fs . mu . RUnlock ( ) return nil , err } d . IncRef ( ) defer d . DecRef ( ctx ) fs . mu . RUnlock ( ) return d . open ( ctx , rp , & opts , false ) } mustCreate := opts . Flags & linux . O_EXCL != 0 start := rp . Start ( ) . Impl ( ) . ( * dentry ) fs . mu . Lock ( ) unlocked := false unlock := func ( ) { if ! unlocked { fs . mu . Unlock ( ) unlocked = true } } defer unlock ( ) if rp . Done ( ) { if rp . MustBeDir ( ) { return nil , syserror . EISDIR } if mustCreate { return nil , syserror . EEXIST } start . IncRef ( ) defer start . DecRef ( ctx ) unlock ( ) return start . open ( ctx , rp , & opts , false ) } afterTrailingSymlink : parentDir , err := walkParentDirLocked ( ctx , rp , start ) if err != nil { return nil , err } if err := parentDir . inode . checkPermissions ( rp . Credentials ( ) , vfs . MayExec ) ; err != nil { return nil , err } if rp . MustBeDir ( ) { return nil , syserror . EISDIR } name := rp . Component ( ) if name == " " || name == " " { return nil , syserror . EISDIR } if len ( name ) > linux . NAME_MAX { return nil , syserror . ENAMETOOLONG } child , ok := parentDir . childMap [ name ] if ! ok { if err := parentDir . inode . checkPermissions ( rp . Credentials ( ) , vfs . MayWrite ) ; err != nil { return nil , err } if err := rp . Mount ( ) . CheckBeginWrite ( ) ; err != nil { return nil , err } defer rp . Mount ( ) . EndWrite ( ) creds := rp . Credentials ( ) child := fs . newDentry ( fs . newRegularFile ( creds . EffectiveKUID , creds . EffectiveKGID , opts . Mode , parentDir ) ) parentDir . insertChildLocked ( child , name ) child . IncRef ( ) defer child . DecRef ( ctx ) unlock ( ) fd , err := child . open ( ctx , rp , & opts , true ) if err != nil { return nil , err } parentDir . inode . watches . Notify ( ctx , name , linux . IN_CREATE , 0 , vfs . PathEvent , false ) parentDir . inode . touchCMtime ( ) return fd , nil } if mustCreate { return nil , syserror . EEXIST } if err := rp . CheckMount ( ctx , & child . vfsd ) ; err != nil { return nil , err } if symlink , ok := child . inode . impl . ( * symlink ) ; ok && rp . ShouldFollowSymlink ( ) { child . inode . touchAtime ( rp . Mount ( ) ) if err := rp . HandleSymlink ( symlink . target ) ; err != nil { return nil , err } start = & parentDir . dentry goto afterTrailingSymlink } if rp . MustBeDir ( ) && ! child . inode . isDir ( ) { return nil , syserror . ENOTDIR } child . IncRef ( ) defer child . DecRef ( ctx ) unlock ( ) return child . open ( ctx , rp , & opts , false ) }
OpenAt implements vfs.FilesystemImpl.OpenAt.
OpenAt implements vfs . FilesystemImpl . OpenAt .
// Not yet supported. // Handle O_CREAT and !O_CREAT separately, since in the latter case we // don't need fs.mu for writing. /* afterCreate */ // Reject attempts to open mount root directory with O_CREAT. /* afterCreate */ // Check for search permission in the parent directory. // Reject attempts to open directories with O_CREAT. // Determine whether or not we need to create a file. // Already checked for searchability above; now check for writability. // Create and open the child. /* unlinked */ // Is the file mounted over? // Do we need to resolve a trailing symlink? // Symlink traversal updates access time.