1
1
package rpc
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"encoding/json"
6
7
"fmt"
7
8
"io"
9
+ "os"
10
+ "strconv"
11
+ "time"
8
12
9
13
"github.com/ipfs/boxo/files"
10
14
unixfs "github.com/ipfs/boxo/ipld/unixfs"
@@ -24,20 +28,35 @@ func (api *UnixfsAPI) Get(ctx context.Context, p path.Path) (files.Node, error)
24
28
}
25
29
26
30
var stat struct {
27
- Hash string
28
- Type string
29
- Size int64 // unixfs size
31
+ Hash string
32
+ Type string
33
+ Size int64 // unixfs size
34
+ Mode string
35
+ Mtime int64
36
+ MtimeNsecs int
30
37
}
31
38
err := api .core ().Request ("files/stat" , p .String ()).Exec (ctx , & stat )
32
39
if err != nil {
33
40
return nil , err
34
41
}
35
42
43
+ mode , err := stringToFileMode (stat .Mode )
44
+ if err != nil {
45
+ return nil , err
46
+ }
47
+
48
+ var modTime time.Time
49
+ if stat .Mtime != 0 {
50
+ modTime = time .Unix (stat .Mtime , int64 (stat .MtimeNsecs )).UTC ()
51
+ }
52
+
36
53
switch stat .Type {
37
54
case "file" :
38
- return api .getFile (ctx , p , stat .Size )
55
+ return api .getFile (ctx , p , stat .Size , mode , modTime )
39
56
case "directory" :
40
- return api .getDir (ctx , p , stat .Size )
57
+ return api .getDir (ctx , p , stat .Size , mode , modTime )
58
+ case "symlink" :
59
+ return api .getSymlink (ctx , p , modTime )
41
60
default :
42
61
return nil , fmt .Errorf ("unsupported file type '%s'" , stat .Type )
43
62
}
@@ -49,6 +68,9 @@ type apiFile struct {
49
68
size int64
50
69
path path.Path
51
70
71
+ mode os.FileMode
72
+ mtime time.Time
73
+
52
74
r * Response
53
75
at int64
54
76
}
@@ -128,16 +150,37 @@ func (f *apiFile) Close() error {
128
150
return nil
129
151
}
130
152
153
+ func (f * apiFile ) Mode () os.FileMode {
154
+ return f .mode
155
+ }
156
+
157
+ func (f * apiFile ) ModTime () time.Time {
158
+ return f .mtime
159
+ }
160
+
131
161
func (f * apiFile ) Size () (int64 , error ) {
132
162
return f .size , nil
133
163
}
134
164
135
- func (api * UnixfsAPI ) getFile (ctx context.Context , p path.Path , size int64 ) (files.Node , error ) {
165
+ func stringToFileMode (mode string ) (os.FileMode , error ) {
166
+ if mode == "" {
167
+ return 0 , nil
168
+ }
169
+ mode64 , err := strconv .ParseUint (mode , 8 , 32 )
170
+ if err != nil {
171
+ return 0 , fmt .Errorf ("cannot parse mode %s: %s" , mode , err )
172
+ }
173
+ return os .FileMode (uint32 (mode64 )), nil
174
+ }
175
+
176
+ func (api * UnixfsAPI ) getFile (ctx context.Context , p path.Path , size int64 , mode os.FileMode , mtime time.Time ) (files.Node , error ) {
136
177
f := & apiFile {
137
- ctx : ctx ,
138
- core : api .core (),
139
- size : size ,
140
- path : p ,
178
+ ctx : ctx ,
179
+ core : api .core (),
180
+ size : size ,
181
+ path : p ,
182
+ mode : mode ,
183
+ mtime : mtime ,
141
184
}
142
185
143
186
return f , f .reset ()
@@ -195,13 +238,19 @@ func (it *apiIter) Next() bool {
195
238
196
239
switch it .cur .Type {
197
240
case unixfs .THAMTShard , unixfs .TMetadata , unixfs .TDirectory :
198
- it .curFile , err = it .core .getDir (it .ctx , path .FromCid (c ), int64 (it .cur .Size ))
241
+ it .curFile , err = it .core .getDir (it .ctx , path .FromCid (c ), int64 (it .cur .Size ), it . cur . Mode , it . cur . ModTime )
199
242
if err != nil {
200
243
it .err = err
201
244
return false
202
245
}
203
246
case unixfs .TFile :
204
- it .curFile , err = it .core .getFile (it .ctx , path .FromCid (c ), int64 (it .cur .Size ))
247
+ it .curFile , err = it .core .getFile (it .ctx , path .FromCid (c ), int64 (it .cur .Size ), it .cur .Mode , it .cur .ModTime )
248
+ if err != nil {
249
+ it .err = err
250
+ return false
251
+ }
252
+ case unixfs .TSymlink :
253
+ it .curFile , err = it .core .getSymlink (it .ctx , path .FromCid (c ), it .cur .ModTime )
205
254
if err != nil {
206
255
it .err = err
207
256
return false
@@ -223,13 +272,24 @@ type apiDir struct {
223
272
size int64
224
273
path path.Path
225
274
275
+ mode os.FileMode
276
+ mtime time.Time
277
+
226
278
dec * json.Decoder
227
279
}
228
280
229
281
func (d * apiDir ) Close () error {
230
282
return nil
231
283
}
232
284
285
+ func (d * apiDir ) Mode () os.FileMode {
286
+ return d .mode
287
+ }
288
+
289
+ func (d * apiDir ) ModTime () time.Time {
290
+ return d .mtime
291
+ }
292
+
233
293
func (d * apiDir ) Size () (int64 , error ) {
234
294
return d .size , nil
235
295
}
@@ -242,7 +302,7 @@ func (d *apiDir) Entries() files.DirIterator {
242
302
}
243
303
}
244
304
245
- func (api * UnixfsAPI ) getDir (ctx context.Context , p path.Path , size int64 ) (files.Node , error ) {
305
+ func (api * UnixfsAPI ) getDir (ctx context.Context , p path.Path , size int64 , mode os. FileMode , modTime time. Time ) (files.Node , error ) {
246
306
resp , err := api .core ().Request ("ls" , p .String ()).
247
307
Option ("resolve-size" , true ).
248
308
Option ("stream" , true ).Send (ctx )
@@ -253,18 +313,43 @@ func (api *UnixfsAPI) getDir(ctx context.Context, p path.Path, size int64) (file
253
313
return nil , resp .Error
254
314
}
255
315
256
- d := & apiDir {
257
- ctx : ctx ,
258
- core : api ,
259
- size : size ,
260
- path : p ,
316
+ data , _ := io .ReadAll (resp .Output )
317
+ rdr := bytes .NewReader (data )
261
318
262
- dec : json .NewDecoder (resp .Output ),
319
+ d := & apiDir {
320
+ ctx : ctx ,
321
+ core : api ,
322
+ size : size ,
323
+ path : p ,
324
+ mode : mode ,
325
+ mtime : modTime ,
326
+
327
+ //dec: json.NewDecoder(resp.Output),
328
+ dec : json .NewDecoder (rdr ),
263
329
}
264
330
265
331
return d , nil
266
332
}
267
333
334
+ func (api * UnixfsAPI ) getSymlink (ctx context.Context , p path.Path , modTime time.Time ) (files.Node , error ) {
335
+ resp , err := api .core ().Request ("cat" , p .String ()).
336
+ Option ("resolve-size" , true ).
337
+ Option ("stream" , true ).Send (ctx )
338
+ if err != nil {
339
+ return nil , err
340
+ }
341
+ if resp .Error != nil {
342
+ return nil , resp .Error
343
+ }
344
+
345
+ target , err := io .ReadAll (resp .Output )
346
+ if err != nil {
347
+ return nil , err
348
+ }
349
+
350
+ return files .NewSymlinkFile (string (target ), modTime ), nil
351
+ }
352
+
268
353
var (
269
354
_ files.File = & apiFile {}
270
355
_ files.Directory = & apiDir {}
0 commit comments