File: declone.c

package info (click to toggle)
hxtools 20231224-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,640 kB
  • sloc: ansic: 4,825; perl: 3,463; sh: 1,629; cpp: 353; makefile: 149
file content (107 lines) | stat: -rw-r--r-- 2,566 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// SPDX-License-Identifier: MIT
/*
 *	declone.c - break hardlink off a file
 *	written by Jan Engelhardt, 2021
 */
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libHX/defs.h>
#include <libHX/string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>

static void dofile(const char *file)
{
	struct stat sb;
	int infd = open(file, O_RDONLY);
	if (infd < 0) {
		fprintf(stderr, "Could not open %s: %s\n",
		        file, strerror(errno));
		return;
	}
	if (fstat(infd, &sb) < 0) {
		fprintf(stderr, "Could not stat %s: %s\n",
		        file, strerror(errno));
		goto out;
	}
	void *inmap = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, infd, 0);
	if (inmap == MAP_FAILED) {
		fprintf(stderr, "mmap %s: %s\n", file, strerror(errno));
		goto out;
	}

	char *cont_dir = HX_dirname(file);
	if (cont_dir == NULL) {
		fprintf(stderr, "%s\n", strerror(errno));
		goto out2;
	}
	hxmc_t *outname = HXmc_strinit(cont_dir);
	if (outname == NULL) {
		fprintf(stderr, "%s\n", strerror(errno));
		goto out3;
	}
	if (HXmc_strcat(&outname, "/decloneXXXXXX") == NULL) {
		fprintf(stderr, "%s\n", strerror(errno));
		goto out4;
	}
	if (mkstemp(outname) < 0) {
		fprintf(stderr, "mkstemp: %s\n", strerror(errno));
		goto out4;
	}
	int outfd = open(outname, O_RDWR, S_IRUGO | S_IWUGO);
	if (outfd < 0) {
		fprintf(stderr, "open %s: %s\n", outname, strerror(errno));
		goto out4;
	}
	if (ftruncate(outfd, sb.st_size) < 0) {
		fprintf(stderr, "ftruncate %s: %s\n", outname, strerror(errno));
		goto out5;
	}
	if (fchown(outfd, sb.st_uid, sb.st_gid) < 0 ||
	    fchmod(outfd, sb.st_mode) < 0) {
		fprintf(stderr, "fchown/fchmod %s: %s\n", outname, strerror(errno));
		goto out5;
	}
	void *outmap = mmap(NULL, sb.st_size, PROT_WRITE, MAP_SHARED, outfd, 0);
	if (outmap == MAP_FAILED) {
		fprintf(stderr, "mmap %s: %s\n", outname, strerror(errno));
		goto out5;
	}
	memcpy(outmap, inmap, sb.st_size);
	if (msync(outmap, sb.st_size, MS_ASYNC) < 0) {
		fprintf(stderr, "msync: %s\n", strerror(errno));
		goto out6;
	}
	if (rename(outname, file) < 0) {
		fprintf(stderr, "Could not replace %s: %s\n",
		        file, strerror(errno));
		goto out6;
	}
	printf("* %s\n", file);
 out6:
	munmap(outmap, sb.st_size);
 out5:
	close(outfd);
	unlink(outname);
 out4:
	HXmc_free(outname);
 out3:
	free(cont_dir);
 out2:
	munmap(inmap, sb.st_size);
 out:
	close(infd);
}

int main(int argc, const char **argv)
{
	++argv;
	for (; --argc > 0 && *argv != NULL; ++argv)
		dofile(*argv);
	return EXIT_SUCCESS;
}