1 // query.cpp 2 // 3 // A shell utility for somewhat emulating the Tracker's "Find By Formula" 4 // functionality. 5 // 6 // by Ficus Kirkpatrick (ficus@ior.com) 7 // 8 // Modified by Jerome Duval on November 03, 2003 9 // 10 // Filtering capability added by Stefano Ceccherini on January 14, 2005 11 12 13 #include <stdio.h> 14 #include <string.h> 15 #include <stdlib.h> 16 #include <unistd.h> 17 18 #include <Path.h> 19 #include <Query.h> 20 #include <Entry.h> 21 #include <Volume.h> 22 #include <VolumeRoster.h> 23 #include <SupportDefs.h> 24 #include <String.h> 25 26 #include "FilteredQuery.h" 27 28 extern const char *__progname; 29 30 struct folder_params 31 { 32 BPath path; 33 bool includeSubFolders; 34 }; 35 36 37 static bool 38 FilterByFolder(const entry_ref *ref, void *arg) 39 { 40 folder_params* params = static_cast<folder_params*>(arg); 41 BPath& wantedPath = params->path; 42 bool includeSub = params->includeSubFolders; 43 44 BPath path(ref); 45 if (includeSub) { 46 if (!strncmp(path.Path(), wantedPath.Path(), 47 strlen(wantedPath.Path()))) 48 return true; 49 } else { 50 if (path.GetParent(&path) == B_OK && 51 path == wantedPath) 52 return true; 53 } 54 return false; 55 } 56 57 58 // Option variables. 59 bool o_all_volumes = false; // Query all volumes? 60 bool o_escaping = true; // Escape metacharacters? 61 bool o_subfolders = false; 62 63 void 64 usage(void) 65 { 66 printf("usage: %s [ -e ] [ -p <path-to-search> ] [ -s ] [ -a || -v <path-to-volume> ] expression\n" 67 " -e\t\tdon't escape meta-characters\n" 68 " -p <path>\tsearch only in the given path. Defaults to the current directory.\n" 69 " -s\t\tinclude subfolders\n" 70 " -a\t\tperform the query on all volumes\n" 71 " -v <file>\tperform the query on just one volume; <file> can be any\n" 72 "\t\tfile on that volume. Defaults to the current volume.\n" 73 " Hint: '%s name=foo' will find files named \"foo\"\n", 74 __progname, __progname); 75 exit(0); 76 } 77 78 79 void 80 perform_query(BVolume &volume, const char *predicate, const char *filterpath) 81 { 82 TFilteredQuery query; 83 84 // Set up the volume and predicate for the query. 85 query.SetVolume(&volume); 86 query.SetPredicate(predicate); 87 folder_params options; 88 if (filterpath != NULL) { 89 options.path = filterpath; 90 options.includeSubFolders = o_subfolders; 91 query.AddFilter(FilterByFolder, &options); 92 } 93 94 status_t status = query.Fetch(); 95 if (status == B_BAD_VALUE) { 96 // the "name=" part may be omitted in our arguments 97 BString string = "name="; 98 string << predicate; 99 100 query.SetPredicate(string.String()); 101 status = query.Fetch(); 102 } 103 if (status != B_OK) { 104 printf("query: bad query expression\n"); 105 return; 106 } 107 108 BEntry entry; 109 BPath path; 110 while (query.GetNextEntry(&entry) == B_OK) { 111 if (entry.GetPath(&path) < B_OK) { 112 fprintf(stderr, "%s: could not get path for entry\n", __progname); 113 continue; 114 } 115 116 printf("%s\n", o_escaping ? 117 BString().CharacterEscape(path.Path(), " ()?*&\"'[]^\\~|;!<>*$", '\\').String() 118 : path.Path()); 119 } 120 } 121 122 123 int 124 main(int32 argc, const char **argv) 125 { 126 // Make sure we have the minimum number of arguments. 127 if (argc < 2) 128 usage(); 129 130 // Which volume do we make the query on? 131 // Default to the current volume. 132 char volumePath[B_FILE_NAME_LENGTH]; 133 char directoryPath[B_PATH_NAME_LENGTH]; 134 135 strcpy(volumePath, "."); 136 strcpy(directoryPath, "."); 137 138 // Parse command-line arguments. 139 int opt; 140 while ((opt = getopt(argc, (char **)argv, "easv:p:")) != -1) { 141 switch(opt) { 142 case 'a': 143 o_all_volumes = true; 144 break; 145 146 case 'e': 147 o_escaping = false; 148 break; 149 150 case 'v': 151 strncpy(volumePath, optarg, B_FILE_NAME_LENGTH); 152 break; 153 154 case 'p': 155 strncpy(directoryPath, optarg, B_PATH_NAME_LENGTH); 156 break; 157 158 case 's': 159 o_subfolders = true; 160 break; 161 162 default: 163 usage(); 164 break; 165 } 166 } 167 168 BVolume volume; 169 170 if (!o_all_volumes) { 171 // Find the volume that the query should be performed on, 172 // and set the query to it. 173 BEntry entry(volumePath); 174 if (entry.InitCheck() != B_OK) { 175 printf("query: %s is not a valid file\n", volumePath); 176 exit(1); 177 } 178 179 status_t status = entry.GetVolume(&volume); 180 if (status != B_OK) { 181 fprintf(stderr, "%s: could not get volume: %s\n", __progname, strerror(status)); 182 exit(1); 183 } 184 185 if (!volume.KnowsQuery()) 186 printf("query: volume containing %s is not query-enabled\n", volumePath); 187 else 188 perform_query(volume, argv[optind], directoryPath); 189 } else { 190 // Okay, we want to query all the disks -- so iterate over 191 // them, one by one, running the query. 192 BVolumeRoster volumeRoster; 193 while (volumeRoster.GetNextVolume(&volume) == B_OK) { 194 // We don't print errors here -- this will catch /pipe and 195 // other filesystems we don't care about. 196 if (volume.KnowsQuery()) 197 perform_query(volume, argv[optind], directoryPath); 198 } 199 } 200 201 return 0; 202 } 203