35
35
import securesystemslib .settings
36
36
import securesystemslib .hash
37
37
import securesystemslib .formats
38
+ import securesystemslib .storage
38
39
39
40
import six
40
41
41
42
logger = logging .getLogger (__name__ )
42
43
43
44
44
- def get_file_details (filepath , hash_algorithms = ['sha256' ]):
45
+ def get_file_details (filepath , hash_algorithms = ['sha256' ],
46
+ storage_backend = None ):
45
47
"""
46
48
<Purpose>
47
49
To get file's length and hash information. The hash is computed using the
@@ -53,6 +55,13 @@ def get_file_details(filepath, hash_algorithms=['sha256']):
53
55
Absolute file path of a file.
54
56
55
57
hash_algorithms:
58
+ A list of hash algorithms with which the file's hash should be computed.
59
+ Defaults to ['sha256']
60
+
61
+ storage_backend:
62
+ An object which implements
63
+ securesystemslib.storage.StorageBackendInterface. When no object is
64
+ passed a FilesystemBackend will be instantiated and used.
56
65
57
66
<Exceptions>
58
67
securesystemslib.exceptions.FormatError: If hash of the file does not match
@@ -69,23 +78,22 @@ def get_file_details(filepath, hash_algorithms=['sha256']):
69
78
securesystemslib .formats .PATH_SCHEMA .check_match (filepath )
70
79
securesystemslib .formats .HASHALGORITHMS_SCHEMA .check_match (hash_algorithms )
71
80
81
+ if storage_backend is None :
82
+ storage_backend = securesystemslib .storage .FilesystemBackend ()
83
+
72
84
# The returned file hashes of 'filepath'.
73
85
file_hashes = {}
74
86
75
- # Does the path exists?
76
- if not os .path .exists (filepath ):
77
- raise securesystemslib .exceptions .Error ('Path ' + repr (filepath ) + ' doest'
78
- ' not exist.' )
79
-
80
87
filepath = os .path .abspath (filepath )
81
88
82
89
# Obtaining length of the file.
83
- file_length = os . path .getsize (filepath )
90
+ file_length = storage_backend .getsize (filepath )
84
91
85
- # Obtaining hash of the file.
86
- for algorithm in hash_algorithms :
87
- digest_object = securesystemslib .hash .digest_filename (filepath , algorithm )
88
- file_hashes .update ({algorithm : digest_object .hexdigest ()})
92
+ with storage_backend .get (filepath ) as fileobj :
93
+ # Obtaining hash of the file.
94
+ for algorithm in hash_algorithms :
95
+ digest_object = securesystemslib .hash .digest_fileobject (fileobj , algorithm )
96
+ file_hashes .update ({algorithm : digest_object .hexdigest ()})
89
97
90
98
# Performing a format check to ensure 'file_hash' corresponds HASHDICT_SCHEMA.
91
99
# Raise 'securesystemslib.exceptions.FormatError' if there is a mismatch.
@@ -94,11 +102,12 @@ def get_file_details(filepath, hash_algorithms=['sha256']):
94
102
return file_length , file_hashes
95
103
96
104
97
- def persist_temp_file (temp_file , persist_path ):
105
+ def persist_temp_file (temp_file , persist_path , storage_backend = None ,
106
+ should_close = True ):
98
107
"""
99
108
<Purpose>
100
109
Copies 'temp_file' (a file like object) to a newly created non-temp file at
101
- 'persist_path' and closes 'temp_file' so that it is removed .
110
+ 'persist_path'.
102
111
103
112
<Arguments>
104
113
temp_file:
@@ -108,26 +117,32 @@ def persist_temp_file(temp_file, persist_path):
108
117
persist_path:
109
118
File path to create the persistent file in.
110
119
120
+ storage_backend:
121
+ An object which implements
122
+ securesystemslib.storage.StorageBackendInterface. When no object is
123
+ passed a FilesystemBackend will be instantiated and used.
124
+
125
+ should_close:
126
+ A boolean indicating whether the file should be closed after it has been
127
+ persisted. Default is True, the file is closed.
128
+
111
129
<Exceptions>
112
130
None.
113
131
114
132
<Return>
115
133
None.
116
134
"""
117
135
118
- temp_file .flush ()
119
- temp_file .seek (0 )
136
+ if storage_backend is None :
137
+ storage_backend = securesystemslib .storage .FilesystemBackend ()
138
+
139
+ storage_backend .put (temp_file , persist_path )
120
140
121
- with open (persist_path , 'wb' ) as destination_file :
122
- shutil .copyfileobj (temp_file , destination_file )
123
- # Force the destination file to be written to disk from Python's internal
124
- # and the operation system's buffers. os.fsync() should follow flush().
125
- destination_file .flush ()
126
- os .fsync (destination_file .fileno ())
141
+ if should_close :
142
+ temp_file .close ()
127
143
128
- temp_file .close ()
129
144
130
- def ensure_parent_dir (filename ):
145
+ def ensure_parent_dir (filename , storage_backend = None ):
131
146
"""
132
147
<Purpose>
133
148
To ensure existence of the parent directory of 'filename'. If the parent
@@ -140,6 +155,11 @@ def ensure_parent_dir(filename):
140
155
filename:
141
156
A path string.
142
157
158
+ storage_backend:
159
+ An object which implements
160
+ securesystemslib.storage.StorageBackendInterface. When no object is
161
+ passed a FilesystemBackend will be instantiated and used.
162
+
143
163
<Exceptions>
144
164
securesystemslib.exceptions.FormatError: If 'filename' is improperly
145
165
formatted.
@@ -156,12 +176,13 @@ def ensure_parent_dir(filename):
156
176
# Raise 'securesystemslib.exceptions.FormatError' on a mismatch.
157
177
securesystemslib .formats .PATH_SCHEMA .check_match (filename )
158
178
179
+ if storage_backend is None :
180
+ storage_backend = securesystemslib .storage .FilesystemBackend ()
181
+
159
182
# Split 'filename' into head and tail, check if head exists.
160
183
directory = os .path .split (filename )[0 ]
161
184
162
- if directory and not os .path .exists (directory ):
163
- # mode = 'rwx------'. 448 (decimal) is 700 in octal.
164
- os .makedirs (directory , 448 )
185
+ storage_backend .create_folder (directory )
165
186
166
187
167
188
def file_in_confined_directories (filepath , confined_directories ):
@@ -296,7 +317,7 @@ def load_json_string(data):
296
317
return deserialized_object
297
318
298
319
299
- def load_json_file (filepath ):
320
+ def load_json_file (filepath , storage_backend = None ):
300
321
"""
301
322
<Purpose>
302
323
Deserialize a JSON object from a file containing the object.
@@ -305,6 +326,11 @@ def load_json_file(filepath):
305
326
filepath:
306
327
Absolute path of JSON file.
307
328
329
+ storage_backend:
330
+ An object which implements
331
+ securesystemslib.storage.StorageBackendInterface. When no object is
332
+ passed a FilesystemBackend will be instantiated and used.
333
+
308
334
<Exceptions>
309
335
securesystemslib.exceptions.FormatError: If 'filepath' is improperly
310
336
formatted.
@@ -325,21 +351,22 @@ def load_json_file(filepath):
325
351
# securesystemslib.exceptions.FormatError is raised on incorrect format.
326
352
securesystemslib .formats .PATH_SCHEMA .check_match (filepath )
327
353
328
- deserialized_object = None
329
- fileobject = open ( filepath )
354
+ if storage_backend is None :
355
+ storage_backend = securesystemslib . storage . FilesystemBackend ( )
330
356
331
- try :
332
- deserialized_object = json .load (fileobject )
357
+ deserialized_object = None
358
+ with storage_backend .get (filepath ) as file_obj :
359
+ raw_data = file_obj .read ().decode ('utf-8' )
333
360
334
- except (ValueError , TypeError ) as e :
335
- raise securesystemslib .exceptions .Error ('Cannot deserialize to a'
336
- ' Python object: ' + repr (filepath ))
361
+ try :
362
+ deserialized_object = json .loads (raw_data )
337
363
338
- else :
339
- return deserialized_object
364
+ except (ValueError , TypeError ) as e :
365
+ raise securesystemslib .exceptions .Error ('Cannot deserialize to a'
366
+ ' Python object: ' + filepath )
340
367
341
- finally :
342
- fileobject . close ()
368
+ else :
369
+ return deserialized_object
343
370
344
371
345
372
def digests_are_equal (digest1 , digest2 ):
0 commit comments