1 /* 2 * Copyright 2002-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 */ 8 9 /*! 10 \file database_support.cpp 11 Private mime database functions and constants 12 */ 13 14 #include <AppMisc.h> 15 #include <DataIO.h> 16 #include <Directory.h> 17 #include <Entry.h> 18 #include <FindDirectory.h> 19 #include <Message.h> 20 #include <Node.h> 21 #include <Path.h> 22 #include <storage_support.h> 23 #include <TypeConstants.h> 24 25 #include <fs_attr.h> // For struct attr_info 26 #include <new> // For new(nothrow) 27 #include <stdio.h> 28 #include <string> 29 30 #include "mime/database_support.h" 31 32 //#define DBG(x) x 33 #define DBG(x) 34 #define OUT printf 35 36 37 namespace BPrivate { 38 namespace Storage { 39 namespace Mime { 40 41 static const char *get_user_settings_dir(BPath &path); 42 43 static BPath sSettingsDirPath; 44 static const std::string sSettingsDir = get_user_settings_dir(sSettingsDirPath); 45 46 static const char *sHaikuDBDirName = "beos_mime"; 47 // when running natively under Haiku 48 static const char *sBeOSDBDirName = "obos_mime"; 49 // when running under BeOS 50 const std::string kDatabaseDir = sSettingsDir + "/" 51 + (is_running_on_haiku() ? sHaikuDBDirName : sBeOSDBDirName); 52 const std::string kApplicationDatabaseDir = kDatabaseDir + "/application"; 53 54 #define ATTR_PREFIX "META:" 55 #define MINI_ICON_ATTR_PREFIX ATTR_PREFIX "M:" 56 #define LARGE_ICON_ATTR_PREFIX ATTR_PREFIX "L:" 57 58 const char *kMiniIconAttrPrefix = MINI_ICON_ATTR_PREFIX; 59 const char *kLargeIconAttrPrefix = LARGE_ICON_ATTR_PREFIX; 60 const char *kIconAttrPrefix = ATTR_PREFIX; 61 62 // attribute names 63 const char *kFileTypeAttr = "BEOS:TYPE"; 64 const char *kTypeAttr = ATTR_PREFIX "TYPE"; 65 const char *kAppHintAttr = ATTR_PREFIX "PPATH"; 66 const char *kAttrInfoAttr = ATTR_PREFIX "ATTR_INFO"; 67 const char *kShortDescriptionAttr = ATTR_PREFIX "S:DESC"; 68 const char *kLongDescriptionAttr = ATTR_PREFIX "L:DESC"; 69 const char *kFileExtensionsAttr = ATTR_PREFIX "EXTENS"; 70 const char *kMiniIconAttr = MINI_ICON_ATTR_PREFIX "STD_ICON"; 71 const char *kLargeIconAttr = LARGE_ICON_ATTR_PREFIX "STD_ICON"; 72 const char *kIconAttr = ATTR_PREFIX "ICON"; 73 const char *kPreferredAppAttr = ATTR_PREFIX "PREF_APP"; 74 const char *kSnifferRuleAttr = ATTR_PREFIX "SNIFF_RULE"; 75 const char *kSupportedTypesAttr = ATTR_PREFIX "FILE_TYPES"; 76 77 // attribute data types (as used in the R5 database) 78 const int32 kFileTypeType = 'MIMS'; // B_MIME_STRING_TYPE 79 const int32 kTypeType = B_STRING_TYPE; 80 const int32 kAppHintType = 'MPTH'; 81 const int32 kAttrInfoType = B_MESSAGE_TYPE; 82 const int32 kShortDescriptionType = 'MSDC'; 83 const int32 kLongDescriptionType = 'MLDC'; 84 const int32 kFileExtensionsType = B_MESSAGE_TYPE; 85 const int32 kMiniIconType = B_MINI_ICON_TYPE; 86 const int32 kLargeIconType = B_LARGE_ICON_TYPE; 87 const int32 kIconType = B_VECTOR_ICON_TYPE; 88 const int32 kPreferredAppType = 'MSIG'; 89 const int32 kSnifferRuleType = B_STRING_TYPE; 90 const int32 kSupportedTypesType = B_MESSAGE_TYPE; 91 92 // Message fields 93 const char *kApplicationsField = "applications"; 94 const char *kExtensionsField = "extensions"; 95 const char *kSupertypesField = "super_types"; 96 const char *kSupportingAppsSubCountField = "be:sub"; 97 const char *kSupportingAppsSuperCountField = "be:super"; 98 const char *kTypesField = "types"; 99 100 // Mime types 101 const char *kGenericFileType = "application/octet-stream"; 102 const char *kDirectoryType = "application/x-vnd.Be-directory"; 103 const char *kSymlinkType = "application/x-vnd.Be-symlink"; 104 const char *kMetaMimeType = "application/x-vnd.Be-meta-mime"; 105 106 // Error codes 107 const status_t kMimeGuessFailureError = B_ERRORS_END+1; 108 109 // get_settings_dir 110 /*! \brief Sets the supplied BPath to the user settings directory and returns 111 it as C string. 112 \param path BPath to be set to the user settings path. 113 \return the user settings path as C string (\code path.Path() \endcode). 114 */ 115 static 116 const char* 117 get_user_settings_dir(BPath &path) 118 { 119 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 120 path.SetTo("/boot/home/config/settings"); 121 return path.Path(); 122 } 123 124 // type_to_filename 125 //! Converts the given MIME type to an absolute path in the MIME database. 126 std::string 127 type_to_filename(const char *type) 128 { 129 return kDatabaseDir + "/" + BPrivate::Storage::to_lower(type); 130 } 131 132 // open_type 133 /*! \brief Opens a BNode on the given type, failing if the type has no 134 corresponding file in the database. 135 \param type The MIME type to open 136 \param result Pointer to a pre-allocated BNode into which 137 is opened on the given MIME type 138 */ 139 status_t 140 open_type(const char *type, BNode *result) 141 { 142 if (type == NULL || result == NULL) 143 return B_BAD_VALUE; 144 145 status_t status = result->SetTo(type_to_filename(type).c_str()); 146 147 // TODO: this can be removed again later - we just didn't write this 148 // attribute is before at all... 149 #if 1 150 if (status == B_OK) { 151 // check if the MIME:TYPE attribute exist, and create it if not 152 attr_info info; 153 if (result->GetAttrInfo(kTypeAttr, &info) != B_OK) 154 result->WriteAttr(kTypeAttr, B_STRING_TYPE, 0, type, strlen(type) + 1); 155 } 156 #endif 157 158 return status; 159 } 160 161 // open_or_create_type 162 /*! \brief Opens a BNode on the given type, creating a node of the 163 appropriate flavor if necessary. 164 165 All MIME types are converted to lowercase for use in the filesystem. 166 \param type The MIME type to open 167 \param result Pointer to a pre-allocated BNode into which 168 is opened on the given MIME type 169 */ 170 status_t 171 open_or_create_type(const char *type, BNode *result, bool *didCreate) 172 { 173 if (didCreate) 174 *didCreate = false; 175 std::string filename; 176 std::string typeLower = BPrivate::Storage::to_lower(type); 177 status_t err = (type && result ? B_OK : B_BAD_VALUE); 178 if (!err) { 179 filename = type_to_filename(type); 180 err = result->SetTo(filename.c_str()); 181 } 182 if (err == B_ENTRY_NOT_FOUND) { 183 // Figure out what type of node we need to create 184 // + Supertype == directory 185 // + Non-supertype == file 186 uint32 pos = typeLower.find_first_of('/'); 187 if (pos == std::string::npos) { 188 // Supertype == directory 189 BDirectory parent(kDatabaseDir.c_str()); 190 err = parent.InitCheck(); 191 if (!err) 192 err = parent.CreateDirectory(typeLower.c_str(), NULL); 193 } else { 194 // Non-supertype == file 195 std::string super(typeLower, 0, pos); 196 std::string sub(typeLower, pos+1); 197 BDirectory parent((kDatabaseDir + "/" + super).c_str()); 198 err = parent.InitCheck(); 199 if (!err) 200 err = parent.CreateFile(sub.c_str(), NULL); 201 } 202 // Now try opening again 203 if (err == B_OK) 204 err = result->SetTo(filename.c_str()); 205 if (err == B_OK && didCreate) 206 *didCreate = true; 207 if (err == B_OK) { 208 // write META:TYPE attribute 209 result->WriteAttr(kTypeAttr, B_STRING_TYPE, 0, type, strlen(type) + 1); 210 } 211 } 212 return err; 213 } 214 215 // read_mime_attr 216 /*! \brief Reads up to \c len bytes of the given data from the given attribute 217 for the given MIME type. 218 219 If no entry for the given type exists in the database, the function fails, 220 and the contents of \c data are undefined. 221 222 \param type The MIME type 223 \param attr The attribute name 224 \param data Pointer to a memory buffer into which the data should be copied 225 \param len The maximum number of bytes to read 226 \param datatype The expected data type 227 \return If successful, the number of bytes read is returned, otherwise, an 228 error code is returned. 229 */ 230 ssize_t 231 read_mime_attr(const char *type, const char *attr, void *data, 232 size_t len, type_code datatype) 233 { 234 BNode node; 235 ssize_t err = (type && attr && data ? B_OK : B_BAD_VALUE); 236 if (!err) 237 err = open_type(type, &node); 238 if (!err) 239 err = node.ReadAttr(attr, datatype, 0, data, len); 240 return err; 241 } 242 243 // read_mime_attr_message 244 /*! \brief Reads a flattened BMessage from the given attribute of the given 245 MIME type. 246 247 If no entry for the given type exists in the database, or if the data 248 stored in the attribute is not a flattened BMessage, the function fails 249 and the contents of \c msg are undefined. 250 251 \param type The MIME type 252 \param attr The attribute name 253 \param data Pointer to a pre-allocated BMessage into which the attribute 254 data is unflattened. 255 */ 256 status_t 257 read_mime_attr_message(const char *type, const char *attr, BMessage *msg) 258 { 259 BNode node; 260 attr_info info; 261 char *buffer = NULL; 262 ssize_t err = (type && attr && msg ? B_OK : B_BAD_VALUE); 263 if (!err) 264 err = open_type(type, &node); 265 if (!err) 266 err = node.GetAttrInfo(attr, &info); 267 if (!err) 268 err = info.type == B_MESSAGE_TYPE ? B_OK : B_BAD_VALUE; 269 if (!err) { 270 buffer = new(std::nothrow) char[info.size]; 271 if (!buffer) 272 err = B_NO_MEMORY; 273 } 274 if (!err) 275 err = node.ReadAttr(attr, B_MESSAGE_TYPE, 0, buffer, info.size); 276 if (err >= 0) 277 err = err == info.size ? (status_t)B_OK : (status_t)B_FILE_ERROR; 278 if (!err) 279 err = msg->Unflatten(buffer); 280 delete [] buffer; 281 return err; 282 } 283 284 // read_mime_attr_string 285 /*! \brief Reads a BString from the given attribute of the given 286 MIME type. 287 288 If no entry for the given type exists in the database, the function fails 289 and the contents of \c str are undefined. 290 291 \param type The MIME type 292 \param attr The attribute name 293 \param str Pointer to a pre-allocated BString into which the attribute 294 data stored. 295 */ 296 status_t 297 read_mime_attr_string(const char *type, const char *attr, BString *str) 298 { 299 BNode node; 300 status_t err = (type && attr && str ? B_OK : B_BAD_VALUE); 301 if (!err) 302 err = open_type(type, &node); 303 if (!err) 304 err = node.ReadAttrString(attr, str); 305 return err; 306 } 307 308 // write_mime_attr 309 /*! \brief Writes \c len bytes of the given data to the given attribute 310 for the given MIME type. 311 312 If no entry for the given type exists in the database, it is created. 313 314 \param type The MIME type 315 \param attr The attribute name 316 \param data Pointer to the data to write 317 \param len The number of bytes to write 318 \param datatype The data type of the given data 319 */ 320 status_t 321 write_mime_attr(const char *type, const char *attr, const void *data, 322 size_t len, type_code datatype, bool *didCreate) 323 { 324 BNode node; 325 status_t err = (type && attr && data ? B_OK : B_BAD_VALUE); 326 if (!err) 327 err = open_or_create_type(type, &node, didCreate); 328 if (!err) { 329 ssize_t bytes = node.WriteAttr(attr, datatype, 0, data, len); 330 if (bytes < B_OK) 331 err = bytes; 332 else 333 err = (bytes != (ssize_t)len ? (status_t)B_FILE_ERROR : (status_t)B_OK); 334 } 335 return err; 336 } 337 338 // write_mime_attr_message 339 /*! \brief Flattens the given \c BMessage and writes it to the given attribute 340 of the given MIME type. 341 342 If no entry for the given type exists in the database, it is created. 343 344 \param type The MIME type 345 \param attr The attribute name 346 \param msg The BMessage to flatten and write 347 */ 348 status_t 349 write_mime_attr_message(const char *type, const char *attr, const BMessage *msg, bool *didCreate) 350 { 351 BNode node; 352 BMallocIO data; 353 ssize_t bytes; 354 ssize_t err = (type && attr && msg ? B_OK : B_BAD_VALUE); 355 if (!err) 356 err = data.SetSize(msg->FlattenedSize()); 357 if (!err) 358 err = msg->Flatten(&data, &bytes); 359 if (!err) 360 err = bytes == msg->FlattenedSize() ? B_OK : B_ERROR; 361 if (!err) 362 err = open_or_create_type(type, &node, didCreate); 363 if (!err) 364 err = node.WriteAttr(attr, B_MESSAGE_TYPE, 0, data.Buffer(), data.BufferLength()); 365 if (err >= 0) 366 err = err == (ssize_t)data.BufferLength() ? (ssize_t)B_OK : (ssize_t)B_FILE_ERROR; 367 return err; 368 } 369 370 // delete_attribute 371 //! Deletes the given attribute for the given type 372 /*! 373 \param type The mime type 374 \param attr The attribute name 375 \return 376 - B_OK: success 377 - B_ENTRY_NOT_FOUND: no such type or attribute 378 - "error code": failure 379 */ 380 status_t 381 delete_attribute(const char *type, const char *attr) 382 { 383 status_t err = type ? B_OK : B_BAD_VALUE; 384 BNode node; 385 if (!err) 386 err = open_type(type, &node); 387 if (!err) 388 err = node.RemoveAttr(attr); 389 return err; 390 } 391 392 393 394 } // namespace Mime 395 } // namespace Storage 396 } // namespace BPrivate 397 398