Added support for pattern matching of attribute/index names (via glob()).

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18042 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-07-05 14:22:48 +00:00
parent 38f9b78d6c
commit 79b25dd765
2 changed files with 267 additions and 149 deletions
+117 -36
View File
@@ -1,44 +1,125 @@
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ /*
// * Copyright 2001-2006, Haiku, Inc. All Rights Reserved.
// Copyright (c) 2001-2003, OpenBeOS * Distributed under the terms of the MIT License.
// *
// This software is part of the OpenBeOS distribution and is covered * Authors:
// by the OpenBeOS license. * Jérôme Duval, [email protected]
// * Axel Dörfler, [email protected]
// */
// File: rmattr.cpp
// Author: Jérôme Duval
// Description: remove an attribute from a file
//
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
/*! Remove an attribute from a file */
#include <fs_attr.h>
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <fcntl.h> // For O_WRONLY in BeOS R5 headers. #include <string.h>
#include <kernel/fs_attr.h> #include <unistd.h>
int main(int32 argc, const char **argv)
extern const char *__progname;
const char *kProgramName = __progname;
int gCurrentFile;
void
usage()
{ {
// Make sure we have the minimum number of arguments. printf("usage: %s [-p] attr filename1 [filename2...]\n"
if (argc < 3) { "\t'attr' is the name of an attribute of the file\n"
printf("usage: %s attr filename1 [filename2...]\n", argv[0]); "\tIf '-p' is specified, 'attr' is regarded as a pattern.\n", kProgramName);
printf(" attr is the name of an attribute of the file\n");
exit(0);
}
for(int32 i=2; i<argc; i++) {
int fd = open(argv[i], O_WRONLY);
if (fd < 0) {
fprintf( stderr, "%s: can\'t open file %s to remove attribute\n",
argv[0], argv[i]);
exit(0);
}
if(fs_remove_attr(fd, argv[1])!=B_OK) {
fprintf( stderr, "%s: error removing attribute %s from %s : No such attribute\n",
argv[0], argv[1], argv[i] );
}
}
exit(0); exit(0);
} }
void *
open_attr_dir(const char* /*path*/)
{
return fs_fopen_attr_dir(gCurrentFile);
}
int
stat_attr(const char* /*attribute*/, struct stat* stat)
{
memset(stat, 0, sizeof(struct stat));
stat->st_mode = S_IFREG;
return 0;
}
int
remove_attribute(int fd, const char* attribute, bool isPattern)
{
if (!isPattern)
return fs_remove_attr(fd, attribute);
glob_t glob;
memset(&glob, 0, sizeof(glob_t));
glob.gl_closedir = (void (*)(void *))fs_close_attr_dir;
glob.gl_readdir = fs_read_attr_dir;
glob.gl_opendir = open_attr_dir;
glob.gl_lstat = stat_attr;
glob.gl_stat = stat_attr;
// for open_attr_dir():
gCurrentFile = fd;
int result = ::glob(attribute, GLOB_ALTDIRFUNC, NULL, &glob);
if (result < 0) {
errno = B_BAD_VALUE;
return -1;
}
bool error = false;
for (int i = 0; i < glob.gl_pathc; i++) {
if (fs_remove_attr(fd, glob.gl_pathv[i]) != 0)
error = true;
}
return error ? -1 : 0;
}
int
main(int32 argc, const char **argv)
{
// Make sure we have the minimum number of arguments.
if (argc < 3)
usage();
bool isPattern = false;
int attr = 1;
if (!strcmp(argv[attr], "-p")) {
isPattern = true;
attr++;
if (argc < 4)
usage();
}
for (int32 i = attr + 1; i < argc; i++) {
int fd = open(argv[i], O_WRONLY);
if (fd < 0) {
fprintf(stderr, "%s: can\'t open file %s to remove attribute: %s\n",
kProgramName, argv[i], strerror(errno));
return 0;
}
if (remove_attribute(fd, argv[attr], isPattern) != B_OK) {
fprintf(stderr, "%s: error removing attribute %s from %s: %s\n",
kProgramName, argv[attr], argv[i], strerror(errno));
}
close(fd);
}
return 0;
}
+149 -112
View File
@@ -14,11 +14,17 @@
#include <errno.h> #include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <glob.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
extern const char *__progname;
const char *kProgramName = __progname;
dev_t gCurrentDevice;
// The following enum and #define are copied from gnu/sys2.h, because it // The following enum and #define are copied from gnu/sys2.h, because it
// didn't want to compile when including that directly. Since that file // didn't want to compile when including that directly. Since that file
// is marked as being temporary and getting migrated into system.h, // is marked as being temporary and getting migrated into system.h,
@@ -27,125 +33,26 @@
/* These enum values cannot possibly conflict with the option values /* These enum values cannot possibly conflict with the option values
ordinarily used by commands, including CHAR_MAX + 1, etc. Avoid ordinarily used by commands, including CHAR_MAX + 1, etc. Avoid
CHAR_MIN - 1, as it may equal -1, the getopt end-of-options value. */ CHAR_MIN - 1, as it may equal -1, the getopt end-of-options value. */
enum enum {
{
GETOPT_HELP_CHAR = (CHAR_MIN - 2), GETOPT_HELP_CHAR = (CHAR_MIN - 2),
GETOPT_VERSION_CHAR = (CHAR_MIN - 3) GETOPT_VERSION_CHAR = (CHAR_MIN - 3)
}; };
#define GETOPT_HELP_OPTION_DECL \
"help", no_argument, 0, GETOPT_HELP_CHAR
static struct option const longopts[] = { static struct option const longopts[] = {
{"volume", required_argument, 0, 'd'}, {"volume", required_argument, 0, 'd'},
{"type", required_argument, 0, 't'}, {"type", required_argument, 0, 't'},
{"pattern", no_argument, 0, 'p'},
{"verbose", no_argument, 0, 'v'}, {"verbose", no_argument, 0, 'v'},
{GETOPT_HELP_OPTION_DECL}, {"help", no_argument, 0, GETOPT_HELP_CHAR},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
void usage(int);
const char* lookup_index_type(uint32);
int
main (int32 argc, char **argv)
{
int c;
int verbose = 0;
dev_t vol_device = 0;
char *index_name = NULL;
int retval;
char *error_message;
char *path = NULL;
while ((c = getopt_long(argc, argv, "d:ht:v", longopts, NULL)) != -1) {
switch (c) {
case 0:
break;
case 'd':
path = optarg;
break;
case GETOPT_HELP_CHAR:
usage(0);
break;
case 'v':
verbose = 1;
break;
default:
usage(1);
break;
}
}
/* Remove the index from the volume of the current
directory if no volume was specified. */
if (path == NULL) {
path = ".";
}
vol_device = dev_for_path(path);
if (vol_device < 0) {
fprintf(stderr, "%s: can't get information about current volume\n", argv[0]);
return B_ERROR;
}
if (argc - optind == 1) { // last argument
index_name = argv[optind];
} else {
usage(1);
}
if (verbose) {
/* Get the index type. */
index_info i_info;
status_t status = fs_stat_index(vol_device, index_name, &i_info);
if (status != B_OK) {
fprintf(stderr, "%s: fs_stat_index(): (%d) %s\n", argv[0], errno, strerror(errno));
return (errno);
}
/* Look up the string name equivalent of the index type. */
const char* index_type_str = lookup_index_type(i_info.type);
fprintf(stdout, "Removing index \"%s\" of type %s from volume containing %s\n", index_name, index_type_str, path);
}
if ((retval = fs_remove_index(vol_device, index_name)) != 0) {
switch (errno) {
case B_FILE_ERROR:
error_message = "A filesystem error prevented the operation.";
break;
case B_BAD_VALUE:
error_message = "Invalid device specified.";
break;
case B_NOT_ALLOWED:
error_message = "Can't remove a system-reserved index, or the device is read-only.";
break;
case B_NO_MEMORY:
error_message = "Insufficient memory to complete the operation.";
break;
case B_ENTRY_NOT_FOUND:
error_message = "The specified index does not exist.";
break;
default:
error_message = "An unknown error has occured.";
break;
}
fprintf(stderr, "%s\n", error_message);
}
return 0;
}
void void
usage (int status) usage(int status)
{ {
fprintf (stderr, fprintf (stderr,
"Usage: rmindex [OPTION]... INDEX_NAME\n" "Usage: %s [OPTION]... INDEX_NAME\n"
"\n" "\n"
"Removes the index named INDEX_NAME from a disk volume. Once this has been\n" "Removes the index named INDEX_NAME from a disk volume. Once this has been\n"
"done, it will no longer be possible to use the query system to search for\n" "done, it will no longer be possible to use the query system to search for\n"
@@ -154,11 +61,13 @@ usage (int status)
" -d, --volume=PATH a path on the volume from which the index will be\n" " -d, --volume=PATH a path on the volume from which the index will be\n"
" removed\n" " removed\n"
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"
" -v, --verbose print information about the index being removed\n" " -p, --pattern INDEX_NAME is a pattern\n"
" -v, --verbose print information about the index being removed\n"
"\n" "\n"
"INDEX_NAME is the name of a file attribute.\n" "INDEX_NAME is the name of a file attribute.\n"
"\n" "\n"
"If no volume is specified, the volume of the current directory is assumed.\n"); "If no volume is specified, the volume of the current directory is assumed.\n",
kProgramName);
exit(status); exit(status);
} }
@@ -170,21 +79,149 @@ lookup_index_type(uint32 device_type)
switch (device_type) { switch (device_type) {
case B_DOUBLE_TYPE: case B_DOUBLE_TYPE:
return "double"; return "double";
break;
case B_FLOAT_TYPE: case B_FLOAT_TYPE:
return "float"; return "float";
break;
case B_INT64_TYPE: case B_INT64_TYPE:
return "llong"; return "llong";
break;
case B_INT32_TYPE: case B_INT32_TYPE:
return "int"; return "int";
break;
case B_STRING_TYPE: case B_STRING_TYPE:
return "string"; return "string";
break;
default: default:
return "unknown"; return "unknown";
break;
} }
} }
int
remove_index(dev_t device, const char* indexName, bool verbose)
{
if (verbose) {
// Get the index type
index_info info;
status_t status = fs_stat_index(device, indexName, &info);
if (status != B_OK) {
fprintf(stderr, "%s: Can't get type of index %s: %s\n",
kProgramName, indexName, strerror(errno));
return -1;
}
fprintf(stdout, "Removing index \"%s\" of type %s.\n",
indexName, lookup_index_type(info.type));
}
if (fs_remove_index(device, indexName) != 0) {
fprintf(stderr, "%s: Cannot remove index %s: %s\n", kProgramName, indexName, strerror(errno));
return -1;
}
return 0;
}
void *
open_index_dir(const char* /*path*/)
{
return fs_open_index_dir(gCurrentDevice);
}
int
stat_index(const char* /*index*/, struct stat* stat)
{
memset(stat, 0, sizeof(struct stat));
stat->st_mode = S_IFREG;
return 0;
}
int
remove_indices(dev_t device, const char* indexPattern, bool verbose)
{
glob_t glob;
memset(&glob, 0, sizeof(glob_t));
glob.gl_closedir = (void (*)(void *))fs_close_index_dir;
glob.gl_readdir = fs_read_index_dir;
glob.gl_opendir = open_index_dir;
glob.gl_lstat = stat_index;
glob.gl_stat = stat_index;
// for open_attr_dir():
gCurrentDevice = device;
int result = ::glob(indexPattern, GLOB_ALTDIRFUNC, NULL, &glob);
if (result < 0) {
errno = B_BAD_VALUE;
return -1;
}
bool error = false;
for (int i = 0; i < glob.gl_pathc; i++) {
if (remove_index(device, glob.gl_pathv[i], verbose) != 0)
error = true;
}
return error ? -1 : 0;
}
int
main(int32 argc, char **argv)
{
bool isPattern = false;
bool verbose = false;
dev_t device = 0;
char *indexName = NULL;
char *path = NULL;
int c;
while ((c = getopt_long(argc, argv, "d:ht:pv", longopts, NULL)) != -1) {
switch (c) {
case 0:
break;
case 'd':
path = optarg;
break;
case GETOPT_HELP_CHAR:
usage(0);
break;
case 'p':
isPattern = true;
break;
case 'v':
verbose = true;
break;
default:
usage(1);
break;
}
}
// Remove the index from the volume of the current
// directory if no volume was specified.
if (path == NULL)
path = ".";
device = dev_for_path(path);
if (device < 0) {
fprintf(stderr, "%s: can't get information about volume %s\n", kProgramName, path);
return 1;
}
if (argc - optind == 1) {
// last argument
indexName = argv[optind];
} else
usage(1);
int result;
if (isPattern)
result = remove_indices(device, indexName, verbose);
else
result = remove_index(device, indexName, verbose);
return result == 0 ? 0 : 1;
}