1/* 2 * Copyright 2002-2006, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 * Ingo Weinhold, bonefish@users.sf.net 8 */ 9 10/*! 11 \file UpdateMimeInfoThread.h 12 UpdateMimeInfoThread implementation 13*/ 14 15#include "mime/UpdateMimeInfoThread.h" 16 17#include <AppFileInfo.h> 18#include <Bitmap.h> 19#include <fs_attr.h> 20#include <Message.h> 21#include <Messenger.h> 22#include <mime/database_support.h> 23#include <Node.h> 24#include <Resources.h> 25#include <String.h> 26 27#if !defined(__BEOS__) || defined(__HAIKU__) 28# include <MimeType.h> 29#else 30# define B_VECTOR_ICON_TYPE 'VICN' 31#endif 32 33#ifndef B_UPDATE_MIME_INFO_FORCE_UPDATE_ALL 34# define B_UPDATE_MIME_INFO_FORCE_UPDATE_ALL 2 35#endif 36#ifndef B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE 37# define B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE 1 38#endif 39#ifndef B_BITMAP_NO_SERVER_LINK 40# define B_BITMAP_NO_SERVER_LINK 0 41#endif 42 43namespace BPrivate { 44namespace Storage { 45namespace Mime { 46 47static const char *kAppFlagsAttribute = "BEOS:APP_FLAGS"; 48 49 50static status_t 51update_icon(BAppFileInfo &appFileInfoRead, BAppFileInfo &appFileInfoWrite, 52 const char *type, BBitmap &icon, icon_size iconSize) 53{ 54 status_t err = appFileInfoRead.GetIconForType(type, &icon, iconSize); 55 if (err == B_OK) 56 err = appFileInfoWrite.SetIconForType(type, &icon, iconSize); 57 else if (err == B_ENTRY_NOT_FOUND || err == B_NAME_NOT_FOUND) { 58 err = appFileInfoWrite.SetIconForType(type, NULL, iconSize); 59#if defined(__BEOS__) && !defined(__HAIKU__) 60 // gives an error if the attribute didn't exist yet... 61 err = B_OK; 62#endif 63 } 64 65 return err; 66} 67 68 69/*! 70 This updates the vector icon of the file from its resources. 71 Instead of putting this functionality into BAppFileInfo (as done in Haiku), 72 we're doing it here, so that the mimeset executable that runs under BeOS 73 can make use of it as well. 74*/ 75static status_t 76update_vector_icon(BFile& file, const char *type) 77{ 78 // try to read icon from resources 79 BResources resources(&file); 80 81 BString name("BEOS:"); 82 83 // check type param 84 if (type) { 85 if (BMimeType::IsValid(type)) 86 name += type; 87 else 88 return B_BAD_VALUE; 89 } else 90 name += "ICON"; 91 92 size_t size; 93 const void* data = resources.LoadResource(B_VECTOR_ICON_TYPE, name.String(), &size); 94 if (data == NULL) { 95 // remove attribute; the resources don't have an icon 96 file.RemoveAttr(name.String()); 97 return B_OK; 98 } 99 100 // update icon 101 102 ssize_t written = file.WriteAttr(name.String(), B_VECTOR_ICON_TYPE, 0, data, size); 103 if (written < B_OK) 104 return written; 105 if ((size_t)written < size) { 106 file.RemoveAttr(name.String()); 107 return B_ERROR; 108 } 109 return B_OK; 110} 111 112 113#if defined(__BEOS__) || !defined(__HAIKU__) 114// BMimeType::GuessMimeType() doesn't seem to work under BeOS 115status_t 116guess_mime_type(const void *_buffer, int32 length, BMimeType *type) 117{ 118 const uint8 *buffer = (const uint8*)_buffer; 119 if (!buffer || !type) 120 return B_BAD_VALUE; 121 122 // we only know ELF files 123 if (length >= 4 && buffer[0] == 0x7f && buffer[1] == 'E' && buffer[2] == 'L' 124 && buffer[3] == 'F') { 125 return type->SetType(B_ELF_APP_MIME_TYPE); 126 } 127 128 return type->SetType(B_FILE_MIME_TYPE); 129} 130 131 132status_t 133guess_mime_type(const entry_ref *ref, BMimeType *type) 134{ 135 if (!ref || !type) 136 return B_BAD_VALUE; 137 138 // get BEntry 139 BEntry entry; 140 status_t error = entry.SetTo(ref); 141 if (error != B_OK) 142 return error; 143 144 // does entry exist? 145 if (!entry.Exists()) 146 return B_ENTRY_NOT_FOUND; 147 148 // check entry type 149 if (entry.IsDirectory()) 150 return type->SetType("application/x-vnd.be-directory"); 151 if (entry.IsSymLink()) 152 return type->SetType("application/x-vnd.be-symlink"); 153 if (!entry.IsFile()) 154 return B_ERROR; 155 156 // we have a file, read the first 4 bytes 157 BFile file; 158 char buffer[4]; 159 if (file.SetTo(ref, B_READ_ONLY) == B_OK 160 && file.Read(buffer, 4) == 4) { 161 return guess_mime_type(buffer, 4, type); 162 } 163 164 // we couldn't open or read the file 165 return type->SetType(B_FILE_MIME_TYPE); 166} 167#endif 168 169 170static bool 171is_shared_object_mime_type(BMimeType &type) 172{ 173 return (type == B_APP_MIME_TYPE); 174} 175 176 177// #pragma mark - 178 179 180//! Creates a new UpdateMimeInfoThread object 181UpdateMimeInfoThread::UpdateMimeInfoThread(const char *name, int32 priority, 182 BMessenger managerMessenger, const entry_ref *root, bool recursive, 183 int32 force, BMessage *replyee) 184 : MimeUpdateThread(name, priority, managerMessenger, root, recursive, force, 185 replyee) 186{ 187} 188 189// DoMimeUpdate 190/*! \brief Performs an update_mime_info() update on the given entry 191 192 If the entry has no \c BEOS:TYPE attribute, or if \c fForce is true, the 193 entry is sniffed and its \c BEOS:TYPE attribute is set accordingly. 194*/ 195status_t 196UpdateMimeInfoThread::DoMimeUpdate(const entry_ref *entry, bool *entryIsDir) 197{ 198 if (entry == NULL) 199 return B_BAD_VALUE; 200 201 bool updateType = false; 202 bool updateAppInfo = false; 203 204 BNode node; 205 status_t err = node.SetTo(entry); 206 if (!err && entryIsDir) 207 *entryIsDir = node.IsDirectory(); 208 if (!err) { 209 // If not forced, only update if the entry has no file type attribute 210 attr_info info; 211 if (fForce == B_UPDATE_MIME_INFO_FORCE_UPDATE_ALL 212 || node.GetAttrInfo(kFileTypeAttr, &info) == B_ENTRY_NOT_FOUND) 213 updateType = true; 214 215 updateAppInfo = updateType 216 || fForce == B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE; 217 } 218 219 // guess the MIME type 220 BMimeType type; 221 if (!err && (updateType || updateAppInfo)) { 222 err = BMimeType::GuessMimeType(entry, &type); 223#if defined(__BEOS__) && !defined(__HAIKU__) 224 // GuessMimeType() doesn't seem to work correctly under BeOS 225 if (err) 226 err = guess_mime_type(entry, &type); 227#endif 228 if (!err) 229 err = type.InitCheck(); 230 } 231 232 // update the MIME type 233 if (!err && updateType) { 234 const char *typeStr = type.Type(); 235 ssize_t len = strlen(typeStr) + 1; 236 ssize_t bytes = node.WriteAttr(kFileTypeAttr, kFileTypeType, 0, 237 typeStr, len); 238 if (bytes < B_OK) 239 err = bytes; 240 else 241 err = (bytes != len ? (status_t)B_FILE_ERROR : (status_t)B_OK); 242 } 243 244 // update the app file info attributes, if this is a shared object 245 BFile file; 246 BAppFileInfo appFileInfoRead; 247 BAppFileInfo appFileInfoWrite; 248 if (!err && updateAppInfo && node.IsFile() 249 && is_shared_object_mime_type(type) 250 && file.SetTo(entry, B_READ_WRITE) == B_OK 251 && appFileInfoRead.SetTo(&file) == B_OK 252 && appFileInfoWrite.SetTo(&file) == B_OK) { 253 // we read from resources and write to attributes 254 appFileInfoRead.SetInfoLocation(B_USE_RESOURCES); 255 appFileInfoWrite.SetInfoLocation(B_USE_ATTRIBUTES); 256 257 // signature 258 char signature[B_MIME_TYPE_LENGTH]; 259 err = appFileInfoRead.GetSignature(signature); 260 if (err == B_OK) 261 err = appFileInfoWrite.SetSignature(signature); 262 else if (err == B_ENTRY_NOT_FOUND || err == B_NAME_NOT_FOUND || err == B_BAD_VALUE) { 263 // BeOS returns B_BAD_VALUE on shared libraries 264 err = appFileInfoWrite.SetSignature(NULL); 265#if defined(__BEOS__) && !defined(__HAIKU__) 266 err = B_OK; 267#endif 268 } 269 if (err != B_OK) 270 return err; 271 272 // catalog entry 273 char catalogEntry[B_MIME_TYPE_LENGTH * 3]; 274 err = appFileInfoRead.GetCatalogEntry(catalogEntry); 275 if (err == B_OK) 276 err = appFileInfoWrite.SetCatalogEntry(catalogEntry); 277 else if (err == B_ENTRY_NOT_FOUND) 278 err = appFileInfoWrite.SetCatalogEntry(NULL); 279 if (err != B_OK) 280 return err; 281 282 // app flags 283 uint32 appFlags; 284 err = appFileInfoRead.GetAppFlags(&appFlags); 285 if (err == B_OK) { 286 err = appFileInfoWrite.SetAppFlags(appFlags); 287 } else if (err == B_ENTRY_NOT_FOUND || err == B_NAME_NOT_FOUND || err == B_BAD_VALUE) { 288 file.RemoveAttr(kAppFlagsAttribute); 289 err = B_OK; 290 } 291 if (err != B_OK) 292 return err; 293 294 // supported types 295 BMessage supportedTypes; 296 bool hasSupportedTypes = false; 297 err = appFileInfoRead.GetSupportedTypes(&supportedTypes); 298 if (err == B_OK) { 299 err = appFileInfoWrite.SetSupportedTypes(&supportedTypes); 300 hasSupportedTypes = true; 301 } else if (err == B_ENTRY_NOT_FOUND || err == B_NAME_NOT_FOUND || err == B_BAD_VALUE) { 302#if defined(__BEOS__) && !defined(__HAIKU__) 303 file.RemoveAttr(kSupportedTypesAttr); 304 err = B_OK; 305#else 306 err = appFileInfoWrite.SetSupportedTypes(NULL); 307#endif 308 } 309 if (err != B_OK) 310 return err; 311 312 // vector icon 313 err = update_vector_icon(file, NULL); 314 if (err != B_OK) 315 return err; 316 317 // small icon 318 BBitmap smallIcon(BRect(0, 0, 15, 15), B_BITMAP_NO_SERVER_LINK, 319 B_CMAP8); 320 if (smallIcon.InitCheck() != B_OK) 321 return smallIcon.InitCheck(); 322 err = update_icon(appFileInfoRead, appFileInfoWrite, NULL, smallIcon, 323 B_MINI_ICON); 324 if (err != B_OK) 325 return err; 326 327 // large icon 328 BBitmap largeIcon(BRect(0, 0, 31, 31), B_BITMAP_NO_SERVER_LINK, 329 B_CMAP8); 330 if (largeIcon.InitCheck() != B_OK) 331 return largeIcon.InitCheck(); 332 err = update_icon(appFileInfoRead, appFileInfoWrite, NULL, largeIcon, 333 B_LARGE_ICON); 334 if (err != B_OK) 335 return err; 336 337 // version infos 338 const version_kind versionKinds[] 339 = {B_APP_VERSION_KIND, B_SYSTEM_VERSION_KIND}; 340 for (int i = 0; i < 2; i++) { 341 version_kind kind = versionKinds[i]; 342 version_info versionInfo; 343 err = appFileInfoRead.GetVersionInfo(&versionInfo, kind); 344 if (err == B_OK) 345 err = appFileInfoWrite.SetVersionInfo(&versionInfo, kind); 346 else if (err == B_ENTRY_NOT_FOUND || err == B_NAME_NOT_FOUND || err == B_BAD_VALUE) { 347#if !defined(HAIKU_HOST_PLATFORM_DANO) && !defined(HAIKU_HOST_PLATFORM_BEOS) && !defined(HAIKU_HOST_PLATFORM_BONE) 348 // BeOS crashes when calling SetVersionInfo() with a NULL pointer 349 err = appFileInfoWrite.SetVersionInfo(NULL, kind); 350#else 351 err = B_OK; 352#endif 353 } 354 if (err != B_OK) 355 return err; 356 } 357 358 // icons for supported types 359 if (hasSupportedTypes) { 360 const char *supportedType; 361 for (int32 i = 0; 362 supportedTypes.FindString("types", i, &supportedType) == B_OK; 363 i++) { 364 // vector icon 365 err = update_vector_icon(file, supportedType); 366 if (err != B_OK) 367 return err; 368 369 // small icon 370 err = update_icon(appFileInfoRead, appFileInfoWrite, 371 supportedType, smallIcon, B_MINI_ICON); 372 if (err != B_OK) 373 return err; 374 375 // large icon 376 err = update_icon(appFileInfoRead, appFileInfoWrite, 377 supportedType, largeIcon, B_LARGE_ICON); 378 if (err != B_OK) 379 return err; 380 } 381 } 382 } 383 384 return err; 385} 386 387} // namespace Mime 388} // namespace Storage 389} // namespace BPrivate 390