Exemplo n.º 1
0
// walkTo handles the walking logic. Walk returns a fidState, len(names) qids
// and a nil error if the walk succeeded. If the walk was partially successful,
// it returns a nil fidState, less than len(names) qids and a nil error. If the
// walk was completely unsuccessful, a nil fidState, nil qid slice and a non-nil
// error is returned.
func walkTo(oldState *fidState, names []string) (*fidState, []qp.Qid, error) {
	var (
		handle          trees.ReadWriteAtCloser
		isdir, addToLoc bool
		root, temproot  trees.File
		username, name  string
		newloc          FilePath
		qids            []qp.Qid
		d               trees.Dir
		err             error
		q               qp.Qid
	)

	// Walk and Arrived can block, so we don't want to be holding locks. Copy
	// what we need.
	oldState.RLock()
	handle = oldState.handle
	newloc = oldState.location.Clone()
	username = oldState.username
	oldState.RUnlock()

	root = newloc.Current()

	if root == nil {
		return nil, nil, errors.New(InvalidOpOnFid)
	}

	if handle != nil {
		// Can't walk on an open fid.
		return nil, nil, errors.New(FidOpen)
	}

	for i := range names {
		addToLoc = false
		name = names[i]
		switch name {
		case ".":
			// This always succeeds, but we don't want to add it to our location
			// list.
		case "..":
			// This also always succeeds, and it either does nothing or shortens
			// our location list. We don't want anything added to the list
			// regardless.
			root = newloc.Parent()
			if len(newloc) > 1 {
				newloc = newloc[:len(newloc)-1]
			}
		default:
			// A regular file name. In this case, walking to the name is only
			// legal if the current file is a directory.
			addToLoc = true

			isdir, err = root.IsDir()
			if err != nil {
				return nil, nil, err
			}

			if !isdir {
				// Root isn't a dir, so we can't walk.
				err = errors.New(FidNotDirectory)
				goto done
			}

			d = root.(trees.Dir)
			if root, err = d.Walk(username, name); err != nil {
				// The walk failed for some arbitrary reason.
				goto done
			} else if root == nil {
				// The file did not exist
				err = errors.New(NoSuchFile)
				goto done
			}

			if temproot, err = root.Arrived(username); err != nil {
				// The Arrived callback failed for some arbitrary reason.
				goto done
			}

			if temproot != nil {
				root = temproot
			}
		}

		if addToLoc {
			newloc = append(newloc, root)
		}

		q, err = root.Qid()
		if err != nil {
			return nil, nil, err
		}

		qids = append(qids, q)
	}

done:
	if err != nil && len(qids) == 0 {
		return nil, nil, err
	}
	if len(qids) < len(names) {
		return nil, qids, nil
	}

	s := &fidState{
		username: username,
		location: newloc,
	}

	return s, qids, nil
}
Exemplo n.º 2
0
func setStat(user string, e trees.File, parent trees.Dir, nstat qp.Stat) error {
	ostat, err := e.Stat()
	if err != nil {
		return err
	}

	length := false
	name := false
	mode := false
	owner := false

	if nstat.Type != ^uint16(0) && nstat.Type != ostat.Type {
		return errors.New("it is illegal to modify type")
	}
	if nstat.Dev != ^uint32(0) && nstat.Dev != ostat.Dev {
		return errors.New("it is illegal to modify dev")
	}
	if nstat.MUID != "" && nstat.MUID != ostat.MUID {
		return errors.New("it is illegal to modify muid")
	}
	if nstat.Atime != ^uint32(0) && nstat.Atime != ostat.Atime {
		return errors.New("it is illegal to modify atime")
	}
	if parent == nil && nstat.Name != "" && nstat.Name != ostat.Name {
		return errors.New("it is illegal to rename root")
	}
	if nstat.Length != ^uint64(0) && nstat.Length != ostat.Length {
		if ostat.Mode&qp.DMDIR != 0 {
			return errors.New("cannot set length of directory")
		}
		if nstat.Length > ostat.Length {
			return errors.New("cannot extend length")
		}
		length = true
	}
	if nstat.Name != "" && nstat.Name != ostat.Name {
		name = true
	}
	if (nstat.UID != "" && nstat.UID != ostat.UID) || (nstat.GID != "" && nstat.GID != ostat.GID) {
		owner = true
	}
	if nstat.Mode != ^qp.FileMode(0) && nstat.Mode != ostat.Mode {
		mode = true
	}

	if nstat.Mtime != ^uint32(0) && nstat.Mtime != ostat.Mtime {
		// We ignore mtime changes ATM. Only owner can change mtime.
	}

	if mode {
		if err := e.SetMode(user, ostat.Mode&qp.DMDIR | nstat.Mode & ^qp.DMDIR); err != nil {
			return err
		}
	}
	if owner {
		if err := e.SetOwner(user, nstat.UID, nstat.GID); err != nil {
			e.SetMode(user, ostat.Mode)
			return err
		}
	}
	if name {
		if err := parent.Rename(user, ostat.Name, nstat.Name); err != nil {
			e.SetMode(user, ostat.Mode)
			e.SetOwner(user, ostat.UID, ostat.GID)
			return err
		}
	}
	if length {
		if err := e.SetLength(user, nstat.Length); err != nil {
			e.SetMode(user, ostat.Mode)
			e.SetOwner(user, ostat.UID, ostat.GID)
			parent.Rename(user, nstat.Name, ostat.Name)
			return err
		}
	}
	return nil
}
Exemplo n.º 3
0
func (fs *FileServer) attach(r *qp.AttachRequest, rs *requestState) {
	defer fs.handlePanic()
	if r.Fid == qp.NOFID {
		fs.sendError(rs, InvalidFid)
		return
	}

	fs.fidLock.Lock()
	defer fs.fidLock.Unlock()

	if _, exists := fs.fids[r.Fid]; exists {
		fs.sendError(rs, FidInUse)
		return
	}

	if fs.AuthFile != nil {
		if r.AuthFid == qp.NOFID {
			// There's an authfile, but no authfid was provided.
			fs.sendError(rs, AuthRequired)
			return
		}

		as, exists := fs.fids[r.AuthFid]
		if !exists {
			fs.sendError(rs, UnknownFid)
			return
		}

		if as.handle == nil {
			fs.sendError(rs, FidNotOpen)
			return
		}

		auther, ok := as.handle.(trees.Authenticator)
		if !ok {
			fs.sendError(rs, AfidNotAuthFile)
			return
		}

		authed, err := auther.Authenticated(r.Username, r.Service)
		if err != nil {
			fs.sendError(rs, err.Error())
			return
		}

		if !authed {
			fs.sendError(rs, PermissionDenied)
			return
		}
	} else if r.AuthFid != qp.NOFID {
		// There's no authfile, but an authfid was provided.
		fs.sendError(rs, AuthNotSupported)
		return
	}

	var root trees.File
	if x, exists := fs.Roots[r.Service]; exists {
		root = x
	} else {
		root = fs.DefaultRoot
	}

	if root == nil {
		fs.sendError(rs, NoSuchService)
		return
	}

	fs.fids[r.Fid] = &fidState{
		username: r.Username,
		location: FilePath{root},
	}

	qid, err := root.Qid()
	if err != nil {
		fs.sendError(rs, err.Error())
		return
	}

	fs.respond(rs, &qp.AttachResponse{
		Tag: r.Tag,
		Qid: qid,
	})
}