1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
11 from fresh import FreshBase, convertTime
13 _logger = logging.getLogger('arvados.arvados_fuse')
15 class File(FreshBase):
16 """Base for file objects."""
18 def __init__(self, parent_inode, _mtime=0):
19 super(File, self).__init__()
21 self.parent_inode = parent_inode
27 def readfrom(self, off, size, num_retries=0):
30 def writeto(self, off, size, num_retries=0):
31 raise Exception("Not writable")
46 class FuseArvadosFile(File):
47 """Wraps a ArvadosFile."""
49 def __init__(self, parent_inode, arvfile, _mtime):
50 super(FuseArvadosFile, self).__init__(parent_inode, _mtime)
51 self.arvfile = arvfile
54 with llfuse.lock_released:
55 return self.arvfile.size()
57 def readfrom(self, off, size, num_retries=0):
58 with llfuse.lock_released:
59 return self.arvfile.readfrom(off, size, num_retries, exact=True)
61 def writeto(self, off, buf, num_retries=0):
62 with llfuse.lock_released:
63 return self.arvfile.writeto(off, buf, num_retries)
69 return self.arvfile.writable()
72 with llfuse.lock_released:
74 self.arvfile.parent.root_collection().save()
77 class StringFile(File):
78 """Wrap a simple string as a file"""
79 def __init__(self, parent_inode, contents, _mtime):
80 super(StringFile, self).__init__(parent_inode, _mtime)
81 self.contents = contents
84 return len(self.contents)
86 def readfrom(self, off, size, num_retries=0):
87 return self.contents[off:(off+size)]
90 class ObjectFile(StringFile):
91 """Wrap a dict as a serialized json object."""
93 def __init__(self, parent_inode, obj):
94 super(ObjectFile, self).__init__(parent_inode, "", 0)
95 self.object_uuid = obj['uuid']
99 return self.object_uuid
101 def update(self, obj=None):
103 # TODO: retrieve the current record for self.object_uuid
104 # from the server. For now, at least don't crash when
105 # someone tells us it's a good time to update but doesn't
106 # pass us a fresh obj. See #8345
108 self._mtime = convertTime(obj['modified_at']) if 'modified_at' in obj else 0
109 self.contents = json.dumps(obj, indent=4, sort_keys=True) + "\n"
115 class FuncToJSONFile(StringFile):
116 """File content is the return value of a given function, encoded as JSON.
118 The function is called at the time the file is read. The result is
119 cached until invalidate() is called.
121 def __init__(self, parent_inode, func):
122 super(FuncToJSONFile, self).__init__(parent_inode, "", 0)
125 # invalidate_inode() is asynchronous with no callback to wait for. In
126 # order to guarantee userspace programs don't get stale data that was
127 # generated before the last invalidate(), we must disallow inode
129 self.allow_attr_cache = False
133 return super(FuncToJSONFile, self).size()
135 def readfrom(self, *args, **kwargs):
137 return super(FuncToJSONFile, self).readfrom(*args, **kwargs)
142 self._mtime = time.time()
144 self.contents = json.dumps(obj, indent=4, sort_keys=True) + "\n"