Ejemplo n.º 1
0
func (s *Session) handleTcreate(cx context.Context, msg styxproto.Tcreate, file file) bool {
	qid := s.conn.qid(file.name, 0)
	if qid.Type()&styxproto.QTDIR == 0 {
		s.conn.clearTag(msg.Tag())
		s.conn.Rerror(msg.Tag(), "not a directory: %q", file.name)
		s.conn.Flush()
		return true
	}
	s.requests <- Tcreate{
		Name:    string(msg.Name()),
		Mode:    styxfile.ModeOS(msg.Perm()),
		Flag:    openFlag(msg.Mode()),
		reqInfo: newReqInfo(cx, s, msg, file.name),
	}
	return true
}
Ejemplo n.º 2
0
// The Ropen method signals to the client that a file has succesfully
// been opened and is ready for I/O. After Ropen returns, future reads
// and writes to the opened file handle will pass through rwc.
//
// The value rwc must implement some of the interfaces in the io package
// for reading and writing. If the type implements io.Seeker or io.ReaderAt
// and io.WriterAt, clients may read or write at arbitrary offsets within
// the file. Types that only implement Read or Write operations will return
// errors on writes and reads, respectively.
//
// If rwc implements the Stat method of os.File, that will be used to
// answer Tstat requests. Otherwise, the styx package will assemble Rstat
// responses out of default values merged with any methods rwc provides
// from the os.FileInfo interface.
//
// If a file does not implement any of the Read or Write interfaces in
// the io package, A generic error is returned to the client, and a message
// will be written to the server's ErrorLog.
func (t Topen) Ropen(rwc interface{}, err error) {
	var (
		file file
		f    styxfile.Interface
	)
	if err != nil {
		t.Rerror("%s", err)
		return
	}
	// The type of the file (regular or directory) will have been
	// established in a previous Twalk request.
	qid := t.session.conn.qid(t.Path(), 0)
	mode := styxfile.ModeOS(uint32(qid.Type()) << 24)

	if dir, ok := rwc.(Directory); ok && mode.IsDir() {
		f = styxfile.NewDir(dir, t.Path(), t.session.conn.qidpool)
	} else {
		f, err = styxfile.New(rwc)
	}

	if err != nil {
		t.session.conn.srv.logf("%s open %s failed: %s", t.path, err)

		// Don't want to expose too many implementation details
		// to clients.
		t.Rerror("open failed")
		return
	}
	t.session.files.Update(t.fid, &file, func() {
		file.rwc = f
	})
	t.session.unhandled = false
	if t.session.conn.clearTag(t.tag) {
		t.session.conn.Ropen(t.tag, qid, 0)
	}
}
Ejemplo n.º 3
0
Archivo: wstat.go Proyecto: droyo/styx
func (s *Session) handleTwstat(cx context.Context, msg styxproto.Twstat, file file) bool {
	// mode, atime+mtime, length, name, uid+gid, sync
	// we will ignore muid
	const numMutable = 6

	// By convention, sending a Twstat message with a stat structure consisting
	// entirely of "don't touch" values indicates that the client wants the server
	// to sync the file to disk.
	var haveChanges bool
	var messages int

	stat := msg.Stat()

	// We buffer the channel so that the response
	// methods for each attribute do not block.
	status := make(chan error, numMutable)
	info := newReqInfo(cx, s, msg, file.name)
	filled := make([]int32, numMutable)

	atime, mtime := stat.Atime(), stat.Mtime()
	if atime != math.MaxUint32 || mtime != math.MaxUint32 {
		haveChanges = true
		s.requests <- Tutimes{
			Atime:  time.Unix(int64(atime), 0),
			Mtime:  time.Unix(int64(mtime), 0),
			twstat: twstat{status, filled, messages, info},
		}
		messages++
	}
	if uid, gid := string(stat.Uid()), string(stat.Gid()); uid != "" || gid != "" {
		haveChanges = true
		s.requests <- Tchown{
			User:   uid,
			Group:  gid,
			twstat: twstat{status, filled, messages, info},
		}
		messages++
	}
	if name := string(stat.Name()); name != "" && name != file.name {
		haveChanges = true
		s.requests <- Trename{
			OldPath: file.name,
			NewPath: name,
			twstat:  twstat{status, filled, messages, info},
		}
		messages++
	}
	if length := stat.Length(); length != -1 {
		haveChanges = true
		s.requests <- Ttruncate{
			Size:   length,
			twstat: twstat{status, filled, messages, info},
		}
		messages++
	}
	if stat.Mode() != math.MaxUint32 {
		haveChanges = true
		s.requests <- Tchmod{
			Mode:   styxfile.ModeOS(stat.Mode()),
			twstat: twstat{status, filled, messages, info},
		}
		messages++
	}
	if len(stat.Muid()) != 0 {
		// even though we won't respond to this field, we don't
		// want to needlessly stimulate a sync request
		haveChanges = true
	}
	if !haveChanges {
		s.requests <- Tsync{
			twstat: twstat{status, filled, messages, info},
		}
		messages++
	}

	go func() {
		var (
			success bool
			err     error
		)
		for i := 0; i < messages; i++ {
			if e, ok := <-status; !ok {
				panic("closed Twstat channel prematurely")
			} else if e != nil {
				err = e
			} else {
				success = true
			}
		}
		if !s.conn.clearTag(msg.Tag()) {
			return
		}
		if success {
			s.conn.Rwstat(msg.Tag())
		} else {
			s.conn.Rerror(msg.Tag(), "%s", err)
		}
		s.conn.Flush()
	}()

	return true
}