Expand capture-only NetScaler NITRO simulation and crash recovery
This commit is contained in:
1 parent
7b99db9e25
commit
c65f049223
10 files changed
+2097
-19
No files matched your search
+24
-2
@@ -6,6 +6,7 @@ import os
|
||||
import pathlib
|
||||
import threading
|
||||
import time
|
||||
import tempfile
|
||||
|
||||
|
||||
class EvidenceError(OSError):
|
||||
@@ -25,6 +26,21 @@ class Evidence:
|
||||
self.used = sum(p.stat().st_size for p in self.directory.rglob('*') if p.is_file())
|
||||
self.journal = os.open(self.directory / 'events.jsonl', os.O_WRONLY | os.O_APPEND | os.O_CREAT | os.O_NOFOLLOW, 0o600)
|
||||
os.fchmod(self.journal, 0o600)
|
||||
# Preserve a crash-interrupted record without merging the next event into it.
|
||||
with (self.directory / 'events.jsonl').open('rb') as previous:
|
||||
previous.seek(0, os.SEEK_END)
|
||||
if previous.tell():
|
||||
previous.seek(-1, os.SEEK_END)
|
||||
if previous.read(1) != b'\n':
|
||||
self.reserve(1)
|
||||
os.write(self.journal, b'\n')
|
||||
os.fsync(self.journal)
|
||||
self.used += 1
|
||||
directory = os.open(self.directory, os.O_RDONLY)
|
||||
try:
|
||||
os.fsync(directory)
|
||||
finally:
|
||||
os.close(directory)
|
||||
|
||||
def reserve(self, size):
|
||||
if self.used + size > self.quota:
|
||||
@@ -50,14 +66,20 @@ class Evidence:
|
||||
with self.lock:
|
||||
if not path.exists():
|
||||
self.reserve(len(data))
|
||||
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600)
|
||||
fd, temporary = tempfile.mkstemp(prefix='.capture-', dir=self.artifacts)
|
||||
try:
|
||||
with os.fdopen(fd, 'wb') as output:
|
||||
output.write(data)
|
||||
output.flush()
|
||||
os.fsync(output.fileno())
|
||||
os.replace(temporary, path)
|
||||
directory = os.open(self.artifacts, os.O_RDONLY)
|
||||
try:
|
||||
os.fsync(directory)
|
||||
finally:
|
||||
os.close(directory)
|
||||
except BaseException:
|
||||
path.unlink(missing_ok=True) # do not leave a partial blob with a full-content hash
|
||||
pathlib.Path(temporary).unlink(missing_ok=True)
|
||||
raise
|
||||
self.used += len(data)
|
||||
return dict(sha256=digest, bytes=len(data), artifact='artifacts/' + path.name)
|
||||
|
||||
Reference in new issue
Block a user