Skip to content

Commit 56fdba2

Browse files
authored
Merge pull request #17 from CalebQ42/fuseBraz
Fuse SUCCESS
2 parents a015b16 + ffbf4eb commit 56fdba2

File tree

9 files changed

+320
-11
lines changed

9 files changed

+320
-11
lines changed

fuse.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package squashfs
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"io"
7+
8+
"github.com/CalebQ42/fuse"
9+
"github.com/CalebQ42/fuse/fs"
10+
"github.com/CalebQ42/squashfs/internal/inode"
11+
)
12+
13+
func (r *Reader) Mount(mountpoint string) (con *fuse.Conn, err error) {
14+
con, err = fuse.Mount(mountpoint, fuse.ReadOnly())
15+
if err != nil {
16+
return
17+
}
18+
err = fs.Serve(con, &squashFuse{r: r})
19+
return
20+
}
21+
22+
type squashFuse struct {
23+
r *Reader
24+
}
25+
26+
func (s *squashFuse) Root() (fs.Node, error) {
27+
return &fileNode{File: s.r.FS.File}, nil
28+
}
29+
30+
type fileNode struct {
31+
*File
32+
}
33+
34+
func (f *fileNode) Attr(ctx context.Context, attr *fuse.Attr) error {
35+
attr.Blocks = f.r.s.Size / 512
36+
if f.r.s.Size%512 > 0 {
37+
attr.Blocks++
38+
}
39+
attr.Gid = f.r.ids[f.i.GidInd]
40+
attr.Inode = uint64(f.i.Num)
41+
attr.Mode = f.i.Mode()
42+
attr.Nlink = f.i.LinkCount()
43+
attr.Size = f.i.Size()
44+
attr.Uid = f.r.ids[f.i.UidInd]
45+
return nil
46+
}
47+
48+
func (f *fileNode) Id() uint64 {
49+
return uint64(f.i.Num)
50+
}
51+
52+
func (f *fileNode) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) {
53+
return f.SymlinkPath(), nil
54+
}
55+
56+
func (f *fileNode) Lookup(ctx context.Context, name string) (fs.Node, error) {
57+
asFS, err := f.FS()
58+
if err != nil {
59+
return nil, fuse.ENOTDIR
60+
}
61+
ret, err := asFS.OpenFile(name)
62+
if err != nil {
63+
return nil, fuse.ENOENT
64+
}
65+
return &fileNode{File: ret}, nil
66+
}
67+
68+
func (f *fileNode) ReadAll(ctx context.Context) ([]byte, error) {
69+
if f.IsRegular() {
70+
var buf bytes.Buffer
71+
_, err := f.WriteTo(&buf)
72+
return buf.Bytes(), err
73+
}
74+
return nil, fuse.ENODATA
75+
}
76+
77+
func (f *fileNode) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
78+
if f.IsRegular() {
79+
buf := make([]byte, req.Size)
80+
n, err := f.File.ReadAt(buf, req.Offset)
81+
if err == io.EOF {
82+
resp.Data = buf[:n]
83+
}
84+
return nil
85+
}
86+
return fuse.ENODATA
87+
}
88+
89+
func (f *fileNode) ReadDirAll(ctx context.Context) (out []fuse.Dirent, err error) {
90+
asFS, err := f.FS()
91+
if err != nil {
92+
return nil, fuse.ENOTDIR
93+
}
94+
var t fuse.DirentType
95+
for i := range asFS.e {
96+
switch asFS.e[i].Type {
97+
case inode.Fil:
98+
t = fuse.DT_File
99+
case inode.Dir:
100+
t = fuse.DT_Dir
101+
case inode.Block:
102+
t = fuse.DT_Block
103+
case inode.Sym:
104+
t = fuse.DT_Link
105+
case inode.Char:
106+
t = fuse.DT_Char
107+
case inode.Fifo:
108+
t = fuse.DT_FIFO
109+
case inode.Sock:
110+
t = fuse.DT_Socket
111+
default:
112+
t = fuse.DT_Unknown
113+
}
114+
out = append(out, fuse.Dirent{
115+
Inode: uint64(asFS.e[i].Num),
116+
Type: t,
117+
Name: asFS.e[i].Name,
118+
})
119+
}
120+
return
121+
}

