mar.h (10243B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef MAR_H__ 8 #define MAR_H__ 9 10 #include <assert.h> // for C11 static_assert 11 #include <stdint.h> 12 #include <stdio.h> 13 14 #ifdef __cplusplus 15 extern "C" { 16 #endif 17 18 /* We have a MAX_SIGNATURES limit so that an invalid MAR will never 19 * waste too much of either updater's or signmar's time. 20 * It is also used at various places internally and will affect memory usage. 21 * If you want to increase this value above 9 then you need to adjust parsing 22 * code in tool/mar.c. 23 */ 24 #define MAX_SIGNATURES 8 25 static_assert(MAX_SIGNATURES <= 9, "too many signatures"); 26 27 struct ProductInformationBlock { 28 const char* MARChannelID; 29 const char* productVersion; 30 }; 31 32 /** 33 * The MAR item data structure. 34 */ 35 typedef struct MarItem_ { 36 struct MarItem_* next; /* private field */ 37 uint32_t offset; /* offset into archive */ 38 uint32_t length; /* length of data in bytes */ 39 uint32_t flags; /* contains file mode bits */ 40 char name[1]; /* file path */ 41 } MarItem; 42 43 /** 44 * File offset and length for tracking access of byte indexes 45 */ 46 typedef struct SeenIndex_ { 47 struct SeenIndex_* next; /* private field */ 48 uint32_t offset; /* offset into archive */ 49 uint32_t length; /* length of the data in bytes */ 50 } SeenIndex; 51 52 #define TABLESIZE 256 53 54 /** 55 * Mozilla ARchive (MAR) file data structure 56 */ 57 struct MarFile_ { 58 unsigned char* buffer; /* file buffer containing the entire MAR */ 59 size_t data_len; /* byte count of the data in the buffer */ 60 MarItem* item_table[TABLESIZE]; /* hash table of files in the archive */ 61 SeenIndex* index_list; /* file indexes processed */ 62 int item_table_is_valid; /* header and index validation flag */ 63 }; 64 65 typedef struct MarFile_ MarFile; 66 67 /** 68 * Signature of callback function passed to mar_enum_items. 69 * @param mar The MAR file being visited. 70 * @param item The MAR item being visited. 71 * @param data The data parameter passed by the caller of mar_enum_items. 72 * @return A non-zero value to stop enumerating. 73 */ 74 typedef int (*MarItemCallback)(MarFile* mar, const MarItem* item, void* data); 75 76 enum MarReadResult_ { 77 MAR_READ_SUCCESS, 78 MAR_IO_ERROR, 79 MAR_MEM_ERROR, 80 MAR_FILE_TOO_BIG_ERROR, 81 }; 82 83 typedef enum MarReadResult_ MarReadResult; 84 85 /** 86 * Open a MAR file for reading. 87 * @param path Specifies the path to the MAR file to open. This path must 88 * be compatible with fopen. 89 * @param out_mar Out-parameter through which the created MarFile structure is 90 * returned. Guaranteed to be a valid structure if 91 * MAR_READ_SUCCESS is returned. Otherwise NULL will be 92 * assigned. 93 * @return NULL if an error occurs. 94 */ 95 MarReadResult mar_open(const char* path, MarFile** out_mar); 96 97 #ifdef XP_WIN 98 MarReadResult mar_wopen(const wchar_t* path, MarFile** out_mar); 99 #endif 100 101 /** 102 * Close a MAR file that was opened using mar_open. 103 * @param mar The MarFile object to close. 104 */ 105 void mar_close(MarFile* mar); 106 107 /** 108 * Reads the specified amount of data from the buffer in MarFile that contains 109 * the entirety of the MAR file data. 110 * @param mar The MAR file to read from. 111 * @param dest The buffer to read into. 112 * @param position The byte index to start reading from the MAR at. 113 * On success, position will be incremented by size. 114 * @param size The number of bytes to read. 115 * @return 0 If the specified amount of data was read. 116 * -1 If the buffer MAR is not large enough to read the 117 * specified amount of data at the specified position. 118 */ 119 int mar_read_buffer(MarFile* mar, void* dest, size_t* position, size_t size); 120 121 /** 122 * Reads the specified amount of data from the buffer in MarFile that contains 123 * the entirety of the MAR file data. If there isn't that much data remaining, 124 * reads as much as possible. 125 * @param mar The MAR file to read from. 126 * @param dest The buffer to read into. 127 * @param position The byte index to start reading from the MAR at. 128 * This function will increment position by the number of bytes 129 * copied. 130 * @param size The maximum number of bytes to read. 131 * @return The number of bytes copied into dest. 132 */ 133 int mar_read_buffer_max(MarFile* mar, void* dest, size_t* position, 134 size_t size); 135 136 /** 137 * Increments position by distance. Checks that the resulting position is still 138 * within the bounds of the buffer. Much like fseek, this will allow position to 139 * be successfully placed just after the end of the buffer. 140 * @param mar The MAR file to read from. 141 * @param position The byte index to start reading from the MAR at. 142 * On success, position will be incremented by size. 143 * @param distance The number of bytes to move forward by. 144 * @return 0 If position was successfully moved. 145 * -1 If moving position by distance would move it outside the 146 * bounds of the buffer. 147 */ 148 int mar_buffer_seek(MarFile* mar, size_t* position, size_t distance); 149 150 /** 151 * Find an item in the MAR file by name. 152 * @param mar The MarFile object to query. 153 * @param item The name of the item to query. 154 * @return A const reference to a MAR item or NULL if not found. 155 */ 156 const MarItem* mar_find_item(MarFile* mar, const char* item); 157 158 /** 159 * Enumerate all MAR items via callback function. 160 * @param mar The MAR file to enumerate. 161 * @param callback The function to call for each MAR item. 162 * @param data A caller specified value that is passed along to the 163 * callback function. 164 * @return 0 if the enumeration ran to completion. Otherwise, any 165 * non-zero return value from the callback is returned. 166 */ 167 int mar_enum_items(MarFile* mar, MarItemCallback callback, void* data); 168 169 /** 170 * Read from MAR item at given offset up to bufsize bytes. 171 * @param mar The MAR file to read. 172 * @param item The MAR item to read. 173 * @param offset The byte offset relative to the start of the item. 174 * @param buf A pointer to a buffer to copy the data into. 175 * @param bufsize The length of the buffer to copy the data into. 176 * @return The number of bytes written or a negative value if an 177 * error occurs. 178 */ 179 int mar_read(MarFile* mar, const MarItem* item, int offset, uint8_t* buf, 180 int bufsize); 181 182 /** 183 * Create a MAR file from a set of files. 184 * @param dest The path to the file to create. This path must be 185 * compatible with fopen. 186 * @param numfiles The number of files to store in the archive. 187 * @param files The list of null-terminated file paths. Each file 188 * path must be compatible with fopen. 189 * @param infoBlock The information to store in the product information block. 190 * @return A non-zero value if an error occurs. 191 */ 192 int mar_create(const char* dest, int numfiles, char** files, 193 struct ProductInformationBlock* infoBlock); 194 195 /** 196 * Extract a MAR file to the current working directory. 197 * @param path The path to the MAR file to extract. This path must be 198 * compatible with fopen. 199 * @return A non-zero value if an error occurs. 200 */ 201 int mar_extract(const char* path); 202 203 #define MAR_MAX_CERT_SIZE (16 * 1024) // Way larger than necessary 204 205 /* Read the entire file (not a MAR file) into a newly-allocated buffer. 206 * This function does not write to stderr. Instead, the caller should 207 * write whatever error messages it sees fit. The caller must free the returned 208 * buffer using free(). 209 * 210 * @param filePath The path to the file that should be read. 211 * @param maxSize The maximum valid file size. 212 * @param data On success, *data will point to a newly-allocated buffer 213 * with the file's contents in it. 214 * @param size On success, *size will be the size of the created buffer. 215 * 216 * @return 0 on success, -1 on error 217 */ 218 int mar_read_entire_file(const char* filePath, uint32_t maxSize, 219 /*out*/ const uint8_t** data, 220 /*out*/ uint32_t* size); 221 222 /** 223 * Verifies a MAR file by verifying each signature with the corresponding 224 * certificate. That is, the first signature will be verified using the first 225 * certificate given, the second signature will be verified using the second 226 * certificate given, etc. The signature count must exactly match the number of 227 * certificates given, and all signature verifications must succeed. 228 * We do not check that the certificate was issued by any trusted authority. 229 * We assume it to be self-signed. We do not check whether the certificate 230 * is valid for this usage. 231 * 232 * @param mar The already opened MAR file. 233 * @param certData Pointer to the first element in an array of certificate 234 * file data. 235 * @param certDataSizes Pointer to the first element in an array for size of 236 * the cert data. 237 * @param certCount The number of elements in certData and certDataSizes 238 * @return 0 on success 239 * a negative number if there was an error 240 * a positive number if the signature does not verify 241 */ 242 int mar_verify_signatures(MarFile* mar, const uint8_t* const* certData, 243 const uint32_t* certDataSizes, uint32_t certCount); 244 245 /** 246 * Reads the product info block from the MAR file's additional block section. 247 * The caller is responsible for freeing the fields in infoBlock 248 * if the return is successful. 249 * 250 * @param infoBlock Out parameter for where to store the result to 251 * @return 0 on success, -1 on failure 252 */ 253 int mar_read_product_info_block(MarFile* mar, 254 struct ProductInformationBlock* infoBlock); 255 256 #ifdef __cplusplus 257 } 258 #endif 259 260 #endif /* MAR_H__ */