2 * Copyright 2012, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
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'},
29 #define FLAG_VERBOSE 1
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
];
42 moveAttribute(const char* fromFile
, const char* fromAttr
, const char* toFile
,
43 const char* toAttr
, uint32 flags
)
45 int fromFileFD
= open(fromFile
, O_RDONLY
);
49 FileDescriptorCloser
fromFileFDCloser(fromFileFD
);
50 FileDescriptorCloser toFileFDCloser
;
52 int toFileFD
= fromFileFD
;
53 if (strcmp(fromFile
, toFile
) != 0) {
54 toFileFD
= open(toFile
, O_RDONLY
);
58 toFileFDCloser
.SetTo(toFileFD
);
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
);
71 if ((flags
& FLAG_FORCE
) == 0
72 && fs_stat_attr(toFileFD
, toAttr
, &toInfo
) == 0)
75 int fromAttrFD
= fs_fopen_attr(fromFileFD
, fromAttr
, fromInfo
.type
,
80 FileDescriptorCloser
fromAttrFDCloser(fromAttrFD
);
82 int toAttrFD
= fs_fopen_attr(toFileFD
, toAttr
, fromInfo
.type
,
83 O_CREAT
| O_WRONLY
| O_TRUNC
);
87 FileDescriptorCloser
toAttrFDCloser(toAttrFD
);
89 size_t bytesLeft
= fromInfo
.size
;
91 while (bytesLeft
> 0) {
92 size_t size
= min_c(kBufferSize
, bytesLeft
);
93 ssize_t bytesRead
= read_pos(fromAttrFD
, offset
, kBuffer
, size
);
95 fs_remove_attr(toFileFD
, toAttr
);
99 ssize_t bytesWritten
= write_pos(toAttrFD
, offset
, kBuffer
, bytesRead
);
100 if (bytesWritten
!= bytesRead
) {
101 fs_remove_attr(toFileFD
, toAttr
);
102 if (bytesWritten
>= 0)
107 bytesLeft
-= bytesRead
;
111 if (fs_remove_attr(fromFileFD
, fromAttr
) < 0)
119 moveAttributes(const char* fromFile
, const char* toFile
,
120 const char* attrPattern
, uint32 flags
)
122 // TODO: implement me (with pattern support)
128 renameAttribute(const char* fileName
, const char* fromAttr
, const char* toAttr
,
131 if ((flags
& FLAG_VERBOSE
) != 0)
132 printf("Rename attribute: %s\n", fileName
);
134 status_t status
= moveAttribute(fileName
, fromAttr
, fileName
, toAttr
,
136 if (status
!= B_OK
) {
137 fprintf(stderr
, "%s: Could not rename attribute for file \"%s\": %s\n",
138 kProgramName
, fileName
, strerror(status
));
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
);
160 main(int argc
, char** argv
)
163 bool crossFile
= false;
166 while ((c
= getopt_long(argc
, argv
, "hfxPv", kLongOptions
, NULL
)) != -1) {
177 flags
|= FLAG_DO_NOT_FOLLOW_LINKS
;
180 flags
|= FLAG_VERBOSE
;
191 if (argc
- optind
< 3)
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
;