13111: Merge branch 'master' into 12308-go-fuse
[arvados.git] / sdk / go / arvados / fs_filehandle.go
1 package arvados
2
3 import (
4         "io"
5         "os"
6 )
7
8 type filehandle struct {
9         inode
10         ptr        filenodePtr
11         append     bool
12         readable   bool
13         writable   bool
14         unreaddirs []os.FileInfo
15 }
16
17 func (f *filehandle) Read(p []byte) (n int, err error) {
18         if !f.readable {
19                 return 0, ErrWriteOnlyMode
20         }
21         f.inode.RLock()
22         defer f.inode.RUnlock()
23         n, f.ptr, err = f.inode.Read(p, f.ptr)
24         return
25 }
26
27 func (f *filehandle) Seek(off int64, whence int) (pos int64, err error) {
28         size := f.inode.Size()
29         ptr := f.ptr
30         switch whence {
31         case io.SeekStart:
32                 ptr.off = off
33         case io.SeekCurrent:
34                 ptr.off += off
35         case io.SeekEnd:
36                 ptr.off = size + off
37         }
38         if ptr.off < 0 {
39                 return f.ptr.off, ErrNegativeOffset
40         }
41         if ptr.off != f.ptr.off {
42                 f.ptr = ptr
43                 // force filenode to recompute f.ptr fields on next
44                 // use
45                 f.ptr.repacked = -1
46         }
47         return f.ptr.off, nil
48 }
49
50 func (f *filehandle) Truncate(size int64) error {
51         return f.inode.Truncate(size)
52 }
53
54 func (f *filehandle) Write(p []byte) (n int, err error) {
55         if !f.writable {
56                 return 0, ErrReadOnlyFile
57         }
58         f.inode.Lock()
59         defer f.inode.Unlock()
60         if fn, ok := f.inode.(*filenode); ok && f.append {
61                 f.ptr = filenodePtr{
62                         off:        fn.fileinfo.size,
63                         segmentIdx: len(fn.segments),
64                         segmentOff: 0,
65                         repacked:   fn.repacked,
66                 }
67         }
68         n, f.ptr, err = f.inode.Write(p, f.ptr)
69         return
70 }
71
72 func (f *filehandle) Readdir(count int) ([]os.FileInfo, error) {
73         if !f.inode.IsDir() {
74                 return nil, ErrInvalidOperation
75         }
76         if count <= 0 {
77                 return f.inode.Readdir(), nil
78         }
79         if f.unreaddirs == nil {
80                 f.unreaddirs = f.inode.Readdir()
81         }
82         if len(f.unreaddirs) == 0 {
83                 return nil, io.EOF
84         }
85         if count > len(f.unreaddirs) {
86                 count = len(f.unreaddirs)
87         }
88         ret := f.unreaddirs[:count]
89         f.unreaddirs = f.unreaddirs[count:]
90         return ret, nil
91 }
92
93 func (f *filehandle) Stat() (os.FileInfo, error) {
94         return f.inode.FileInfo(), nil
95 }
96
97 func (f *filehandle) Close() error {
98         return nil
99 }
100
101 func (f *filehandle) Sync() error {
102         // Sync the containing filesystem.
103         return f.FS().Sync()
104 }