go.mod

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ module github.com/CalebQ42/squashfs
33
go 1.19
44

55
require (
6-
github.com/klauspost/compress v1.15.9
7-
github.com/pierrec/lz4/v4 v4.1.15
6+
github.com/CalebQ42/fuse v0.1.0
7+
github.com/klauspost/compress v1.15.12
8+
github.com/pierrec/lz4/v4 v4.1.17
89
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e
910
github.com/therootcompany/xz v1.0.1
1011
github.com/ulikunitz/xz v0.5.10
1112
)
13+
14+
require golang.org/x/sys v0.2.0 // indirect

go.sum

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
2-
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
3-
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
4-
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
1+
github.com/CalebQ42/fuse v0.1.0 h1:KLCNjun7zcd2kBNVFfH+SWJyhuwJdE0nhw5/q8K8HGQ=
2+
github.com/CalebQ42/fuse v0.1.0/go.mod h1:pJpoKG03HJKVhsp8o0YQYqmfbFsr3Eowt90yQGQVO+4=
3+
github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
4+
github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
5+
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
6+
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
57
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e h1:dCWirM5F3wMY+cmRda/B1BiPsFtmzXqV9b0hLWtVBMs=
68
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e/go.mod h1:9leZcVcItj6m9/CfHY5Em/iBrCz7js8LcRQGTKEEv2M=
79
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
810
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
911
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
1012
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
13+
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
14+
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

internal/data/fullreader.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,91 @@ func (r FullReader) process(index int, offset int64, out chan outDat) {
7979
}
8080
}
8181

82+
func (r FullReader) ReadAt(p []byte, off int64) (n int, err error) {
83+
out := make(chan outDat, len(r.sizes))
84+
offset := r.start
85+
num := len(r.sizes)
86+
start := off / int64(r.blockSize)
87+
end := len(p) / int(r.blockSize)
88+
if end%int(r.blockSize) > 0 {
89+
end++
90+
}
91+
if end > len(r.sizes) {
92+
if r.fragRdr != nil {
93+
end = len(r.sizes)
94+
} else {
95+
end = len(r.sizes) + 1
96+
}
97+
}
98+
for i := 0; i < num; i++ {
99+
if i < int(start) || i > end {
100+
offset += uint64(realSize(r.sizes[i]))
101+
continue
102+
}
103+
if i == num-1 && r.fragRdr != nil {
104+
go func() {
105+
rdr, e := r.fragRdr()
106+
if err != nil {
107+
out <- outDat{
108+
i: num - 1,
109+
err: e,
110+
}
111+
return
112+
}
113+
dat, e := io.ReadAll(rdr)
114+
out <- outDat{
115+
i: num - 1,
116+
err: e,
117+
data: dat,
118+
}
119+
if clr, ok := rdr.(io.Closer); ok {
120+
clr.Close()
121+
}
122+
}()
123+
continue
124+
}
125+
go r.process(i, int64(offset), out)
126+
offset += uint64(realSize(r.sizes[i]))
127+
}
128+
cache := make(map[int]outDat)
129+
for cur := start; cur < int64(end); {
130+
dat := <-out
131+
if dat.err != nil {
132+
err = dat.err
133+
return
134+
}
135+
if dat.i != int(cur) {
136+
cache[dat.i] = dat
137+
continue
138+
}
139+
if cur == start {
140+
dat.data = dat.data[off%int64(r.blockSize):]
141+
}
142+
for i := range dat.data {
143+
p[n+i] = dat.data[i]
144+
}
145+
n += len(dat.data)
146+
cur++
147+
var ok bool
148+
for {
149+
dat, ok = cache[int(cur)]
150+
if !ok {
151+
break
152+
}
153+
for i := range dat.data {
154+
p[n+i] = dat.data[i]
155+
}
156+
n += len(dat.data)
157+
cur++
158+
delete(cache, int(cur))
159+
}
160+
}
161+
if n < len(p) {
162+
err = io.EOF
163+
}
164+
return
165+
}
166+
82167
func (r FullReader) WriteTo(w io.Writer) (n int64, err error) {
83168
out := make(chan outDat, len(r.sizes))
84169
offset := r.start

internal/directory/directory.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type Entry struct {
2929
BlockStart uint32
3030
Type uint16
3131
Offset uint16
32+
Num uint32
3233
}
3334

3435
func readEntry(r io.Reader) (e entry, err error) {
@@ -72,6 +73,7 @@ func ReadEntries(rdr io.Reader, size uint32) (e []Entry, err error) {
7273
BlockStart: h.InodeStart,
7374
Type: en.Type,
7475
Offset: en.Offset,
76+
Num: h.Num + uint32(en.NumOffset),
7577
})
7678
}
7779
}

