do not edit — generated by btf.
git.druid.rocksindexdruid520kaboomsrc/user/mv.nsc

src/user/mv.nsc


include "syscalls.nsh";
include "lib.nsh";
include "string.nsh";
include "stdio.nsh";
 
/* mv src dst -- files only, not directories (kfs has no directory
 * move/rename primitive, and moving a whole subtree is a bigger
 * feature than "rename this file"). not a real rename either: kfs
 * has no rename-in-place at the directory-entry level yet, so this
 * is genuinely copy-then-delete (read src fully, sys_writefile it to
 * dst, sys_rm the old name) -- functionally a move (src is gone
 * afterward, dst has its content), just not atomic and not O(1) the
 * way a real rename would be. good enough until something actually
 * needs better.
 *
 * because the source is destroyed at the end, the order below is the
 * whole point:
 *   (0) if src and dst already name the same file -- same inode, by
 *       sys_ino, e.g. `mv /usr/k /usr/k`, or `cd /usr; mv k /usr/k`
 *       -- do nothing at all and succeed. copy-then-delete onto
 *       itself would rewrite the file and then rm the only copy.
 *   (1) read ALL of src (read_all returns 0 rather than a partial
 *       buffer).
 *   (2) write ALL of it to dst and check sys_writefile actually
 *       succeeded (kfs_save refuses a dst that's a directory rather
 *       than overwriting it).
 *   (3) only then sys_rm src.
 * any failure before (3) returns with src untouched. this used to
 * read at most 63488 bytes (kfs's old max file size), so moving
 * anything bigger wrote a truncated dst and then deleted the only full
 * copy. */
global i32
main(i32 argc, ptr argv)
{
	ptr src;
	ptr dst;
	u64 src_len;
	u64 dst_len;
	i32 fd;
	i64 n;
	i64 src_ino;
	ptr buf;
 
	if(argc < 3)
	{
		fputs(2, "usage: mv src dst\n");
		return 1;
	}
 
	src = argv_get(argv, 1);
	src_len = strlen(src);
	dst = argv_get(argv, 2);
	dst_len = strlen(dst);
 
	src_ino = sys_ino(src, src_len);
	if(src_ino >= 0 && sys_ino(dst, dst_len) == src_ino)
	{
		return 0; /* same file: moving it onto itself is a no-op */
	}
 
	fd = sys_open(src, src_len);
	if(fd < 0)
	{
		print_err(2, "mv", "source not found");
		return 1;
	}
 
	buf = read_all(fd, &n);
	sys_close(fd);
	if(buf == (ptr)0)
	{
		print_err(2, "mv", "read failed, source left in place");
		return 1;
	}
 
	if(sys_writefile(dst, dst_len, buf, (u64)n) == 0)
	{
		print_err(2, "mv", "write failed, source left in place");
		return 1;
	}
	if(sys_rm(src, src_len) == 0)
	{
		print_err(2, "mv", "warning: could not remove source");
		return 1;
	}
	return 0;
}
powered by btf.