2 * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
14 #include <Directory.h>
26 extern const char *__progname
;
27 static const char *kProgramName
= __progname
;
29 bool gRecursive
= false; // enter directories recursively
30 bool gVerbose
= false;
32 bool gIsPattern
= false;
33 bool gFromVolume
= false; // copy indices from another volume
34 BList gAttrList
; // list of indices of that volume
39 Attribute(const char *name
);
42 status_t
ReadFromFile(BNode
*node
);
43 status_t
WriteToFile(BNode
*node
);
44 status_t
RemoveFromFile(BNode
*node
);
46 const char *Name() const { return fName
.String(); }
47 type_code
Type() const { return fType
; }
48 size_t Length() const { return fLength
; }
58 Attribute::Attribute(const char *name
)
67 Attribute::~Attribute()
74 Attribute::ReadFromFile(BNode
*node
)
77 status_t status
= node
->GetAttrInfo(fName
.String(), &info
);
84 if ((fBuffer
= malloc(fLength
)) == NULL
)
87 ssize_t bytesRead
= node
->ReadAttr(fName
.String(), fType
, 0, fBuffer
,
91 if (bytesRead
< (ssize_t
)fLength
)
99 Attribute::WriteToFile(BNode
*node
)
101 ssize_t bytesWritten
= node
->WriteAttr(fName
.String(), fType
, 0, fBuffer
,
103 if (bytesWritten
< B_OK
)
105 if (bytesWritten
< (ssize_t
)fLength
)
113 Attribute::RemoveFromFile(BNode
*node
)
115 return node
->RemoveAttr(fName
.String());
123 nameMatchesPattern(char *name
)
126 return !strcmp(name
,gAttrPattern
);
128 // test the beginning
130 for(; name
[i
]; i
++) {
131 if (gAttrPattern
[i
] == '*')
133 if (name
[i
] != gAttrPattern
[i
])
138 int j
= strlen(name
) - 1;
139 int k
= strlen(gAttrPattern
) - 1;
140 for(; j
>= i
&& k
>= i
; j
--, k
--) {
141 if (gAttrPattern
[k
] == '*')
143 if (name
[j
] != gAttrPattern
[k
])
146 if (gAttrPattern
[k
] != '*')
154 isAttrInList(char *name
)
156 for (int32 index
= gAttrList
.CountItems();index
-- > 0;) {
157 const char *attr
= (const char *)gAttrList
.ItemAt(index
);
158 if (!strcmp(attr
, name
))
166 handleFile(BEntry
*entry
, BNode
*node
)
168 // Recurse the directories
169 if (gRecursive
&& entry
->IsDirectory()) {
170 BDirectory
dir(entry
);
171 BEntry entryIterator
;
174 while (dir
.GetNextEntry(&entryIterator
, false) == B_OK
) {
176 handleFile(&entryIterator
, &innerNode
);
179 // also rewrite the attributes of the directory
182 char name
[B_FILE_NAME_LENGTH
];
183 entry
->GetName(name
);
185 status_t status
= node
->SetTo(entry
);
186 if (status
!= B_OK
) {
187 fprintf(stderr
, "%s: could not open \"%s\": %s\n", kProgramName
, name
,
192 // rewrite file attributes
194 char attrName
[B_ATTR_NAME_LENGTH
];
200 while (node
->GetNextAttrName(attrName
) == B_OK
) {
202 if (!isAttrInList(attrName
))
204 } else if (!nameMatchesPattern(attrName
))
207 attr
= new(std::nothrow
) Attribute(attrName
);
209 fprintf(stderr
, "%s: out of memory.\n", kProgramName
);
213 status
= attr
->ReadFromFile(node
);
214 if (status
!= B_OK
) {
215 fprintf(stderr
, "%s: could not read attribute \"%s\" of file "
216 "\"%s\": %s\n", kProgramName
, attrName
, name
, strerror(status
));
221 printf("%s: read attribute '%s' (%ld bytes of data)\n", name
,
222 attrName
, attr
->Length());
224 if (!list
.AddItem(attr
)) {
225 fprintf(stderr
, "%s: out of memory.\n", kProgramName
);
230 // creates index to that attribute if necessary
232 if (entry
->GetRef(&ref
) == B_OK
) {
233 index_info indexInfo
;
234 if (fs_stat_index(ref
.device
, attrName
, &indexInfo
) != B_OK
)
235 fs_create_index(ref
.device
, attrName
, attr
->Type(), 0);
241 for (int32 i
= list
.CountItems(); i
-- > 0;) {
242 attr
= static_cast<Attribute
*>(list
.ItemAt(i
));
243 if (attr
->RemoveFromFile(node
) != B_OK
) {
244 fprintf(stderr
, "%s: could not remove attribute '%s' from file "
245 "'%s'.\n", kProgramName
, attr
->Name(), name
);
249 // rewrite attrs and empty the list
250 while ((attr
= static_cast<Attribute
*>(list
.RemoveItem((int32
)0))) != NULL
) {
251 // write attribute back to file
252 status
= attr
->WriteToFile(node
);
253 if (status
!= B_OK
) {
254 fprintf(stderr
, "%s: could not write attribute '%s' to file \"%s\":"
255 " %s\n", kProgramName
, attr
->Name(), name
, strerror(status
));
256 } else if (gVerbose
) {
257 printf("%s: wrote attribute '%s' (%ld bytes of data)\n", name
,
258 attr
->Name(), attr
->Length());
267 copyIndicesFromVolume(const char *path
, BEntry
&to
)
270 if (to
.GetRef(&ref
) != B_OK
) {
271 fprintf(stderr
, "%s: Could not open target volume.\n", kProgramName
);
275 dev_t targetDevice
= ref
.device
;
276 dev_t sourceDevice
= dev_for_path(path
);
277 if (sourceDevice
< B_OK
) {
278 fprintf(stderr
, "%s: Could not open source volume: %s\n", kProgramName
,
279 strerror(sourceDevice
));
283 DIR *indexDirectory
= fs_open_index_dir(sourceDevice
);
284 if (indexDirectory
== NULL
)
287 while (dirent
*index
= fs_read_index_dir(indexDirectory
)) {
288 index_info indexInfo
;
289 if (fs_stat_index(sourceDevice
, index
->d_name
, &indexInfo
) != B_OK
) {
290 fprintf(stderr
, "%s: Could not get information about index "
291 "\"%s\": %s\n", kProgramName
, index
->d_name
, strerror(errno
));
295 if (fs_create_index(targetDevice
, index
->d_name
, indexInfo
.type
, 0)
296 == -1 && errno
!= B_FILE_EXISTS
&& errno
!= B_BAD_VALUE
) {
297 fprintf(stderr
, "Could not create index '%s' (type = %" B_PRIu32
298 "): %s\n", index
->d_name
, indexInfo
.type
, strerror(errno
));
300 gAttrList
.AddItem(strdup(index
->d_name
));
302 fs_close_index_dir(indexDirectory
);
307 printUsage(char *cmd
)
309 printf("usage: %s [-rvf] attr <list of filenames and/or directories>\n"
310 " -r\tenter directories recursively\n"
311 " -v\tverbose output\n"
312 " -f\tcreate/update all indices from the source volume,\n\t\"attr\" is "
313 "the path to the source volume\n", cmd
);
318 main(int argc
, char **argv
)
327 while (*++argv
&& **argv
== '-') {
328 for (int i
= 1; (*argv
)[i
]; i
++) {
329 switch ((*argv
)[i
]) {
345 gAttrPattern
= *argv
;
346 if (strchr(gAttrPattern
,'*'))
353 if (entry
.InitCheck() == B_OK
) {
355 copyIndicesFromVolume(gAttrPattern
, entry
);
356 handleFile(&entry
, &node
);
358 fprintf(stderr
, "%s: could not find \"%s\".\n", kProgramName
, *argv
);