From d0b24abbf939e15f4236b4e1697cb4d906c0217c Mon Sep 17 00:00:00 2001 From: NorSomething Date: Sun, 29 Mar 2026 15:35:17 +0530 Subject: [PATCH 1/6] feat: add dynamic time attr modification --- cmd/radFS/main.go | 2 +- internal/fs/dir.go | 10 +++++++++- internal/fs/file.go | 20 ++++++++++++++++++++ internal/fs/fs.go | 7 +++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/cmd/radFS/main.go b/cmd/radFS/main.go index 1c91e8b..02cfc6f 100644 --- a/cmd/radFS/main.go +++ b/cmd/radFS/main.go @@ -54,7 +54,7 @@ func main() { signal.Notify(signals, os.Interrupt) <-signals - log.Println("Interrupt received: shutting down.") + log.Println(" Interrupt received: shutting down.") unmount_err := fuse.Unmount(cfg.mount) if unmount_err != nil { diff --git a/internal/fs/dir.go b/internal/fs/dir.go index 0c3cc2c..97c2d9e 100644 --- a/internal/fs/dir.go +++ b/internal/fs/dir.go @@ -5,6 +5,7 @@ import ( "log/slog" "os" "syscall" + "time" "bazil.org/fuse" "bazil.org/fuse/fs" @@ -99,7 +100,14 @@ func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.Cr d.mu.Lock() defer d.mu.Unlock() - f := &File{inode: nextInode(), data: []byte{}, mode: uint32(req.Mode)} + f := &File{ + inode: nextInode(), + data: []byte{}, + mode: uint32(req.Mode), + atime: time.Now(), + ctime: time.Now(), + mtime: time.Now(), + } d.Nodes[req.Name] = f return f, f, nil diff --git a/internal/fs/file.go b/internal/fs/file.go index b6c8860..3115ca6 100644 --- a/internal/fs/file.go +++ b/internal/fs/file.go @@ -3,6 +3,7 @@ package fs import ( "context" "os" + "time" "bazil.org/fuse" "bazil.org/fuse/fs" @@ -14,6 +15,9 @@ func (f *File) Attr(ctx context.Context, a *fuse.Attr) error { a.Inode = f.inode a.Mode = os.FileMode(f.mode) a.Size = uint64(len(f.data)) + a.Atime = f.atime + a.Mtime = f.mtime + a.Ctime = f.ctime return nil } @@ -36,6 +40,8 @@ func (f *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadR end = min(end, int64(len(f.data))) resp.Data = f.data[req.Offset:end] + f.atime = time.Now() + return nil } @@ -56,6 +62,9 @@ func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.Wri copy(f.data[req.Offset:], req.Data) resp.Size = len(req.Data) + f.mtime = time.Now() + f.ctime = time.Now() // writing to file constitutes changes in certain fields of inode too + return nil } @@ -66,6 +75,7 @@ func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse if req.Valid.Mode() { f.mode = uint32(req.Mode) + f.ctime = time.Now() // valid ctime done here } if req.Valid.Size() { @@ -78,9 +88,19 @@ func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse } } + if req.Valid.Atime() { + f.atime = req.Atime + } + if req.Valid.Mtime() { + f.mtime = req.Mtime + } + resp.Attr.Inode = f.inode resp.Attr.Mode = os.FileMode(f.mode) resp.Attr.Size = uint64(len(f.data)) + resp.Attr.Atime = f.atime + resp.Attr.Mtime = f.mtime + resp.Attr.Ctime = f.ctime return nil } diff --git a/internal/fs/fs.go b/internal/fs/fs.go index 8cee95e..db7444d 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -3,6 +3,7 @@ package fs import ( "sync" "sync/atomic" + "time" "bazil.org/fuse/fs" ) @@ -25,6 +26,9 @@ func (f *FS) Root() (fs.Node, error) { inode: nextInode(), data: []byte("Hello from radFS!\n"), mode: 0o666, + atime: time.Now(), + mtime: time.Now(), + ctime: time.Now(), }, }, fs: f, @@ -38,6 +42,9 @@ type File struct { inode uint64 data []byte mode uint32 + atime time.Time // read + mtime time.Time // write | truncate + ctime time.Time // metadata (setattr) } type Dir struct { From 0becccff4fd24f75ec61603272b079577866a413 Mon Sep 17 00:00:00 2001 From: NorSomething Date: Mon, 30 Mar 2026 00:38:40 +0530 Subject: [PATCH 2/6] feat: add dynamic time attr mods for dirs --- internal/fs/dir.go | 50 ++++++++++++++++++++++++++++++++++++++++++++- internal/fs/file.go | 2 ++ internal/fs/fs.go | 9 ++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/internal/fs/dir.go b/internal/fs/dir.go index 97c2d9e..cc0e23f 100644 --- a/internal/fs/dir.go +++ b/internal/fs/dir.go @@ -21,10 +21,38 @@ func (f *FS) DebugPrint(msg string, v ...any) { func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error { a.Inode = d.inode a.Mode = os.ModeDir | 0o755 + a.Atime = d.atime + a.Mtime = d.mtime + a.Ctime = d.ctime return nil } +func (d *Dir) Setattr(ctx context,Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error { + f.mu.Lock() + defer d.mu.Unlock() + + if req.Valid.Atime() { + d.atime = req.Atime + } + if req.Valid.A=Mtime() { + d.mtime = req.Mtime + } + if req.Valid.Ctime() { + d.ctime = req.Ctime + } + + resp.Attr.Inode = d.inode + resp.Attr.Mode = os.ModeDir | 0o755 + + resp.Attr.Atime = d.atime + resp.Attr.Mtime = d.mtime + resp.Attr.Ctime = d.Ctime + + return nil + +} + func (d *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) { d.fs.DebugPrint("LOOKUP", "fetching", name) @@ -37,6 +65,8 @@ func (d *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) { return nil, syscall.ENOENT } + d.atime = time.Now() + return node, nil } @@ -60,6 +90,8 @@ func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { entries = append(entries, fuse.Dirent{Name: name, Type: dt}) } + d.atime = time.Now() + return entries, nil } @@ -80,9 +112,19 @@ func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error return nil, syscall.EEXIST } - newDir := &Dir{inode: nextInode(), Nodes: make(map[string]fs.Node), fs: d.fs} + newDir := &Dir{ + inode: nextInode(), + Nodes: make(map[string]fs.Node), + fs: d.fs, + atime = time.Now(), + ctime = time.Now(), + mtime = time.Now() + } d.Nodes[req.Name] = newDir + d.mtime = time.Now() + d.ctime = time.Now() + return newDir, nil } @@ -110,6 +152,9 @@ func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.Cr } d.Nodes[req.Name] = f + d.mtime = time.Now() + d.ctime = time.Now() + return f, f, nil } @@ -139,5 +184,8 @@ func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error { delete(d.Nodes, req.Name) + d.mtime = time.Now() + d.ctime = time.Now() + return nil } diff --git a/internal/fs/file.go b/internal/fs/file.go index 3115ca6..f629997 100644 --- a/internal/fs/file.go +++ b/internal/fs/file.go @@ -18,6 +18,8 @@ func (f *File) Attr(ctx context.Context, a *fuse.Attr) error { a.Atime = f.atime a.Mtime = f.mtime a.Ctime = f.ctime + a.Uid = f.uid + a.Gid = f.gid return nil } diff --git a/internal/fs/fs.go b/internal/fs/fs.go index db7444d..07037dc 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -32,6 +32,9 @@ func (f *FS) Root() (fs.Node, error) { }, }, fs: f, + atime: time.Now(), + mtime: time.Now(), + ctime: time.Now(), } return root, nil @@ -45,6 +48,8 @@ type File struct { atime time.Time // read mtime time.Time // write | truncate ctime time.Time // metadata (setattr) + uid uint32 + gid uint32 } type Dir struct { @@ -52,4 +57,8 @@ type Dir struct { inode uint64 Nodes map[string]fs.Node fs *FS + atime time.Time + mtime time.Time + ctime time.Time + } From 3885e87c48e20a7017001de79a8d2d828c474d92 Mon Sep 17 00:00:00 2001 From: NorSomething Date: Mon, 30 Mar 2026 01:16:47 +0530 Subject: [PATCH 3/6] fix: bug and syntax error fixes --- internal/fs/dir.go | 28 ++++++++++++++-------------- internal/fs/file.go | 11 +++++++---- internal/fs/fs.go | 7 +++---- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/internal/fs/dir.go b/internal/fs/dir.go index cc0e23f..da9f1ff 100644 --- a/internal/fs/dir.go +++ b/internal/fs/dir.go @@ -28,26 +28,23 @@ func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error { return nil } -func (d *Dir) Setattr(ctx context,Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error { - f.mu.Lock() +func (d *Dir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error { + d.mu.Lock() defer d.mu.Unlock() if req.Valid.Atime() { d.atime = req.Atime } - if req.Valid.A=Mtime() { + if req.Valid.Mtime() { d.mtime = req.Mtime } - if req.Valid.Ctime() { - d.ctime = req.Ctime - } resp.Attr.Inode = d.inode resp.Attr.Mode = os.ModeDir | 0o755 resp.Attr.Atime = d.atime resp.Attr.Mtime = d.mtime - resp.Attr.Ctime = d.Ctime + resp.Attr.Ctime = d.ctime return nil @@ -115,10 +112,10 @@ func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error newDir := &Dir{ inode: nextInode(), Nodes: make(map[string]fs.Node), - fs: d.fs, - atime = time.Now(), - ctime = time.Now(), - mtime = time.Now() + fs: d.fs, + atime: time.Now(), + ctime: time.Now(), + mtime: time.Now(), } d.Nodes[req.Name] = newDir @@ -144,12 +141,16 @@ func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.Cr f := &File{ inode: nextInode(), - data: []byte{}, - mode: uint32(req.Mode), + data: []byte{}, + mode: uint32(req.Mode), atime: time.Now(), ctime: time.Now(), mtime: time.Now(), } + + if _, exists := d.Nodes[req.Name]; exists { // checking for dupes + return nil, nil, syscall.EEXIST + } d.Nodes[req.Name] = f d.mtime = time.Now() @@ -180,7 +181,6 @@ func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error { return syscall.ENOTEMPTY } } - delete(d.Nodes, req.Name) diff --git a/internal/fs/file.go b/internal/fs/file.go index f629997..8e86778 100644 --- a/internal/fs/file.go +++ b/internal/fs/file.go @@ -77,24 +77,27 @@ func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse if req.Valid.Mode() { f.mode = uint32(req.Mode) - f.ctime = time.Now() // valid ctime done here + f.ctime = time.Now() } if req.Valid.Size() { if req.Size < uint64(len(f.data)) { f.data = f.data[:req.Size] + f.ctime = time.Now() // cuz creating file here } else { newData := make([]byte, req.Size) copy(newData, f.data) f.data = newData } + f.mtime = time.Now() + f.ctime = time.Now() } if req.Valid.Atime() { f.atime = req.Atime } if req.Valid.Mtime() { - f.mtime = req.Mtime + f.mtime = req.Mtime } resp.Attr.Inode = f.inode @@ -113,5 +116,5 @@ func (f *File) Flush(ctx context.Context, req *fuse.FlushRequest) error { } func (f *File) Fsync(ctx context.Context, req *fuse.FsyncRequest) error { - return nil -} \ No newline at end of file + return nil +} diff --git a/internal/fs/fs.go b/internal/fs/fs.go index 07037dc..1179678 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -31,7 +31,7 @@ func (f *FS) Root() (fs.Node, error) { ctime: time.Now(), }, }, - fs: f, + fs: f, atime: time.Now(), mtime: time.Now(), ctime: time.Now(), @@ -48,8 +48,8 @@ type File struct { atime time.Time // read mtime time.Time // write | truncate ctime time.Time // metadata (setattr) - uid uint32 - gid uint32 + uid uint32 + gid uint32 } type Dir struct { @@ -60,5 +60,4 @@ type Dir struct { atime time.Time mtime time.Time ctime time.Time - } From 54c34192d8b38bef13e3351979e50a43188bf61f Mon Sep 17 00:00:00 2001 From: NorSomething Date: Mon, 30 Mar 2026 08:52:45 +0530 Subject: [PATCH 4/6] feat: add ctime updation in set attr --- internal/fs/dir.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/fs/dir.go b/internal/fs/dir.go index da9f1ff..6a6ef44 100644 --- a/internal/fs/dir.go +++ b/internal/fs/dir.go @@ -38,6 +38,7 @@ func (d *Dir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse. if req.Valid.Mtime() { d.mtime = req.Mtime } + d.ctime = time.Now() resp.Attr.Inode = d.inode resp.Attr.Mode = os.ModeDir | 0o755 From 829d06b7967672fb454674553985c0f57abbedac Mon Sep 17 00:00:00 2001 From: NorSomething Date: Thu, 2 Apr 2026 00:40:28 +0530 Subject: [PATCH 5/6] refactor(fs): switch file allocation to fixed-size blocks --- internal/fs/dir.go | 22 ++++++--- internal/fs/file.go | 110 +++++++++++++++++++++++++++++++++++--------- internal/fs/fs.go | 48 +++++++++++++------ 3 files changed, 137 insertions(+), 43 deletions(-) diff --git a/internal/fs/dir.go b/internal/fs/dir.go index 6a6ef44..e9c5dd4 100644 --- a/internal/fs/dir.go +++ b/internal/fs/dir.go @@ -24,6 +24,8 @@ func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error { a.Atime = d.atime a.Mtime = d.mtime a.Ctime = d.ctime + a.Uid = d.uid + a.Gid = d.gid return nil } @@ -32,6 +34,11 @@ func (d *Dir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse. d.mu.Lock() defer d.mu.Unlock() + if req.Valid.Uid() { + d.uid = req.Uid + d.ctime = time.Now() + } + if req.Valid.Atime() { d.atime = req.Atime } @@ -46,6 +53,8 @@ func (d *Dir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse. resp.Attr.Atime = d.atime resp.Attr.Mtime = d.mtime resp.Attr.Ctime = d.ctime + resp.Attr.Uid = d.uid + resp.Attr.Gid = d.gid return nil @@ -141,12 +150,13 @@ func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.Cr defer d.mu.Unlock() f := &File{ - inode: nextInode(), - data: []byte{}, - mode: uint32(req.Mode), - atime: time.Now(), - ctime: time.Now(), - mtime: time.Now(), + inode: nextInode(), + blocks: [][]byte{}, + size: 0, + mode: uint32(req.Mode), + atime: time.Now(), + ctime: time.Now(), + mtime: time.Now(), } if _, exists := d.Nodes[req.Name]; exists { // checking for dupes diff --git a/internal/fs/file.go b/internal/fs/file.go index 8e86778..6952bd7 100644 --- a/internal/fs/file.go +++ b/internal/fs/file.go @@ -9,12 +9,14 @@ import ( "bazil.org/fuse/fs" ) +const blockSize = 4096 + func (f *File) Attr(ctx context.Context, a *fuse.Attr) error { f.mu.Lock() defer f.mu.Unlock() a.Inode = f.inode a.Mode = os.FileMode(f.mode) - a.Size = uint64(len(f.data)) + a.Size = uint64(f.size) //using size instead of len because its [][]byte a.Atime = f.atime a.Mtime = f.mtime a.Ctime = f.ctime @@ -32,16 +34,34 @@ func (f *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadR f.mu.Lock() defer f.mu.Unlock() - if req.Offset >= int64(len(f.data)) { + // checking if reading is starting from offset that actually exists + if req.Offset >= int64(f.size) { resp.Data = []byte{} - return nil } + // so that we dont read past file size end := req.Offset + int64(req.Size) - end = min(end, int64(len(f.data))) - resp.Data = f.data[req.Offset:end] + if end > int64(f.size) { + end = int64(f.size) + } + + var result []byte // final fully read file as a single array that we will reeturn + offset := req.Offset + for offset < end { + blockIndex := offset / blockSize + blockOffset := offset % blockSize + + // min of how much space is left on currect block and how much data is left to read -> basically safety guard + toRead := min(int64(blockSize)-blockOffset, end-offset) + + result = append(result, f.blocks[blockIndex][blockOffset:blockOffset+toRead]...) //expanding each byte individually + + offset += toRead + } + + resp.Data = result f.atime = time.Now() return nil @@ -52,18 +72,37 @@ func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.Wri f.mu.Lock() defer f.mu.Unlock() - end := req.Offset + int64(len(req.Data)) + offset := req.Offset + data := req.Data + end := req.Offset + int64(len(req.Data)) // till where we'll be writing + + // grow blocks if needed + for end > int64(len(f.blocks))*blockSize { + f.blocks = append(f.blocks, make([]byte, blockSize)) + } - // Grow the buffer if needed - if end > int64(len(f.data)) { - newData := make([]byte, end) - copy(newData, f.data) - f.data = newData + // updating file size + if end > int64(f.size) { + f.size = uint64(end) } - copy(f.data[req.Offset:], req.Data) - resp.Size = len(req.Data) + written := 0 + + for len(data) > 0 { + blockIndex := offset / blockSize + blockOffset := offset % blockSize + + toWrite := min(int64(blockSize)-blockOffset, int64(len(data))) + + n := copy(f.blocks[blockIndex][blockOffset:blockOffset+toWrite], data[:toWrite]) + + data = data[n:] + offset += int64(n) + written += n + } + + resp.Size = written f.mtime = time.Now() f.ctime = time.Now() // writing to file constitutes changes in certain fields of inode too @@ -80,17 +119,42 @@ func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse f.ctime = time.Now() } - if req.Valid.Size() { - if req.Size < uint64(len(f.data)) { - f.data = f.data[:req.Size] - f.ctime = time.Now() // cuz creating file here - } else { - newData := make([]byte, req.Size) - copy(newData, f.data) - f.data = newData + if req.Valid.Uid() { + f.uid = req.Uid + f.ctime = time.Now() + } + + if req.Valid.Gid() { + f.gid = req.Gid + f.ctime = time.Now() + } + + if req.Valid.Size() { // mainly for truncate? + + new_size := req.Size + needed := (new_size + uint64(blockSize) - 1) / uint64(blockSize) // ceil division to find how many blocks are required to store the new size + + if new_size < f.size { //shrinking operation + + //start from where we need to start + f.blocks = f.blocks[:needed] + + if new_size > 0 { + last_offset := new_size % uint64(blockSize) + if last_offset != 0 { + clear(f.blocks[needed-1][last_offset:]) // since we are shirnking/truncating we need to remove(clear) the stuff we dont need + } + } + } else if new_size > f.size { // explanding operation + for uint64(len(f.blocks)) < needed { + f.blocks = append(f.blocks, make([]byte, blockSize)) + } } + + f.size = new_size f.mtime = time.Now() f.ctime = time.Now() + } if req.Valid.Atime() { @@ -102,10 +166,12 @@ func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse resp.Attr.Inode = f.inode resp.Attr.Mode = os.FileMode(f.mode) - resp.Attr.Size = uint64(len(f.data)) + resp.Attr.Size = f.size resp.Attr.Atime = f.atime resp.Attr.Mtime = f.mtime resp.Attr.Ctime = f.ctime + resp.Attr.Uid = f.uid + resp.Attr.Gid = f.gid return nil } diff --git a/internal/fs/fs.go b/internal/fs/fs.go index 1179678..eace9a2 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -1,6 +1,7 @@ package fs import ( + "os" "sync" "sync/atomic" "time" @@ -19,16 +20,30 @@ func nextInode() uint64 { } func (f *FS) Root() (fs.Node, error) { + + content := []byte("Hello from radFS!\n") + blocks := [][]byte{} + for i := 0; i < len(content); i += blockSize { + end := min(i+blockSize, len(content)) + block := make([]byte, blockSize) + copy(block, content[i:end]) + blocks = append(blocks, block) + } + root := &Dir{ inode: 1, Nodes: map[string]fs.Node{ + "hello.txt": &File{ - inode: nextInode(), - data: []byte("Hello from radFS!\n"), - mode: 0o666, - atime: time.Now(), - mtime: time.Now(), - ctime: time.Now(), + inode: nextInode(), + blocks: blocks, + size: uint64(len(content)), + mode: 0o666, + atime: time.Now(), + mtime: time.Now(), + ctime: time.Now(), + uid: uint32(os.Getuid()), + gid: uint32(os.Getgid()), }, }, fs: f, @@ -41,15 +56,16 @@ func (f *FS) Root() (fs.Node, error) { } type File struct { - mu sync.Mutex - inode uint64 - data []byte - mode uint32 - atime time.Time // read - mtime time.Time // write | truncate - ctime time.Time // metadata (setattr) - uid uint32 - gid uint32 + mu sync.Mutex + inode uint64 + blocks [][]byte + size uint64 + mode uint32 + atime time.Time // read + mtime time.Time // write | truncate + ctime time.Time // metadata (setattr) + uid uint32 + gid uint32 } type Dir struct { @@ -60,4 +76,6 @@ type Dir struct { atime time.Time mtime time.Time ctime time.Time + uid uint32 + gid uint32 } From 55068950051833f311777d7f5c94184fd3cabe63 Mon Sep 17 00:00:00 2001 From: NorSomething Date: Fri, 3 Apr 2026 00:42:20 +0530 Subject: [PATCH 6/6] feat: add chown support --- cmd/radFS/main.go | 3 ++- cmd/radFS/temp/a.txt | 0 internal/fs/dir.go | 10 ++++++++++ internal/fs/file.go | 21 ++++++++++++++------- internal/fs/fs.go | 2 ++ 5 files changed, 28 insertions(+), 8 deletions(-) mode change 100644 => 100755 cmd/radFS/main.go create mode 100644 cmd/radFS/temp/a.txt diff --git a/cmd/radFS/main.go b/cmd/radFS/main.go old mode 100644 new mode 100755 index 02cfc6f..76abfbb --- a/cmd/radFS/main.go +++ b/cmd/radFS/main.go @@ -37,7 +37,8 @@ func main() { } //c is a fuse connection to dev/fuse - c, err := fuse.Mount(cfg.mount) + //allowother() allows any user to access the point moint -> used in chown + c, err := fuse.Mount(cfg.mount, fuse.AllowOther()) if err != nil { log.Println(err) diff --git a/cmd/radFS/temp/a.txt b/cmd/radFS/temp/a.txt new file mode 100644 index 0000000..e69de29 diff --git a/internal/fs/dir.go b/internal/fs/dir.go index e9c5dd4..e1e8223 100644 --- a/internal/fs/dir.go +++ b/internal/fs/dir.go @@ -35,6 +35,12 @@ func (d *Dir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse. defer d.mu.Unlock() if req.Valid.Uid() { + + //if caller is not root and caller is trying to chown to uid that is not itself + if req.Header.Uid != 0 && req.Uid != req.Header.Uid { // to get the uid of the process making the req -> checking the caller + return syscall.EPERM + } + d.uid = req.Uid d.ctime = time.Now() } @@ -126,6 +132,8 @@ func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error atime: time.Now(), ctime: time.Now(), mtime: time.Now(), + uid: req.Uid, + gid: req.Gid, } d.Nodes[req.Name] = newDir @@ -157,6 +165,8 @@ func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.Cr atime: time.Now(), ctime: time.Now(), mtime: time.Now(), + uid: req.Uid, + gid: req.Gid, } if _, exists := d.Nodes[req.Name]; exists { // checking for dupes diff --git a/internal/fs/file.go b/internal/fs/file.go index 6952bd7..c0f7bae 100644 --- a/internal/fs/file.go +++ b/internal/fs/file.go @@ -4,6 +4,7 @@ import ( "context" "os" "time" + "syscall" "bazil.org/fuse" "bazil.org/fuse/fs" @@ -120,6 +121,12 @@ func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse } if req.Valid.Uid() { + + //if caller is not root and caller is trying to chown to uid that is not itself + if req.Header.Uid != 0 && req.Uid != req.Header.Uid{ // to get the uid of the process making the req -> checking the caller + return syscall.EPERM + } + f.uid = req.Uid f.ctime = time.Now() } @@ -131,27 +138,27 @@ func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse if req.Valid.Size() { // mainly for truncate? - new_size := req.Size - needed := (new_size + uint64(blockSize) - 1) / uint64(blockSize) // ceil division to find how many blocks are required to store the new size + newSize := req.Size + needed := (newSize + uint64(blockSize) - 1) / uint64(blockSize) // ceil division to find how many blocks are required to store the new size - if new_size < f.size { //shrinking operation + if newSize < f.size { //shrinking operation //start from where we need to start f.blocks = f.blocks[:needed] - if new_size > 0 { - last_offset := new_size % uint64(blockSize) + if newSize > 0 { + last_offset := newSize % uint64(blockSize) if last_offset != 0 { clear(f.blocks[needed-1][last_offset:]) // since we are shirnking/truncating we need to remove(clear) the stuff we dont need } } - } else if new_size > f.size { // explanding operation + } else if newSize > f.size { // explanding operation for uint64(len(f.blocks)) < needed { f.blocks = append(f.blocks, make([]byte, blockSize)) } } - f.size = new_size + f.size = newSize f.mtime = time.Now() f.ctime = time.Now() diff --git a/internal/fs/fs.go b/internal/fs/fs.go index eace9a2..b8a90b1 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -50,6 +50,8 @@ func (f *FS) Root() (fs.Node, error) { atime: time.Now(), mtime: time.Now(), ctime: time.Now(), + uid: uint32(os.Getuid()), + gid: uint32(os.Getgid()), } return root, nil