open static method

Future<OfficialFileStorage> open(
  1. String path, {
  2. int maxImageBytes = 64 * 1024 * 1024,
})

Implementation

static Future<OfficialFileStorage> open(String path,
    {int maxImageBytes = 64 * 1024 * 1024}) async {
  if (maxImageBytes < 100) throw RangeError.value(maxImageBytes);
  RandomAccessFile? file;
  RandomAccessFile? shm;
  int? walLock;
  var writable = true;
  try {
    try {
      file = await File(path).open(mode: FileMode.append);
    } on FileSystemException {
      writable = false;
      file = await File(path).open(mode: FileMode.read);
    }
    if (!await _tryLock(file, FileLock.shared, SqliteLock.sharedFirst,
        SqliteLock.sharedFirst + 1)) {
      throw const SqlException('database is locked');
    }
    final length = await file.length();
    Uint8List? image;
    final journalFile = File('$path-journal');
    if (journalFile.existsSync() && writable) {
      final journal = await journalFile.readAsBytes();
      if (HotJournal.looksHot(journal) &&
          await _tryLock(file, FileLock.exclusive, SqliteLock.reservedByte,
              SqliteLock.reservedByte + 1)) {
        try {
          final superName = HotJournal.superJournalName(journal);
          final blocked = superName != null && !File(superName).existsSync();
          if (!blocked) {
            if (length > maxImageBytes) {
              throw const FormatException('Image limit exceeded');
            }
            image =
                HotJournal.recover(await _readFully(file, length), journal);
          }
        } finally {
          await file.unlock(
              SqliteLock.reservedByte, SqliteLock.reservedByte + 1);
        }
      }
    }
    final walFile = File('$path-wal');
    if (walFile.existsSync()) {
      final shmFile = File('$path-shm');
      // A live SQLite connection keeps the locks in `-shm`. Creating that
      // file would change the sidecar set, so a leftover WAL with no
      // `-shm` is recovered without one.
      if (shmFile.existsSync()) {
        shm = await shmFile.open(mode: FileMode.read);
        for (var byte = SqliteLock.walRead;
            byte < SqliteLock.walRead + SqliteLock.walReadCount;
            byte++) {
          if (await _tryLock(shm, FileLock.shared, byte, byte + 1)) {
            walLock = byte;
            break;
          }
        }
        if (walLock == null) {
          throw const SqlException('database is locked');
        }
      }
      final wal = await walFile.readAsBytes();
      final base = image ?? await _readFully(file, length);
      if (base.length > maxImageBytes) {
        throw const FormatException('Image limit exceeded');
      }
      image = WalSnapshot.recover(base, wal, maxImageBytes: maxImageBytes);
    }
    return OfficialFileStorage._(file, image, shm, walLock);
  } catch (_) {
    if (shm != null) {
      try {
        if (walLock != null) {
          await shm.unlock(walLock, walLock + 1);
        }
      } catch (_) {}
      await shm.close();
    }
    if (file != null) {
      try {
        await file.unlock(SqliteLock.sharedFirst, SqliteLock.sharedFirst + 1);
      } catch (_) {}
      await file.close();
    }
    rethrow;
  }
}