├── .gitignore ├── README.md ├── disklib └── disklib.go ├── filesys ├── dir.go ├── file.go ├── fs.go └── node.go ├── license ├── main.go └── working.png /.gitignore: -------------------------------------------------------------------------------- 1 | data/ 2 | .floo 3 | .flooignore 4 | disklib/sda -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # litfs 2 | 3 | ![Image of litfs at work](https://raw.githubusercontent.com/anaskhan96/litfs/master/working.png) 4 | 5 | This FUSE filesystem, apart from providing the normal file I/O operations, implements persistence by emulating a single binary Unix file as disk and performing read/writes on it. 6 | 7 | ## Build and Run 8 | 9 | ```bash 10 | go get github.com/anaskhan96/litfs 11 | cd $GOPATH/src/github.com/anaskhan96/litfs 12 | go run main.go data # data/ is the directory on which to mount the filesystem on 13 | ``` 14 | 15 | Run `umount ` to unmount the filesystem. 16 | 17 | ## File System Characteristics 18 | 19 | - Create, remove a directory 20 | - Create, remove, read from, and write to files inside a directory 21 | - Copy, move the contents of a file to another, across directories 22 | 23 | ## Persistence Implementation 24 | 25 | `disklib/sda` is the created binary file emulating a disk. Keeping a block size of `4096` bytes: 26 | 27 | - A serialized form of the tree representation of the filesystem is stored in the first block 28 | - A structure containing two components - a bitmap indicating free and allocated blocks in the filesystem and an integer containing the lowest free block at the moment - is serialized and stored in the second block 29 | - File data is stored from the third block onwards, with a block as a whole being allocated to/deallocated from the file 30 | 31 | --- 32 | 33 | This project was built under the course *Unix Systems Programming* at *PES University*. 34 | -------------------------------------------------------------------------------- /disklib/disklib.go: -------------------------------------------------------------------------------- 1 | /* First block - metadata and structure of the filesystem 2 | Second block - bit array of free and used blocks */ 3 | 4 | package disklib 5 | 6 | import ( 7 | "bytes" 8 | "encoding/json" 9 | "github.com/Workiva/go-datastructures/bitarray" 10 | "log" 11 | "os" 12 | ) 13 | 14 | const ( 15 | DISKSIZE int = 3 16 | BLKSIZE int = 4096 17 | ) 18 | 19 | type MetaBlock struct { 20 | Bitmap []byte 21 | LowestFree int 22 | } 23 | 24 | var metaBlockMem MetaBlock 25 | 26 | func OpenDisk(filename string, mbytes int) (*os.File, error) { 27 | if _, err := os.Stat(filename); err == nil { 28 | if f, err := os.OpenFile(filename, os.O_RDWR, 0666); err == nil { 29 | return f, nil 30 | } 31 | } 32 | size := uint64(mbytes * 1024 * 1024) 33 | fd, _ := os.Create(filename) 34 | fd.Seek(int64(size-1), 0) 35 | fd.Write([]byte{0}) 36 | fd.Seek(0, 0) 37 | initBlocks(fd, size, uint64(BLKSIZE)) 38 | return fd, nil 39 | } 40 | 41 | func ReadBlock(disk *os.File, blocknr int, data *[]byte) (int, error) { 42 | if _, err := disk.Seek(int64(blocknr*BLKSIZE), 0); err != nil { 43 | return 0, err 44 | } 45 | nbytes, err := disk.Read(*data) 46 | if err != nil { 47 | return 0, err 48 | } 49 | *data = bytes.Trim(*data, string(byte(0))) 50 | return nbytes, nil 51 | } 52 | 53 | func WriteBlock(disk *os.File, blocknr int, data []byte) (int, error) { 54 | zeros := make([]byte, BLKSIZE) 55 | if _, err := disk.Seek(int64(blocknr*BLKSIZE), 0); err != nil { 56 | return 0, err 57 | } 58 | disk.Write(zeros) 59 | if len(data) == 0 { 60 | updateBlocks("del", blocknr) 61 | return 0, nil 62 | } 63 | if _, err := disk.Seek(-int64(BLKSIZE), 1); err != nil { 64 | return 0, err 65 | } 66 | nbytes, err := disk.Write(data) 67 | if err != nil { 68 | return 0, err 69 | } 70 | updateBlocks("set", blocknr) 71 | return nbytes, nil 72 | } 73 | 74 | func initBlocks(fd *os.File, size, blksize uint64) { 75 | ba := bitarray.NewBitArray(size / blksize) 76 | ba.SetBit(0) 77 | ba.SetBit(1) 78 | data, _ := bitarray.Marshal(ba) 79 | metaBlockMem = MetaBlock{data, 2} 80 | } 81 | 82 | func MetaToDisk(f *os.File) { 83 | metablock, _ := json.Marshal(metaBlockMem) 84 | WriteBlock(f, 1, metablock) 85 | } 86 | 87 | func DiskToMeta(data []byte) { 88 | json.Unmarshal(data, &metaBlockMem) 89 | } 90 | 91 | func updateBlocks(operation string, blocknr int) { 92 | if operation == "del" { 93 | ba, _ := bitarray.Unmarshal(metaBlockMem.Bitmap) 94 | ba.ClearBit(uint64(blocknr)) 95 | data, _ := bitarray.Marshal(ba) 96 | metaBlockMem.Bitmap = data 97 | if blocknr < metaBlockMem.LowestFree { 98 | metaBlockMem.LowestFree = blocknr 99 | } 100 | } else if operation == "set" { 101 | ba, _ := bitarray.Unmarshal(metaBlockMem.Bitmap) 102 | if ok, _ := ba.GetBit(uint64(blocknr)); !ok { 103 | ba.SetBit(uint64(blocknr)) 104 | data, _ := bitarray.Marshal(ba) 105 | metaBlockMem.Bitmap = data 106 | if blocknr == metaBlockMem.LowestFree { 107 | i := blocknr + 1 108 | for i < int(ba.Capacity()) { 109 | if ok, _ := ba.GetBit(uint64(i)); !ok { 110 | metaBlockMem.LowestFree = i 111 | break 112 | } 113 | i++ 114 | } 115 | } 116 | } 117 | } 118 | log.Println("New lowest free block:", metaBlockMem.LowestFree) 119 | } 120 | 121 | func GetLowestFreeBlock() int { 122 | return metaBlockMem.LowestFree 123 | } 124 | -------------------------------------------------------------------------------- /filesys/dir.go: -------------------------------------------------------------------------------- 1 | package filesys 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "sync" 7 | 8 | "golang.org/x/net/context" 9 | 10 | "bazil.org/fuse" 11 | "bazil.org/fuse/fs" 12 | "github.com/anaskhan96/litfs/disklib" 13 | "syscall" 14 | ) 15 | 16 | type Dir struct { 17 | Node 18 | Files *[]*File 19 | Directories *[]*Dir 20 | sync.Mutex 21 | } 22 | 23 | func (dir *Dir) Attr(ctx context.Context, attr *fuse.Attr) error { 24 | log.Println("Attributes for directory", dir.Name) 25 | attr.Inode = dir.Inode 26 | attr.Mode = os.ModeDir | 0444 27 | attr.BlockSize = uint32(disklib.BLKSIZE) 28 | return nil 29 | } 30 | 31 | func (dir *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) { 32 | log.Println("Lookup for ", name) 33 | if dir.Files != nil { 34 | for _, file := range *dir.Files { 35 | if file.Name == name { 36 | log.Println("Found match for directory lookup with size", file.Size) 37 | return file, nil 38 | } 39 | } 40 | } 41 | if dir.Directories != nil { 42 | for _, directory := range *dir.Directories { 43 | if directory.Name == name { 44 | log.Println("Found match for directory lookup") 45 | return directory, nil 46 | } 47 | } 48 | } 49 | return nil, fuse.ENOENT 50 | } 51 | 52 | func (dir *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) { 53 | log.Println("Mkdir request for name", req.Name) 54 | newDir := &Dir{Node: Node{Name: req.Name, Inode: NewInode()}} 55 | directories := []*Dir{newDir} 56 | if dir.Directories != nil { 57 | directories = append(*dir.Directories, directories...) 58 | } 59 | dir.Directories = &directories 60 | return newDir, nil 61 | 62 | } 63 | 64 | func (dir *Dir) ReadDir(ctx context.Context, name string) (fs.Node, error) { 65 | if dir.Files != nil { 66 | for _, file := range *dir.Files { 67 | if file.Name == name { 68 | return file, nil 69 | } 70 | } 71 | } 72 | if dir.Directories != nil { 73 | for _, directory := range *dir.Directories { 74 | if directory.Name == name { 75 | return directory, nil 76 | } 77 | } 78 | } 79 | return nil, fuse.ENOENT 80 | } 81 | 82 | func (dir *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) { 83 | log.Println("Create request for name", req.Name) 84 | newFile := &File{Node: Node{Name: req.Name, Inode: NewInode()}} 85 | files := []*File{newFile} 86 | if dir.Files != nil { 87 | files = append(files, *dir.Files...) 88 | } 89 | dir.Files = &files 90 | return newFile, newFile, nil 91 | } 92 | 93 | func (dir *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error { 94 | log.Println("Remove request for ", req.Name) 95 | if req.Dir && dir.Directories != nil { 96 | newDirs := []*Dir{} 97 | for _, directory := range *dir.Directories { 98 | if directory.Name != req.Name { 99 | newDirs = append(newDirs, directory) 100 | } else { 101 | if directory.Files != nil { 102 | return fuse.Errno(syscall.ENOTEMPTY) 103 | } 104 | } 105 | } 106 | dir.Directories = &newDirs 107 | return nil 108 | } else if !req.Dir && *dir.Files != nil { 109 | newFiles := []*File{} 110 | for _, file := range *dir.Files { 111 | if file.Name != req.Name { 112 | newFiles = append(newFiles, file) 113 | } else { 114 | /* Clear the allocated blocks */ 115 | data := make([]byte, 0) 116 | f, _ := disklib.OpenDisk("disklib/sda", disklib.DISKSIZE) 117 | defer f.Close() 118 | for _, i := range file.Blocks { 119 | disklib.WriteBlock(f, i, data) 120 | } 121 | } 122 | } 123 | dir.Files = &newFiles 124 | return nil 125 | } 126 | return fuse.ENOENT 127 | } 128 | 129 | func (dir *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { 130 | log.Println("Reading all dirs") 131 | var children []fuse.Dirent 132 | if dir.Files != nil { 133 | for _, file := range *dir.Files { 134 | children = append(children, fuse.Dirent{Inode: file.Inode, Type: fuse.DT_File, Name: file.Name}) 135 | } 136 | } 137 | if dir.Directories != nil { 138 | for _, directory := range *dir.Directories { 139 | children = append(children, fuse.Dirent{Inode: directory.Inode, Type: fuse.DT_Dir, Name: directory.Name}) 140 | } 141 | log.Println(len(children), " children for dir", dir.Name) 142 | } 143 | return children, nil 144 | } 145 | 146 | func (dir *Dir) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error { 147 | log.Println("Rename requested from", req.OldName, "to", req.NewName) 148 | nd := newDir.(*Dir) 149 | if dir.Inode == nd.Inode { 150 | dir.Lock() 151 | defer dir.Unlock() 152 | for _, file := range *dir.Files { 153 | if file.Name == req.OldName { 154 | file.Name = req.NewName 155 | return nil 156 | } 157 | } 158 | } else if dir.Inode < nd.Inode { 159 | dir.Lock() 160 | defer dir.Unlock() 161 | nd.Lock() 162 | defer nd.Unlock() 163 | var fileDirty *File 164 | for _, file := range *dir.Files { 165 | if file.Name == req.OldName { 166 | fileDirty = file 167 | break 168 | } 169 | } 170 | if fileDirty != nil { 171 | dirExists := false 172 | for _, directory := range *dir.Directories { 173 | if directory.Name == nd.Name { 174 | dirExists = true 175 | break 176 | } 177 | } 178 | if dirExists { 179 | // Removing the file 180 | files := []*File{} 181 | for _, file := range *dir.Files { 182 | if file != fileDirty { 183 | files = append(files, file) 184 | } 185 | } 186 | dir.Files = &files 187 | // Adding in the new directory 188 | ndFiles := []*File{fileDirty} 189 | if nd.Files != nil { 190 | ndFiles = append(ndFiles, *nd.Files...) 191 | } 192 | nd.Files = &ndFiles 193 | return nil 194 | } 195 | } 196 | } else { 197 | nd.Lock() 198 | defer nd.Unlock() 199 | dir.Lock() 200 | defer dir.Unlock() 201 | var fileDirty *File 202 | for _, file := range *dir.Files { 203 | if file.Name == req.OldName { 204 | fileDirty = file 205 | break 206 | } 207 | } 208 | if fileDirty != nil { 209 | dirExists := false 210 | for _, directory := range *nd.Directories { 211 | if directory == dir { 212 | dirExists = true 213 | break 214 | } 215 | } 216 | if dirExists { 217 | // Removing the file 218 | files := []*File{} 219 | for _, file := range *dir.Files { 220 | if file != fileDirty { 221 | files = append(files, file) 222 | } 223 | } 224 | dir.Files = &files 225 | // Adding in the new directory 226 | ndFiles := []*File{fileDirty} 227 | if nd.Files != nil { 228 | ndFiles = append(ndFiles, *nd.Files...) 229 | } 230 | nd.Files = &ndFiles 231 | } 232 | return nil 233 | } 234 | } 235 | return fuse.ENOENT 236 | } 237 | -------------------------------------------------------------------------------- /filesys/file.go: -------------------------------------------------------------------------------- 1 | package filesys 2 | 3 | import ( 4 | "log" 5 | 6 | "bazil.org/fuse" 7 | "bazil.org/fuse/fs" 8 | "bazil.org/fuse/fuseutil" 9 | "github.com/anaskhan96/litfs/disklib" 10 | "golang.org/x/net/context" 11 | "math" 12 | "sync" 13 | ) 14 | 15 | type File struct { 16 | Node 17 | //Data []byte 18 | sync.Mutex 19 | } 20 | 21 | func (file *File) Attr(ctx context.Context, attr *fuse.Attr) error { 22 | log.Println("Attributes for file", file.Name) 23 | attr.Inode = file.Inode 24 | attr.Mode = 0777 25 | attr.Size = file.Size 26 | attr.BlockSize = uint32(disklib.BLKSIZE) 27 | attr.Blocks = uint64(len(file.Blocks)) 28 | return nil 29 | } 30 | 31 | /* Look at this function later because it's not supposed to return the whole data */ 32 | func (file *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { 33 | log.Println("Requested Read on File", file.Name) 34 | data := make([]byte, 0, 10) 35 | f, _ := disklib.OpenDisk("disklib/sda", disklib.DISKSIZE) 36 | defer f.Close() 37 | for i := 0; i < len(file.Blocks); i++ { 38 | blockData := make([]byte, disklib.BLKSIZE) 39 | disklib.ReadBlock(f, file.Blocks[i], &blockData) 40 | data = append(data, blockData...) 41 | } 42 | fuseutil.HandleRead(req, resp, data) 43 | return nil 44 | } 45 | 46 | func (file *File) ReadAll(ctx context.Context) ([]byte, error) { 47 | log.Println("Reading all of file", file.Name) 48 | data := make([]byte, 0, 10) 49 | f, _ := disklib.OpenDisk("disklib/sda", disklib.DISKSIZE) 50 | defer f.Close() 51 | for i := 0; i < len(file.Blocks); i++ { 52 | blockData := make([]byte, disklib.BLKSIZE) 53 | disklib.ReadBlock(f, file.Blocks[i], &blockData) 54 | data = append(data, blockData...) 55 | } 56 | return []byte(data), nil 57 | } 58 | 59 | func (file *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error { 60 | log.Println("Trying to write to", file.Name, "data:", string(req.Data)) 61 | file.Lock() 62 | defer file.Unlock() 63 | resp.Size = len(req.Data) 64 | file.Size = uint64(len(req.Data)) 65 | numBlocks := int(math.Ceil(float64(file.Size) / float64(disklib.BLKSIZE))) 66 | blocks := make([]int, numBlocks) 67 | f, _ := disklib.OpenDisk("disklib/sda", disklib.DISKSIZE) 68 | defer f.Close() 69 | k, allocatedBlocks := 0, 0 70 | for i := 0; i < numBlocks; i++ { 71 | var blocknr int 72 | if allocatedBlocks < len(file.Blocks) { 73 | blocknr = file.Blocks[i] 74 | allocatedBlocks++ 75 | } else { 76 | blocknr = disklib.GetLowestFreeBlock() 77 | } 78 | var data []byte 79 | if i == numBlocks-1 { 80 | data = req.Data[k:] 81 | } else { 82 | data = req.Data[k:disklib.BLKSIZE] 83 | } 84 | k += disklib.BLKSIZE 85 | nbytes, err := disklib.WriteBlock(f, blocknr, data) 86 | log.Println("BYTES WRITTEN:", nbytes, "ERR:", err) 87 | blocks[i] = blocknr 88 | } 89 | file.Blocks = blocks 90 | log.Println(file.Blocks) 91 | log.Println("Wrote to file", file.Name) 92 | return nil 93 | } 94 | 95 | func (file *File) Flush(ctx context.Context, req *fuse.FlushRequest) error { 96 | log.Println("Flushing file", file.Name) 97 | return nil 98 | } 99 | 100 | func (file *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { 101 | log.Println("Open call on file", file.Name) 102 | return file, nil 103 | } 104 | 105 | func (file *File) Release(ctx context.Context, req *fuse.ReleaseRequest) error { 106 | log.Println("Release requested on file", file.Name) 107 | return nil 108 | } 109 | 110 | func (file *File) Fsync(ctx context.Context, req *fuse.FsyncRequest) error { 111 | log.Println("Fsync requested on file", file.Name) 112 | return nil 113 | } 114 | -------------------------------------------------------------------------------- /filesys/fs.go: -------------------------------------------------------------------------------- 1 | package filesys 2 | 3 | import ( 4 | "bazil.org/fuse/fs" 5 | "encoding/json" 6 | "github.com/anaskhan96/litfs/disklib" 7 | "log" 8 | ) 9 | 10 | type FS struct { 11 | RootDir *Dir 12 | } 13 | 14 | func (f *FS) Root() (fs.Node, error) { 15 | return f.RootDir, nil 16 | } 17 | 18 | func (fsys *FS) Destroy() { 19 | metadata, err := json.Marshal(&fsys) 20 | if err != nil { 21 | log.Println(err) 22 | } 23 | f, err := disklib.OpenDisk("disklib/sda", disklib.DISKSIZE) 24 | defer f.Close() 25 | disklib.WriteBlock(f, 0, metadata) 26 | disklib.MetaToDisk(f) 27 | } 28 | -------------------------------------------------------------------------------- /filesys/node.go: -------------------------------------------------------------------------------- 1 | package filesys 2 | 3 | var inode uint64 4 | 5 | // serves as the inode table 6 | type Node struct { 7 | Inode uint64 8 | Name string 9 | Blocks []int 10 | Size uint64 11 | } 12 | 13 | func NewInode() uint64 { 14 | inode++ 15 | return inode 16 | } 17 | 18 | func InitInode(n uint64) { 19 | inode = n 20 | } 21 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Anas Khan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/anaskhan96/litfs/disklib" 7 | "log" 8 | "os" 9 | "os/signal" 10 | "syscall" 11 | 12 | "github.com/anaskhan96/litfs/filesys" 13 | 14 | "bazil.org/fuse" 15 | "bazil.org/fuse/fs" 16 | ) 17 | 18 | var inodeCount uint64 19 | 20 | func main() { 21 | if len(os.Args) != 2 { 22 | fmt.Println("Provide directory for mounting") 23 | os.Exit(1) 24 | } 25 | 26 | mountpoint := os.Args[1] 27 | 28 | conn, err := fuse.Mount(mountpoint) 29 | if err != nil { 30 | log.Fatal(err) 31 | } 32 | defer conn.Close() 33 | 34 | server := fs.New(conn, nil) 35 | 36 | var fsys *filesys.FS 37 | if _, err := os.Stat("disklib/sda"); err == nil { 38 | f, _ := disklib.OpenDisk("disklib/sda", disklib.DISKSIZE) 39 | defer f.Close() 40 | metadataBytes := make([]byte, disklib.BLKSIZE) 41 | disklib.ReadBlock(f, 0, &metadataBytes) 42 | metablock := make([]byte, disklib.BLKSIZE) 43 | disklib.ReadBlock(f, 1, &metablock) 44 | disklib.DiskToMeta(metablock) 45 | metadataMap := make(map[string]interface{}) 46 | json.Unmarshal(metadataBytes, &metadataMap) 47 | rootDir, _ := metadataMap["RootDir"].(map[string]interface{}) 48 | root := setupDir(rootDir) 49 | fsys = &filesys.FS{&root} 50 | } else { 51 | fsys = &filesys.FS{&filesys.Dir{}} 52 | } 53 | if inodeCount != 0 { 54 | inodeCount-- 55 | } 56 | filesys.InitInode(inodeCount) 57 | 58 | log.Println("About to serve fs") 59 | //go cleanup(fsys) 60 | if err := server.Serve(fsys); err != nil { 61 | log.Panicln(err) 62 | } 63 | 64 | <-conn.Ready 65 | if err := conn.MountError; err != nil { 66 | log.Panicln(err) 67 | } 68 | } 69 | 70 | func setupDir(m map[string]interface{}) filesys.Dir { 71 | var dir filesys.Dir 72 | for key, value := range m { 73 | if key == "Inode" { 74 | inode, _ := value.(float64) 75 | dir.Inode = uint64(inode) 76 | inodeCount++ 77 | } else if key == "Name" { 78 | dir.Name, _ = value.(string) 79 | } else if key == "Files" { 80 | var files []*filesys.File 81 | allFiles, ok := value.([]interface{}) 82 | if !ok { 83 | dir.Files = nil 84 | continue 85 | } 86 | for _, i := range allFiles { 87 | val, _ := i.(map[string]interface{}) 88 | file := setupFile(val) 89 | files = append(files, &file) 90 | } 91 | dir.Files = &files 92 | } else if key == "Directories" { 93 | var dirs []*filesys.Dir 94 | allDirs, ok := value.([]interface{}) 95 | if !ok { 96 | dir.Directories = nil 97 | continue 98 | } 99 | for _, i := range allDirs { 100 | val, _ := i.(map[string]interface{}) 101 | dirToAppend := setupDir(val) 102 | dirs = append(dirs, &dirToAppend) 103 | } 104 | dir.Directories = &dirs 105 | } 106 | } 107 | return dir 108 | } 109 | 110 | func setupFile(m map[string]interface{}) filesys.File { 111 | var file filesys.File 112 | for key, value := range m { 113 | if key == "Inode" { 114 | inode, _ := value.(float64) 115 | file.Inode = uint64(inode) 116 | inodeCount++ 117 | } else if key == "Name" { 118 | file.Name, _ = value.(string) 119 | /*} else if key == "Data" { 120 | data, _ := value.(string) 121 | file.Data, _ = base64.StdEncoding.DecodeString(data)*/ 122 | } else if key == "Blocks" { 123 | var blocks []int 124 | allBlocks, ok := value.([]interface{}) 125 | if !ok { 126 | file.Blocks = nil 127 | continue 128 | } 129 | for _, i := range allBlocks { 130 | val, _ := i.(float64) 131 | blocks = append(blocks, int(val)) 132 | } 133 | file.Blocks = blocks 134 | } else if key == "Size" { 135 | size, _ := value.(float64) 136 | file.Size = uint64(size) 137 | } 138 | } 139 | return file 140 | } 141 | 142 | /* Not being used; replaced by Destroy() in filesys/fs.go */ 143 | func cleanup(fsys *filesys.FS) { 144 | sigs := make(chan os.Signal, 1) 145 | done := make(chan bool, 1) 146 | 147 | signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) 148 | 149 | go func() { 150 | <-sigs 151 | done <- true 152 | }() 153 | 154 | <-done 155 | metadata, err := json.Marshal(&fsys) 156 | if err != nil { 157 | log.Println(err) 158 | } 159 | f, err := disklib.OpenDisk("disklib/sda", disklib.DISKSIZE) 160 | defer f.Close() 161 | disklib.WriteBlock(f, 0, metadata) 162 | disklib.MetaToDisk(f) 163 | 164 | // Unmounting the directory 165 | err = fuse.Unmount("data") 166 | if err != nil { 167 | log.Println(err) 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /working.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anaskhan96/litfs/c97c238e61f7b215385fef3ce06ce72f58c9b62b/working.png --------------------------------------------------------------------------------