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