cp method
Copies a file or directory from src to dst.
src may be an MFS path (/dir/file) or an IPFS path
(/ipfs/<cid>[/sub/path]), matching Kubo files cp. When dst ends
with a trailing slash the source is copied inside that directory under
its basename (ipfs files cp /src /dir/).
parents creates missing destination directories. force overwrites an
existing file at the destination; it refuses to overwrite a directory,
matching Kubo's unlinkNodeIfExists. Without force, an existing
destination of any kind is an error.
Implementation
Future<void> cp(
String src,
String dst, {
bool force = false,
bool parents = false,
}) async {
final denylist = _denylistService;
if (denylist != null && _pathLooksBlocked(src)) {
throw DenylistBlockedException(src);
}
final srcCid = await _resolveAny(src);
if (srcCid == null) {
throw Exception('Source path not found: $src');
}
// Kubo only treats the destination as a container when it ends with a
// trailing slash; an existing directory named without a slash is an
// "already exists" error there, not an implicit container.
var dstPath = dst;
if (dst.endsWith('/')) {
dstPath = '$dst${_basename(src)}';
}
final destParts = _splitPath(dstPath);
if (destParts.isEmpty) {
throw Exception('Cannot overwrite MFS root: $dst');
}
await _mutationLock.synchronized(() async {
await _modifyPath(destParts, (currentCid) async {
if (currentCid != null) {
if (!force) {
throw Exception('file already exists: $dst');
}
final existingType = await _unixfsType(currentCid);
if (existingType == Data_DataType.Directory ||
existingType == Data_DataType.HAMTShard) {
throw Exception(
'cp: cannot overwrite directory with --force: $dst',
);
}
}
return srcCid;
}, recursive: parents);
});
}