vfs: check userland buffers before reading them.
[haiku.git] / src / bin / mimeset.cpp
blob18f5b7640e1099dc308a7d43b9c8cf452855e110
1 /*
2 * Copyright 2005-2006, Axel Dörfler, axeld@pinc-software.de.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
7 #include <getopt.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include <Application.h>
13 #include <Mime.h>
14 #include <Path.h>
16 #include <mime/AppMetaMimeCreator.h>
17 #include <mime/Database.h>
18 #include <mime/DatabaseLocation.h>
19 #include <mime/MimeInfoUpdater.h>
20 #include <mime/MimeSnifferAddonManager.h>
21 #include <mime/TextSnifferAddon.h>
24 using namespace BPrivate::Storage::Mime;
27 #ifdef HAIKU_HOST_PLATFORM_SUNOS
28 static const char* sProgramName = "mimeset";
29 #else
30 extern const char* __progname;
31 static const char* sProgramName = __progname;
32 #endif
34 // options
35 bool gFiles = true;
36 bool gApps = false;
37 int gForce = B_UPDATE_MIME_INFO_NO_FORCE;
39 static Database* sDatabase = NULL;
42 static void
43 usage(int status)
45 printf("Usage: %s <options> <path> ...\n"
46 "Recursively updates the MIME related attributes (e.g. file type) for\n"
47 "the given files. Alternatively or additionally encountered\n"
48 "applications are entered into the MIME database. When \"@\" is\n"
49 "specified as <path>, file paths are read from stdin.\n"
50 "\n"
51 "Options:\n"
52 " -A, --all\n"
53 " Update the files' MIME information and enter applications into\n"
54 " the MIME database.\n"
55 " -a, --apps\n"
56 " Only enter applications into the MIME database.\n"
57 " -f\n"
58 " Force updating, even if previously updated, but do not overwrite\n"
59 " the type of a file.\n"
60 " -F\n"
61 " Force updating, even if previously updated. Also overwrite the\n"
62 " type of a file.\n"
63 " -h, --help\n"
64 " Display this help information.\n"
65 " -m, --mimedb <directory>\n"
66 " Instead of the system MIME DB use the given directory\n"
67 " <directory>. The option can occur multiple times to specify a\n"
68 " list of directories. MIME DB changes are written to the first\n"
69 " specified directory.\n"
70 "\n"
71 "Obsolete options:\n"
72 " -all (synonymous with --all)\n"
73 " -apps (synonymous with --apps)\n"
74 "\n",
75 sProgramName);
77 exit(status);
81 static status_t
82 process_file_with_custom_mime_db(const BEntry& entry)
84 AppMetaMimeCreator appMetaMimeCreator(sDatabase, NULL, gForce);
85 MimeInfoUpdater mimeInfoUpdater(sDatabase, NULL, gForce);
87 entry_ref ref;
88 status_t error = entry.GetRef(&ref);
90 if (gFiles && error == B_OK)
91 error = mimeInfoUpdater.DoRecursively(ref);
92 if (gApps && error == B_OK) {
93 error = appMetaMimeCreator.DoRecursively(ref);
94 if (error == B_BAD_TYPE) {
95 // Ignore B_BAD_TYPE silently. The most likely cause is that the
96 // file doesn't have a "BEOS:APP_SIG" attribute.
97 error = B_OK;
101 if (error != B_OK) {
102 BPath path;
103 fprintf(stderr, "%s: \"%s\": %s\n",
104 sProgramName,
105 entry.GetPath(&path) == B_OK ? path.Path() : entry.Name(),
106 strerror(error));
107 return error;
110 return B_OK;
114 static status_t
115 process_file(const char* path)
117 status_t status = B_OK;
119 BEntry entry(path);
120 if (!entry.Exists())
121 status = B_ENTRY_NOT_FOUND;
123 if (sDatabase != NULL)
124 return process_file_with_custom_mime_db(entry);
126 if (gFiles && status == B_OK)
127 status = update_mime_info(path, true, true, gForce);
128 if (gApps && status == B_OK)
129 status = create_app_meta_mime(path, true, true, gForce);
131 if (status != B_OK) {
132 fprintf(stderr, "%s: \"%s\": %s\n",
133 sProgramName, path, strerror(status));
135 return status;
140 main(int argc, const char** argv)
142 // parse arguments
144 // replace old-style options first
145 for (int i = 1; i < argc; i++) {
146 const char* arg = argv[i];
147 if (*arg != '-')
148 break;
149 if (strcmp(arg, "-all") == 0)
150 argv[i] = "--all";
151 else if (strcmp(arg, "-apps") == 0)
152 argv[i] = "--apps";
155 BStringList databaseDirectories;
157 for (;;) {
158 static struct option sLongOptions[] = {
159 { "all", no_argument, 0, 'A' },
160 { "apps", no_argument, 0, 'a' },
161 { "help", no_argument, 0, 'h' },
162 { "mimedb", required_argument, 0, 'm' },
163 { 0, 0, 0, 0 }
166 opterr = 0; // don't print errors
167 int c = getopt_long(argc, (char**)argv, "aAfFhm:", sLongOptions,
168 NULL);
169 if (c == -1)
170 break;
172 switch (c) {
173 case 'a':
174 gApps = true;
175 gFiles = false;
176 break;
177 case 'A':
178 gApps = true;
179 gFiles = true;
180 break;
181 case 'f':
182 gForce = B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE;
183 break;
184 case 'F':
185 gForce = B_UPDATE_MIME_INFO_FORCE_UPDATE_ALL;
186 break;
187 case 'h':
188 usage(0);
189 break;
190 case 'm':
191 databaseDirectories.Add(optarg);
192 break;
193 default:
194 usage(1);
195 break;
199 if (argc - optind < 1)
200 usage(1);
202 // set up custom MIME DB, if specified
203 DatabaseLocation databaseLocation;
204 if (!databaseDirectories.IsEmpty()) {
205 int32 count = databaseDirectories.CountStrings();
206 for (int32 i = 0; i < count; i++)
207 databaseLocation.AddDirectory(databaseDirectories.StringAt(i));
209 status_t error = MimeSnifferAddonManager::CreateDefault();
210 if (error != B_OK) {
211 fprintf(stderr, "%s: Failed to create MIME sniffer add-on "
212 "manager: %s\n", sProgramName, strerror(error));
213 exit(1);
215 MimeSnifferAddonManager* manager = MimeSnifferAddonManager::Default();
216 manager->AddMimeSnifferAddon(
217 new(std::nothrow) TextSnifferAddon(&databaseLocation));
219 sDatabase = new(std::nothrow) Database(&databaseLocation, manager,
220 NULL);
221 if (sDatabase == NULL) {
222 fprintf(stderr, "%s: Out of memory!\n", sProgramName);
223 exit(1);
226 error = sDatabase->InitCheck();
227 if (error != B_OK) {
228 fprintf(stderr, "%s: Failed to init MIME DB: %s\n", sProgramName,
229 strerror(error));
230 exit(1);
234 // process files
236 BApplication app("application/x-vnd.haiku.mimeset");
238 for (; optind < argc; optind++) {
239 const char* arg = argv[optind];
241 if (strcmp(arg, "@") == 0) {
242 // read file names from stdin
243 char name[B_PATH_NAME_LENGTH];
244 while (fgets(name, sizeof(name), stdin) != NULL) {
245 name[strlen(name) - 1] = '\0';
246 // remove trailing '\n'
247 if (process_file(name) != B_OK)
248 exit(1);
250 } else {
251 if (process_file(arg) != B_OK)
252 exit(1);
256 return 0;