summaryrefslogtreecommitdiff
path: root/Userland/truncate.cpp
blob: f4d2d209125254ce79d599f6f59c4aef19b68070 (plain)
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
#include <LibCore/CArgsParser.h>

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

enum TruncateOperation {
    OP_Set,
    OP_Grow,
    OP_Shrink,
};

int main(int argc, char** argv)
{
    CArgsParser args_parser("truncate");

    args_parser.add_arg("s", "size", "Resize the target file to (or by) this size. Prefix with + or - to expand or shrink the file, or a bare number to set the size exactly.");
    args_parser.add_arg("r", "reference", "Resize the target file to match the size of this one.");
    args_parser.add_required_single_value("file");

    CArgsParserResult args = args_parser.parse(argc, argv);

    if (!args.is_present("s") && !args.is_present("r")) {
        args_parser.print_usage();
        return -1;
    }

    if (args.is_present("s") && args.is_present("r")) {
        args_parser.print_usage();
        return -1;
    }

    auto op = OP_Set;
    int size = 0;

    if (args.is_present("s")) {
        auto str = args.get("s");

        switch (str[0]) {
        case '+':
            op = OP_Grow;
            str = str.substring(1, str.length() - 1);
            break;
        case '-':
            op = OP_Shrink;
            str = str.substring(1, str.length() - 1);
            break;
        }

        bool ok;
        size = str.to_int(ok);
        if (!ok) {
            args_parser.print_usage();
            return -1;
        }
    }

    if (args.is_present("r")) {
        struct stat st;
        int rc = stat(args.get("r").characters(), &st);
        if (rc < 0) {
            perror("stat");
            return -1;
        }

        op = OP_Set;
        size = st.st_size;
    }

    auto name = args.get_single_values()[0];

    int fd = open(name.characters(), O_CREAT, 0666);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    struct stat st;
    if (fstat(fd, &st) < 0) {
        perror("fstat");
        return -1;
    }

    switch (op) {
    case OP_Set:
        break;
    case OP_Grow:
        size = st.st_size + size;
        break;
    case OP_Shrink:
        size = st.st_size - size;
        break;
    }

    if (ftruncate(fd, size) < 0) {
        perror("ftruncate");
        return -1;
    }

    if (close(fd) < 0) {
        perror("close");
        return -1;
    }

    return 0;
}