diff options
author | Peter Wu <peter@lekensteyn.nl> | 2015-01-12 11:37:53 +0100 |
---|---|---|
committer | Peter Wu <peter@lekensteyn.nl> | 2015-01-12 11:37:53 +0100 |
commit | a77f2fc042a3bd84d8cadae6e877d928e91db3c7 (patch) | |
tree | 8b2297277b040c5dd35231447949f45de4c3fc67 | |
parent | c28bcc04f41f6b70e43fff87959ecf819388064c (diff) | |
download | c-files-a77f2fc042a3bd84d8cadae6e877d928e91db3c7.tar.gz |
swap: atomically renames a file
Uses the renameat2 syscall from Linux 3.15.
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | swap.c | 51 |
2 files changed, 55 insertions, 0 deletions
@@ -9,4 +9,8 @@ hex2bin slice nntp-get revb +wipe-sectors +xor +timeadd *.swp +swap @@ -0,0 +1,51 @@ +/* Rename two files atomically, swapping one for the other. + * Copyright (C) 2015 Peter Wu <peter@lekensteyn.nl> + */ + +#define _GNU_SOURCE +#include <unistd.h> +#include <sys/syscall.h> +#include <linux/fs.h> /* for RENAME_* */ +#include <fcntl.h> /* for AT_* */ +#include <stdio.h> +#include <errno.h> + +int renameat2(int olddirfd, const char *oldpath, + int newdirfd, const char *newpath, unsigned int flags) +{ + long r; + r = syscall(SYS_renameat2, olddirfd, oldpath, newdirfd, newpath, flags); + return (int)r; +} + +int main(int argc, char **argv) +{ + int olddirfd, newdirfd; + const char *oldpath, *newpath; + unsigned flags; + int r; + + if (argc - 1 < 2) { + fprintf(stderr, "Usage: %s file1 file2\n", argv[0]); + fprintf(stderr, "Atomically swaps file1 and file2.\n"); + return 1; + } + + olddirfd = AT_FDCWD; + newdirfd = AT_FDCWD; + oldpath = argv[1]; + newpath = argv[2]; + flags = RENAME_EXCHANGE; + + r = renameat2(olddirfd, oldpath, newdirfd, newpath, flags); + if (r < 0) { + if (errno == ENOSYS) { + fprintf(stderr, "renameat2 syscall not available!" + " You need Linux 3.15 or newer.\n"); + } else { + perror("renameat2 failed"); + } + } + + return r < 0 ? 1 : 0; +} |