diff --git a/fuse/fuse.go b/fuse/fuse.go index 70fd13bb2bd46e080fd573dd0025bf2cf7f38712..1d55a2a53c364386c4e83288ef14f9227bbeff5e 100644 --- a/fuse/fuse.go +++ b/fuse/fuse.go @@ -17,8 +17,6 @@ type FileSystem interface { GetAttr(h *InHeader, in *GetAttrIn) (out *AttrOut, code Error, err os.Error) } -var was bool - type Mounted interface { Unmount() (err os.Error) } @@ -39,6 +37,9 @@ func loop(f *os.File, fs FileSystem, errors chan os.Error) { toW := make(chan [][]byte, 100) defer close(toW) go writer(f, toW, errors) + managerReq := make(chan *managerRequest, 100) + startManager(managerReq) + defer close(managerReq) for { n, err := f.Read(buf) if err == os.EOF { @@ -49,11 +50,11 @@ func loop(f *os.File, fs FileSystem, errors chan os.Error) { break } - dispatch(fs, buf[0:n], toW, errors) + dispatch(fs, buf[0:n], managerReq, toW, errors) } } -func dispatch(fs FileSystem, in_data []byte, toW chan [][]byte, errors chan os.Error) { +func dispatch(fs FileSystem, in_data []byte, mr chan *managerRequest, toW chan [][]byte, errors chan os.Error) { fmt.Printf("in_data: %v\n", in_data) r := bytes.NewBuffer(in_data) h := new(InHeader) @@ -69,21 +70,21 @@ func dispatch(fs FileSystem, in_data []byte, toW chan [][]byte, errors chan os.E fmt.Printf("Opcode: %v, NodeId: %v, h: %v\n", h.Opcode, h.NodeId, h) switch h.Opcode { case FUSE_INIT: - out, err = initFuse(fs, h, r) + out, err = initFuse(fs, h, r, mr) case FUSE_FORGET: return case FUSE_GETATTR: - out, err = getAttr(fs, h, r) + out, err = getAttr(fs, h, r, mr) case FUSE_GETXATTR: - out, err = getXAttr(h, r) + out, err = getXAttr(h, r, mr) case FUSE_OPENDIR: - out, err = openDir(h, r) + out, err = openDir(h, r, mr) case FUSE_READDIR: - out, err = readDir(h, r) + out, err = readDir(h, r, mr) case FUSE_LOOKUP: - out, err = lookup(h, r) + out, err = lookup(h, r, mr) case FUSE_RELEASEDIR: - out, err = releaseDir(h, r) + out, err = releaseDir(h, r, mr) default: errors <- os.NewError(fmt.Sprintf("Unsupported OpCode: %d", h.Opcode)) out, err = serialize(h, EIO, nil) @@ -130,7 +131,7 @@ func serialize(h *InHeader, res Error, out interface{}) (data [][]byte, err os.E return } -func initFuse(fs FileSystem, h *InHeader, r io.Reader) (data [][]byte, err os.Error) { +func initFuse(fs FileSystem, h *InHeader, r io.Reader, mr chan *managerRequest) (data [][]byte, err os.Error) { in := new(InitIn) err = binary.Read(r, binary.LittleEndian, in) if err != nil { @@ -146,7 +147,7 @@ func initFuse(fs FileSystem, h *InHeader, r io.Reader) (data [][]byte, err os.Er return } -func getAttr(fs FileSystem, h *InHeader, r io.Reader) (data [][]byte, err os.Error) { +func getAttr(fs FileSystem, h *InHeader, r io.Reader, mr chan *managerRequest) (data [][]byte, err os.Error) { in := new(GetAttrIn) err = binary.Read(r, binary.LittleEndian, in) if err != nil { @@ -162,60 +163,95 @@ func getAttr(fs FileSystem, h *InHeader, r io.Reader) (data [][]byte, err os.Err return } -func getXAttr(h *InHeader, r io.Reader) (data [][]byte, err os.Error) { +func getXAttr(h *InHeader, r io.Reader, mr chan *managerRequest) (data [][]byte, err os.Error) { out := new(GetXAttrOut) data, err = serialize(h, OK, out) return } -func openDir(h *InHeader, r io.Reader) (data [][]byte, err os.Error) { +func openDir(h *InHeader, r io.Reader, mr chan *managerRequest) (data [][]byte, err os.Error) { in := new(OpenIn) err = binary.Read(r, binary.LittleEndian, in) if err != nil { + data, _ = serialize(h, EIO, nil) return } fmt.Printf("FUSE_OPENDIR: %v\n", in) + resp := makeManagerRequest(mr, h.NodeId, 0, openDirOp) + err = resp.err + if err != nil { + data, err = serialize(h, EIO, nil) + return + } out := new(OpenOut) - out.Fh = 1 - was = false + out.Fh = resp.fh res := OK data, err = serialize(h, res, out) return } -func readDir(h *InHeader, r io.Reader) (data [][]byte, err os.Error) { - if was { - data, err = serialize(h, OK, nil) - return - } +func readDir(h *InHeader, r io.Reader, mr chan *managerRequest) (data [][]byte, err os.Error) { in := new(ReadIn) err = binary.Read(r, binary.LittleEndian, in) if err != nil { + data, _ = serialize(h, EIO, nil) return } fmt.Printf("FUSE_READDIR: %v\n", in) + resp := makeManagerRequest(mr, h.NodeId, in.Fh, getHandleOp) + err = resp.err + if err != nil { + data, _ = serialize(h, EIO, nil) + return + } + dirRespChan := make(chan *dirResponse, 1) + fmt.Printf("Sending dir request\n") + resp.dirReq <- &dirRequest{false, dirRespChan} + fmt.Printf("receiving dir response\n") + dirResp := <-dirRespChan + fmt.Printf("received %v\n", dirResp) + err = dirResp.err + if err != nil { + fmt.Printf("Err!\n") + data, _ = serialize(h, EIO, nil) + return + } + if dirResp.entries == nil { + fmt.Printf("No entries\n") + data, err = serialize(h, OK, nil) + return + } - dirent := new(Dirent) - dirent.Off = 1 - dirent.Ino = h.NodeId - dirent.NameLen = 7 - dirent.Typ = (S_IFDIR & 0170000) >> 12 + fmt.Printf("len(dirResp.entries): %v\n", len(dirResp.entries)) buf := new(bytes.Buffer) - err = binary.Write(buf, binary.LittleEndian, dirent) - if err != nil { - fmt.Printf("AAA!!! binary.Write failed\n") - os.Exit(1) + off := uint64(0) + for _, entry := range dirResp.entries { + off++ + dirent := new(Dirent) + dirent.Off = off + dirent.Ino = h.NodeId + off + dirent.NameLen = uint32(len(entry.name)) + dirent.Typ = (entry.mode & 0170000) >> 12 + err = binary.Write(buf, binary.LittleEndian, dirent) + if err != nil { + fmt.Printf("AAA!!! binary.Write failed\n") + os.Exit(1) + } + buf.Write([]byte(entry.name)) + buf.WriteByte(0) // padding? + n := (len(entry.name) + 1) % 8 + if n != 0 { + buf.Write(make([]byte, 8-n)) + } } - buf.Write([]byte("hello12")) - buf.WriteByte(0) out := buf.Bytes() - was = true + fmt.Printf("out: %v\n", out) res := OK data, err = serialize(h, res, out) return } -func lookup(h *InHeader, r *bytes.Buffer) (data [][]byte, err os.Error) { +func lookup(h *InHeader, r *bytes.Buffer, mr chan *managerRequest) (data [][]byte, err os.Error) { filename := string(r.Bytes()) fmt.Printf("filename: %s\n", filename) out := new(EntryOut) @@ -226,10 +262,20 @@ func lookup(h *InHeader, r *bytes.Buffer) (data [][]byte, err os.Error) { return } -func releaseDir(h *InHeader, r io.Reader) (data [][]byte, err os.Error) { +func releaseDir(h *InHeader, r io.Reader, mr chan *managerRequest) (data [][]byte, err os.Error) { + in := new(ReleaseIn) + err = binary.Read(r, binary.LittleEndian, in) + if err != nil { + data, err = serialize(h, EIO, nil) + return + } + fmt.Printf("FUSE_RELEASEDIR: %v\n", in) + resp := makeManagerRequest(mr, h.NodeId, in.Fh, closeDirOp) + err = resp.err return } + func writer(f *os.File, in chan [][]byte, errors chan os.Error) { fd := f.Fd() for packet := range in { @@ -242,3 +288,142 @@ func writer(f *os.File, in chan [][]byte, errors chan os.Error) { fmt.Printf("writer: OK\n") } } + +type FileOp int + +const ( + openDirOp = FileOp(1) + getHandleOp = FileOp(2) + closeDirOp = FileOp(3) +) + +type managerRequest struct { + nodeId uint64 + fh uint64 + op FileOp + resp chan *managerResponse +} + +type managerResponse struct { + fh uint64 + dirReq chan *dirRequest + err os.Error +} + +type dirEntry struct { + name string + mode uint32 +} + +type dirRequest struct { + isClose bool + resp chan *dirResponse +} + +type dirResponse struct { + entries []*dirEntry + err os.Error +} + +type dirHandle struct { + fh uint64 + nodeId uint64 + req chan *dirRequest +} + +type manager struct { + dirHandles map[uint64]*dirHandle + cnt uint64 +} + +func startManager(requests chan *managerRequest) { + m := new(manager) + m.dirHandles = make(map[uint64]*dirHandle) + go m.run(requests) +} + +func makeManagerRequest(mr chan *managerRequest, nodeId uint64, fh uint64, op FileOp) (resp *managerResponse) { + fmt.Printf("makeManagerRequest, nodeId = %d, fh = %d, op = %d\n", nodeId, fh, op) + req := &managerRequest{nodeId, fh, op, make(chan *managerResponse, 1)} + mr <- req + resp = <-req.resp + fmt.Printf("makeManagerRequest, resp: %v\n", resp) + return +} + +func (m *manager) run(requests chan *managerRequest) { + var resp *managerResponse + for req := range requests { + switch req.op { + case openDirOp: + resp = m.openDir(req) + case getHandleOp: + resp = m.getHandle(req) + case closeDirOp: + resp = m.closeDir(req) + default: + resp := new(managerResponse) + resp.err = os.NewError(fmt.Sprintf("Unknown FileOp: %v", req.op)) + } + req.resp <- resp + } +} + +func (m *manager) openDir(req *managerRequest) (resp *managerResponse) { + resp = new(managerResponse) + m.cnt++ + h := new(dirHandle) + h.fh = m.cnt + h.nodeId = req.nodeId + h.req = make(chan *dirRequest, 1) + m.dirHandles[h.fh] = h + go readDirRoutine(h.req) + resp.fh = h.fh + return +} + +func (m *manager) getHandle(req *managerRequest) (resp *managerResponse) { + fmt.Printf("getHandle, fh: %v\n", req.fh) + resp = new(managerResponse) + h, ok := m.dirHandles[req.fh] + if !ok { + resp.err = os.NewError(fmt.Sprintf("Unknown handle %d", req.fh)) + return + } + fmt.Printf("Handle found\n") + resp.dirReq = h.req + return +} + +func (m *manager) closeDir(req *managerRequest) (resp *managerResponse) { + resp = new(managerResponse) + h, ok := m.dirHandles[req.fh] + if !ok { + resp.err = os.NewError(fmt.Sprintf("closeDir: unknown handle %d", req.fh)) + return + } + m.dirHandles[h.fh] = nil, false + close(h.req) + return +} + +func readDirRoutine(requests chan *dirRequest) { + defer close(requests) + entries := []*dirEntry{ + &dirEntry{"lala111", S_IFDIR}, + &dirEntry{"bb", S_IFDIR}, + &dirEntry{"ddddd", S_IFDIR}, + } + i := 0 + for req := range requests { + if req.isClose { + return + } + if i < len(entries) { + req.resp <- &dirResponse{[]*dirEntry{entries[i]}, nil} + i++ + } else { + req.resp <- &dirResponse{nil, nil} + } + } +}