Serenity Operating System
1/*
2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <LibCore/ArgsParser.h>
8#include <LibCore/System.h>
9#include <LibMain/Main.h>
10#include <fcntl.h>
11#include <stdio.h>
12#include <sys/stat.h>
13#include <unistd.h>
14
15enum TruncateOperation {
16 OP_Set,
17 OP_Grow,
18 OP_Shrink,
19};
20
21ErrorOr<int> serenity_main(Main::Arguments arguments)
22{
23 TRY(Core::System::pledge("stdio rpath wpath cpath"));
24
25 StringView resize;
26 StringView reference;
27 StringView file;
28
29 Core::ArgsParser args_parser;
30 args_parser.add_option(resize, "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", "size", 's', "size");
31 args_parser.add_option(reference, "Resize the target file to match the size of this one", "reference", 'r', "file");
32 args_parser.add_positional_argument(file, "File path", "file");
33 args_parser.parse(arguments);
34
35 if (resize.is_empty() && reference.is_empty()) {
36 args_parser.print_usage(stderr, arguments.strings[0]);
37 return 1;
38 }
39
40 if (!resize.is_empty() && !reference.is_empty()) {
41 args_parser.print_usage(stderr, arguments.strings[0]);
42 return 1;
43 }
44
45 auto op = OP_Set;
46 off_t size = 0;
47
48 if (!resize.is_empty()) {
49 DeprecatedString str = resize;
50
51 switch (str[0]) {
52 case '+':
53 op = OP_Grow;
54 str = str.substring(1, str.length() - 1);
55 break;
56 case '-':
57 op = OP_Shrink;
58 str = str.substring(1, str.length() - 1);
59 break;
60 }
61
62 auto size_opt = str.to_int<off_t>();
63 if (!size_opt.has_value()) {
64 args_parser.print_usage(stderr, arguments.strings[0]);
65 return 1;
66 }
67 size = size_opt.value();
68 }
69
70 if (!reference.is_empty()) {
71 auto stat = TRY(Core::System::stat(reference));
72 size = stat.st_size;
73 }
74
75 auto fd = TRY(Core::System::open(file, O_RDWR | O_CREAT, 0666));
76 auto stat = TRY(Core::System::fstat(fd));
77
78 switch (op) {
79 case OP_Set:
80 break;
81 case OP_Grow:
82 size = stat.st_size + size;
83 break;
84 case OP_Shrink:
85 size = stat.st_size - size;
86 break;
87 }
88
89 TRY(Core::System::ftruncate(fd, size));
90 TRY(Core::System::close(fd));
91
92 return 0;
93}