/*}}}*/ void write_database(struct database *db, char *filename, int do_integrity_checks)/*{{{*/ { int file_len; int fd; char *data, *cdata; unsigned int *uidata; struct write_map map; if (do_integrity_checks) { check_database_integrity(db); } if (!verify_mbox_size_constraints(db)) { unlock_and_exit(1); } /* Work out mappings */ compute_mapping(db, &map); file_len = char_length(db) + (4 * map.beyond_last_ui_offset); create_rw_mapping(filename, file_len, &fd, &data); uidata = (unsigned int *) data; /* align(int) < align(page)! */ cdata = data + (4 * map.beyond_last_ui_offset); write_header(data, uidata, db, &map); cdata = write_type_and_flag_table(db, uidata, data, cdata); cdata = write_messages(db, &map, uidata, data, cdata); cdata = write_mbox_headers(db, &map, uidata, data, cdata); cdata = write_mbox_checksums(db, &map, uidata, data, cdata); cdata = write_toktable(db->to, &map.to, uidata, data, cdata, "To"); cdata = write_toktable(db->cc, &map.cc, uidata, data, cdata, "Cc"); cdata = write_toktable(db->from, &map.from, uidata, data, cdata, "From"); cdata = write_toktable(db->subject, &map.subject, uidata, data, cdata, "Subject"); cdata = write_toktable(db->body, &map.body, uidata, data, cdata, "Body"); cdata = write_toktable(db->attachment_name, &map.attachment_name, uidata, data, cdata, "Attachment Name"); cdata = write_toktable2(db->msg_ids, &map.msg_ids, uidata, data, cdata, "(Threading)"); /* Write data */ /* Unmap / close file */ if (munmap(data, file_len) < 0) { report_error("munmap", filename); unlock_and_exit(2); } if (fsync(fd) < 0) { report_error("fsync", filename); unlock_and_exit(2); } if (close(fd) < 0) { report_error("close", filename); unlock_and_exit(2); } }
static char *get_database_path(int traverse_up)/*{{{*/ { char *env_var; env_var = getenv("TDL_DATABASE"); if (env_var) { return env_var; } else { int at_root, orig_size, size, dbname_len, found, stat_result; char *orig_cwd, *cwd, *result, *filename; struct stat statbuf; dbname_len = strlen(DBNAME); size = 16; orig_size = 16; found = 0; at_root = 0; cwd = new_array(char, size); orig_cwd = new_array(char, orig_size); do { result = getcwd(orig_cwd, orig_size); if (!result) { if (errno == ERANGE) { orig_size <<= 1; orig_cwd = grow_array(char, orig_size, orig_cwd); } else { fprintf(stderr, "Unexpected error reading current directory\n"); unlock_and_exit(1); } } } while (!result);
/*}}}*/ void close_db(struct read_db *x)/*{{{*/ { free_toktable_db(&x->to); free_toktable_db(&x->cc); free_toktable_db(&x->from); free_toktable_db(&x->subject); free_toktable_db(&x->body); free_toktable_db(&x->attachment_name); free_toktable2_db(&x->msg_ids); if (munmap(x->data, x->len) < 0) { perror("munmap"); unlock_and_exit(2); } free(x); return; }
static void create_rw_mapping(char *filename, size_t len, int *out_fd, char **out_data)/*{{{*/ { int fd; char *data; struct stat sb; fd = open(filename, O_RDWR | O_CREAT, 0600); if (fd < 0) { report_error("open", filename); unlock_and_exit(2); } if (fstat(fd, &sb) < 0) { report_error("stat", filename); unlock_and_exit(2); } if (sb.st_size < len) { /* Extend */ if (lseek(fd, len - 1, SEEK_SET) < 0) { report_error("lseek", filename); unlock_and_exit(2); } if (write(fd, "\000", 1) < 0) { report_error("write", filename); unlock_and_exit(2); } } else if (sb.st_size > len) { /* Truncate */ if (ftruncate(fd, len) < 0) { report_error("ftruncate", filename); unlock_and_exit(2); } } else { /* Exactly the right length already - nothing to do! */ } data = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { report_error("writer:mmap", filename); unlock_and_exit(2); } *out_data = data; *out_fd = fd; }
/*}}}*/ struct read_db *open_db(char *filename)/*{{{*/ { int fd, len; char *data; struct stat sb; struct read_db *result; unsigned int *uidata; unsigned char *ucdata; fd = open(filename, O_RDONLY); if (fd < 0) { report_error("open", filename); unlock_and_exit (2); } if (fstat(fd, &sb) < 0) { report_error("stat", filename); unlock_and_exit(2); } len = sb.st_size; data = (char *) mmap(0, len, PROT_READ, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { report_error("reader:mmap", filename); unlock_and_exit(2); } if (!data) { /* Empty file opened => database corrupt for sure */ if (close(fd) < 0) { report_error("close", filename); unlock_and_exit(2); } return NULL; } if (close(fd) < 0) { report_error("close", filename); unlock_and_exit(2); } result = new(struct read_db); uidata = (unsigned int *) data; /* alignment is assured */ ucdata = (unsigned char *) data; result->len = len; result->data = data; /*{{{ Magic number check */ if (ucdata[0] == HEADER_MAGIC0 || ucdata[1] == HEADER_MAGIC1 || ucdata[2] == HEADER_MAGIC2) { if (ucdata[3] != HEADER_MAGIC3) { fprintf(stderr, "Another version of this program produced the existing database! Please rebuild.\n"); unlock_and_exit(2); } } else { fprintf(stderr, "The existing database wasn't produced by this program! Please rebuild.\n"); unlock_and_exit(2); } /*}}}*/ /* {{{ Endianness check */ if (uidata[UI_ENDIAN] == 0x11223344) { fprintf(stderr, "The endianness of the database is reversed for this machine\n"); unlock_and_exit(2); } else if (uidata[UI_ENDIAN] != 0x44332211) { fprintf(stderr, "The endianness of this machine is strange (or database is corrupt)\n"); unlock_and_exit(2); } /* }}} */ /* Now build tables of where things are in the file */ result->n_msgs = uidata[UI_N_MSGS]; result->msg_type_and_flags = ucdata + uidata[UI_MSG_TYPE_AND_FLAGS]; result->path_offsets = uidata + uidata[UI_MSG_CDATA]; result->mtime_table = uidata + uidata[UI_MSG_MTIME]; result->size_table = uidata + uidata[UI_MSG_SIZE]; result->date_table = uidata + uidata[UI_MSG_DATE]; result->tid_table = uidata + uidata[UI_MSG_TID]; result->n_mboxen = uidata[UI_MBOX_N]; result->mbox_paths_table = uidata + uidata[UI_MBOX_PATHS]; result->mbox_entries_table = uidata + uidata[UI_MBOX_ENTRIES]; result->mbox_mtime_table = uidata + uidata[UI_MBOX_MTIME]; result->mbox_size_table = uidata + uidata[UI_MBOX_SIZE]; result->mbox_checksum_table = uidata + uidata[UI_MBOX_CKSUM]; result->hash_key = uidata[UI_HASH_KEY]; read_toktable_db(data, &result->to, UI_TO_BASE, uidata); read_toktable_db(data, &result->cc, UI_CC_BASE, uidata); read_toktable_db(data, &result->from, UI_FROM_BASE, uidata); read_toktable_db(data, &result->subject, UI_SUBJECT_BASE, uidata); read_toktable_db(data, &result->body, UI_BODY_BASE, uidata); read_toktable_db(data, &result->attachment_name, UI_ATTACHMENT_NAME_BASE, uidata); read_toktable2_db(data, &result->msg_ids, UI_MSGID_BASE, uidata); return result; }