internal/inode/inode.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/binary"
55
"errors"
66
"io"
7+
"io/fs"
78
"strconv"
89
)
910

@@ -77,3 +78,66 @@ func Read(r io.Reader, blockSize uint32) (i Inode, err error) {
7778
}
7879
return
7980
}
81+
82+
func (i Inode) Mode() (out fs.FileMode) {
83+
out = fs.FileMode(i.Perm)
84+
switch i.Data.(type) {
85+
case Directory:
86+
out |= fs.ModeDir
87+
case EDirectory:
88+
out |= fs.ModeDir
89+
case Symlink:
90+
out |= fs.ModeSymlink
91+
case ESymlink:
92+
out |= fs.ModeSymlink
93+
case Device:
94+
out |= fs.ModeDevice
95+
case EDevice:
96+
out |= fs.ModeDevice
97+
case IPC:
98+
out |= fs.ModeNamedPipe
99+
case EIPC:
100+
out |= fs.ModeNamedPipe
101+
}
102+
return
103+
}
104+
105+
func (i Inode) LinkCount() uint32 {
106+
switch i.Data.(type) {
107+
case EFile:
108+
return i.Data.(EFile).LinkCount
109+
case Directory:
110+
return i.Data.(Directory).LinkCount
111+
case EDirectory:
112+
return i.Data.(EDirectory).LinkCount
113+
case Device:
114+
return i.Data.(Device).LinkCount
115+
case EDevice:
116+
return i.Data.(EDevice).LinkCount
117+
case IPC:
118+
return i.Data.(IPC).LinkCount
119+
case EIPC:
120+
return i.Data.(EIPC).LinkCount
121+
case Symlink:
122+
return i.Data.(Symlink).LinkCount
123+
case ESymlink:
124+
return i.Data.(ESymlink).LinkCount
125+
default:
126+
return 0
127+
}
128+
}
129+
130+
func (i Inode) Size() uint64 {
131+
switch i.Data.(type) {
132+
case File:
133+
return uint64(i.Data.(File).Size)
134+
case EFile:
135+
return i.Data.(EFile).Size
136+
// case Directory:
137+
// return uint64(i.Data.(Directory).Size)
138+
// case EDirectory:
139+
// return uint64(i.Data.(EDirectory).Size)
140+
default:
141+
return 0
142+
}
143+
}

reader_file.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strconv"
1111
"strings"
1212

13+
"github.com/CalebQ42/squashfs/internal/data"
1314
"github.com/CalebQ42/squashfs/internal/directory"
1415
"github.com/CalebQ42/squashfs/internal/inode"
1516
)
@@ -18,7 +19,7 @@ import (
1819
type File struct {
1920
i inode.Inode
2021
rdr io.Reader
21-
fullRdr io.WriterTo
22+
fullRdr *data.FullReader
2223
r *Reader
2324
parent *FS
2425
e directory.Entry
@@ -35,7 +36,7 @@ func (r Reader) newFile(en directory.Entry, parent *FS) (*File, error) {
3536
return nil, err
3637
}
3738
var rdr io.Reader
38-
var full io.WriterTo
39+
var full *data.FullReader
3940
if i.Type == inode.Fil || i.Type == inode.EFil {
4041
full, rdr, err = r.getReaders(i)
4142
if err != nil {
@@ -68,6 +69,10 @@ func (f File) Read(p []byte) (int, error) {
6869
return f.rdr.Read(p)
6970
}
7071

72+
func (f File) ReadAt(p []byte, off int64) (int, error) {
73+
return f.fullRdr.ReadAt(p, off)
74+
}
75+
7176
// WriteTo writes all data from the file to the writer. This is multi-threaded.
7277
// The underlying reader is seperate from the one used with Read and can be reused.
7378
func (f File) WriteTo(w io.Writer) (int64, error) {

0 commit comments

Comments
 (0)