fs_ptable *fs_ptable_open_filename(const char *fname, int flags) { fs_ptable *pt = calloc(1, sizeof(fs_ptable)); if (sizeof(struct ptable_header) != 512) { fs_error(LOG_CRIT, "ptable header size not 512 bytes"); return NULL; } pt->fd = open(fname, FS_O_NOATIME | flags, FS_FILE_MODE); if (pt->fd == -1) { fs_error(LOG_CRIT, "failed to open ptable %s: %s", fname, strerror(errno)); return NULL; } pt->filename = g_strdup(fname); pt->flags = flags; struct ptable_header header; lseek(pt->fd, 0, SEEK_SET); if (flags & O_TRUNC || read(pt->fd, &header, sizeof(header)) <= 0) { header.id = PTABLE_ID; header.size = 1024; header.length = 0; header.revision = PTABLE_REVISION; } if (header.id != PTABLE_ID) { fs_error(LOG_CRIT, "%s does not look like a ptable file", pt->filename); return NULL; } if (header.revision != PTABLE_REVISION) { fs_error(LOG_CRIT, "%s is wrong revision of ptable file", pt->filename); return NULL; } if (map_pt(pt, header.length, header.size)) { return NULL; } return pt; }
fs_row_id fs_ptable_new_row(fs_ptable *pt) { if (!pt->ptr) { fs_error(LOG_CRIT, "attempted to get row from unmapped ptable"); return 0; } if (pt->header->length == 0) { pt->header->length = 1; } /* we can reuse a free'd row */ if (pt->header->free_list) { fs_row_id newr = pt->header->free_list; row *r = &pt->data[newr]; pt->header->free_list = r->cont; r->cont = 0; r->data[0] = 0; r->data[1] = 0; return newr; } if (pt->header->length >= pt->header->size) { int length = pt->header->length; int size = pt->header->size; unmap_pt(pt); map_pt(pt, length, size * 2); } row *r = &pt->data[pt->header->length]; r->cont = 0; r->data[0] = 0; r->data[1] = 0; return (pt->header->length)++; }
fs_ptable *fs_ptable_open_filename(const char *fname, int flags) { fs_ptable *pt = calloc(1, sizeof(fs_ptable)); if (sizeof(struct ptable_header) != 512) { fs_error(LOG_CRIT, "ptable header size not 512 bytes"); free(pt); return NULL; } pt->fd = open(fname, FS_O_NOATIME | flags, FS_FILE_MODE); if (pt->fd == -1) { fs_error(LOG_CRIT, "failed to open ptable %s: %s", fname, strerror(errno)); free(pt); return NULL; } pt->filename = g_strdup(fname); pt->flags = flags; if (flags & O_TRUNC && ftruncate(pt->fd, sizeof(struct ptable_header))) fs_error(LOG_CRIT, "ftruncate failed: %s", strerror(errno)); int mflags = PROT_READ; if (flags & (O_RDWR | O_WRONLY)) mflags |= PROT_WRITE; if (flags & (O_TRUNC)) mflags |= PROT_WRITE; struct ptable_header *header = mmap(NULL, sizeof(struct ptable_header), mflags, MAP_FILE | MAP_SHARED, pt->fd, 0); if (header == MAP_FAILED || header == NULL) { fs_error(LOG_CRIT, "failed to mmap: %s", strerror(errno)); return NULL; } if (flags & O_TRUNC) { header->id = PTABLE_ID; header->size = 1024; header->length = 0; header->revision = PTABLE_REVISION; if (msync(header, sizeof(*header), MS_SYNC)) { fs_error(LOG_CRIT, "could not msync %s: %s", pt->filename, strerror(errno)); munmap(header, sizeof(*header)); return NULL; } } if (header->id != PTABLE_ID) { fs_error(LOG_CRIT, "%s does not look like a ptable file", pt->filename); munmap(header, sizeof(*header)); return NULL; } if (header->revision != PTABLE_REVISION) { fs_error(LOG_CRIT, "%s is wrong revision of ptable file", pt->filename); munmap(header, sizeof(*header)); return NULL; } if (map_pt(pt, header->length, header->size)) return NULL; if (munmap(header, sizeof(*header))) fs_error(LOG_ERR, "could not unmap %s: %s", pt->filename, strerror(errno)); return pt; }