rm method

Future<void> rm(
  1. String path, {
  2. bool recursive = false,
  3. bool force = false,
})

Removes a file or directory at the given path.

force ignores missing paths and implies recursive for directories, matching Kubo files rm --force.

Implementation

Future<void> rm(
  String path, {
  bool recursive = false,
  bool force = false,
}) async {
  final parts = _splitPath(path);
  if (parts.isEmpty) throw Exception('Cannot remove root');

  final parentParts = parts.sublist(0, parts.length - 1);
  final nameToRemove = parts.last;

  await _mutationLock.synchronized(() async {
    await _modifyPath(parentParts, (parentCid) async {
      if (parentCid == null) {
        if (force) return null;
        throw Exception('Parent path not found');
      }
      final parentBlock = await _blockStore.getBlock(parentCid.encode());
      if (!parentBlock.found) {
        if (force) return null;
        throw Exception('Parent block not found');
      }

      final parentNode = PBNode.fromBuffer(parentBlock.block.data);
      final newLinks = parentNode.links
          .where((l) => l.name != nameToRemove)
          .toList();

      if (newLinks.length == parentNode.links.length) {
        // Nothing removed
        if (force) return parentCid;
        throw Exception('Path not found: $path');
      }

      final removeDirs = recursive || force;
      if (!removeDirs) {
        final removedLink = parentNode.links.firstWhere(
          (l) => l.name == nameToRemove,
        );
        final removedBlock = await _blockStore.getBlock(
          CID.fromBytes(Uint8List.fromList(removedLink.hash)).encode(),
        );
        if (removedBlock.found) {
          final removedNode = PBNode.fromBuffer(removedBlock.block.data);
          final unixData = Data.fromBuffer(removedNode.data);
          if (unixData.type == Data_DataType.Directory) {
            throw Exception('Cannot remove directory without -r: $path');
          }
        }
      }

      parentNode.links.clear();
      parentNode.links.addAll(newLinks);

      final newData = marshalDagPBNode(parentNode);
      final newCid = await CID.fromContent(newData, codec: 'dag-pb');
      await _blockStore.putBlock(
        Block(cid: newCid, data: newData, format: 'dag-pb'),
      );
      return newCid;
    });
  });
}