libroot/posix/stdio: Remove unused portions.
[haiku.git] / src / bin / mvattr.cpp
blob4ac9ee701a9a3dfb444bccb9db485afda56c6ff0
1 /*
2 * Copyright 2012, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <getopt.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
15 #include <fs_attr.h>
17 #include <AutoDeleter.h>
20 static struct option const kLongOptions[] = {
21 {"help", no_argument, 0, 'h'},
22 {"force", no_argument, 0, 'f'},
23 {"cross-file", no_argument, 0, 'x'},
24 {"verbose", no_argument, 0, 'v'},
25 {NULL}
28 // command flags
29 #define FLAG_VERBOSE 1
30 #define FLAG_FORCE 2
31 #define FLAG_DO_NOT_FOLLOW_LINKS 4
34 extern const char *__progname;
35 static const char *kProgramName = __progname;
37 static const size_t kBufferSize = 1024 * 1024;
38 static uint8 kBuffer[kBufferSize];
41 status_t
42 moveAttribute(const char* fromFile, const char* fromAttr, const char* toFile,
43 const char* toAttr, uint32 flags)
45 int fromFileFD = open(fromFile, O_RDONLY);
46 if (fromFileFD < 0)
47 return errno;
49 FileDescriptorCloser fromFileFDCloser(fromFileFD);
50 FileDescriptorCloser toFileFDCloser;
52 int toFileFD = fromFileFD;
53 if (strcmp(fromFile, toFile) != 0) {
54 toFileFD = open(toFile, O_RDONLY);
55 if (toFileFD < 0)
56 return errno;
58 toFileFDCloser.SetTo(toFileFD);
61 attr_info fromInfo;
62 if (fs_stat_attr(fromFileFD, fromAttr, &fromInfo) != 0) {
63 // TODO: optionally fail
64 if ((flags & FLAG_VERBOSE) != 0)
65 fprintf(stderr, "Warning: file \"%s\" does not have attribute "
66 "\"%s\"\n", fromFile, fromAttr);
67 return B_OK;
70 attr_info toInfo;
71 if ((flags & FLAG_FORCE) == 0
72 && fs_stat_attr(toFileFD, toAttr, &toInfo) == 0)
73 return B_FILE_EXISTS;
75 int fromAttrFD = fs_fopen_attr(fromFileFD, fromAttr, fromInfo.type,
76 O_RDONLY | O_EXCL);
77 if (fromAttrFD < 0)
78 return errno;
80 FileDescriptorCloser fromAttrFDCloser(fromAttrFD);
82 int toAttrFD = fs_fopen_attr(toFileFD, toAttr, fromInfo.type,
83 O_CREAT | O_WRONLY | O_TRUNC);
84 if (fromAttrFD < 0)
85 return errno;
87 FileDescriptorCloser toAttrFDCloser(toAttrFD);
89 size_t bytesLeft = fromInfo.size;
90 off_t offset = 0;
91 while (bytesLeft > 0) {
92 size_t size = min_c(kBufferSize, bytesLeft);
93 ssize_t bytesRead = read_pos(fromAttrFD, offset, kBuffer, size);
94 if (bytesRead < 0) {
95 fs_remove_attr(toFileFD, toAttr);
96 return errno;
99 ssize_t bytesWritten = write_pos(toAttrFD, offset, kBuffer, bytesRead);
100 if (bytesWritten != bytesRead) {
101 fs_remove_attr(toFileFD, toAttr);
102 if (bytesWritten >= 0)
103 return B_IO_ERROR;
104 return errno;
107 bytesLeft -= bytesRead;
108 offset += bytesRead;
111 if (fs_remove_attr(fromFileFD, fromAttr) < 0)
112 return errno;
114 return B_OK;
118 status_t
119 moveAttributes(const char* fromFile, const char* toFile,
120 const char* attrPattern, uint32 flags)
122 // TODO: implement me (with pattern support)
123 return EXIT_FAILURE;
127 status_t
128 renameAttribute(const char* fileName, const char* fromAttr, const char* toAttr,
129 uint32 flags)
131 if ((flags & FLAG_VERBOSE) != 0)
132 printf("Rename attribute: %s\n", fileName);
134 status_t status = moveAttribute(fileName, fromAttr, fileName, toAttr,
135 flags);
136 if (status != B_OK) {
137 fprintf(stderr, "%s: Could not rename attribute for file \"%s\": %s\n",
138 kProgramName, fileName, strerror(status));
140 return status;
144 void
145 usage(int returnValue)
147 fprintf(stderr, "usage: %s [-fPv] attr-from attr-to file1 [file2...]\n"
148 " or: %s -x[fPv] <attr-pattern> from-file to-file\n\n"
149 "\t-f|--force Overwrite existing attributes\n"
150 "\t-P Don't resolve links\n"
151 "\t-x|--cross-file Moves the attributes to another file\n"
152 "\t-v|--verbose Verbose output\n",
153 kProgramName, kProgramName);
155 exit(returnValue);
160 main(int argc, char** argv)
162 uint32 flags = 0;
163 bool crossFile = false;
165 int c;
166 while ((c = getopt_long(argc, argv, "hfxPv", kLongOptions, NULL)) != -1) {
167 switch (c) {
168 case 0:
169 break;
170 case 'f':
171 flags |= FLAG_FORCE;
172 break;
173 case 'x':
174 crossFile = true;
175 break;
176 case 'P':
177 flags |= FLAG_DO_NOT_FOLLOW_LINKS;
178 break;
179 case 'v':
180 flags |= FLAG_VERBOSE;
181 break;
182 case 'h':
183 usage(EXIT_SUCCESS);
184 break;
185 default:
186 usage(EXIT_FAILURE);
187 break;
191 if (argc - optind < 3)
192 usage(EXIT_FAILURE);
194 if (crossFile) {
195 const char* attrPattern = argv[optind++];
196 const char* fromFile = argv[optind++];
197 const char* toFile = argv[optind++];
199 return moveAttributes(fromFile, toFile, attrPattern, flags);
202 const char* fromAttr = argv[optind++];
203 const char* toAttr = argv[optind++];
204 int returnCode = EXIT_SUCCESS;
206 for (int i = optind; i < argc; i++) {
207 if (renameAttribute(argv[i], fromAttr, toAttr, flags) != B_OK)
208 returnCode = EXIT_FAILURE;
211 return returnCode;