int journal_close(journal_t *journal) { /* Check journal. */ if (journal == NULL) { return KNOT_EINVAL; } /* Check if lazy. */ int ret = KNOT_EOK; if (journal->fd < 0) { free(journal->path); } else { /* Recalculate CRC. */ ret = journal_update_crc(journal->fd); /* Unlock journal file. */ journal->fl.l_type = F_UNLCK; fcntl(journal->fd, F_SETLK, &journal->fl); dbg_journal("journal: unlocked journal %p\n", journal); /* Close file. */ close(journal->fd); } dbg_journal("journal: closed journal %p\n", journal); /* Free allocated resources. */ free(journal); return ret; }
/*! \brief Close journal file. */ static int journal_close_file(journal_t *journal) { /* Check journal. */ if (journal == NULL) { return KNOT_EINVAL; } /* Recalculate CRC. */ int ret = journal_update_crc(journal->fd); /* Close file. */ close(journal->fd); journal->fd = -1; /* Free nodes. */ free(journal->nodes); journal->nodes = NULL; dbg_journal("journal: closed journal %p\n", journal); return ret; }
int journal_create(const char *fn, uint16_t max_nodes) { if (fn == NULL) { return KNOT_EINVAL; } /* File lock. */ struct flock fl; memset(&fl, 0, sizeof(struct flock)); fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = getpid(); /* Create journal file. */ int fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (fd < 0) { dbg_journal("journal: failed to create file '%s'\n", fn); return knot_map_errno(errno); } /* Lock. */ fcntl(fd, F_SETLKW, &fl); fl.l_type = F_UNLCK; /* Create journal header. */ dbg_journal("journal: creating header\n"); const char magic[MAGIC_LENGTH] = JOURNAL_MAGIC; if (!sfwrite(magic, MAGIC_LENGTH, fd)) { fcntl(fd, F_SETLK, &fl); close(fd); remove(fn); return KNOT_ERROR; } crc_t crc = crc_init(); if (!sfwrite(&crc, sizeof(crc_t), fd)) { fcntl(fd, F_SETLK, &fl); close(fd); remove(fn); return KNOT_ERROR; } if (!sfwrite(&max_nodes, sizeof(uint16_t), fd)) { fcntl(fd, F_SETLK, &fl); close(fd); remove(fn); return KNOT_ERROR; } /* Create node queue head + tail. * qhead points to least recent node * qtail points to next free node * qhead == qtail means empty queue */ uint16_t zval = 0; if (!sfwrite(&zval, sizeof(uint16_t), fd)) { fcntl(fd, F_SETLK, &fl); close(fd); remove(fn); return KNOT_ERROR; } if (!sfwrite(&zval, sizeof(uint16_t), fd)) { fcntl(fd, F_SETLK, &fl); close(fd); remove(fn); return KNOT_ERROR; } dbg_journal_verb("journal: creating free segment descriptor\n"); /* Create free segment descriptor. */ journal_node_t jn; memset(&jn, 0, sizeof(journal_node_t)); jn.id = 0; jn.flags = JOURNAL_VALID; jn.pos = JOURNAL_HSIZE + (max_nodes + 1) * sizeof(journal_node_t); jn.len = 0; if (!sfwrite(&jn, sizeof(journal_node_t), fd)) { fcntl(fd, F_SETLK, &fl); close(fd); remove(fn); return KNOT_ERROR; } /* Create nodes. */ dbg_journal("journal: creating node table, size=%u\n", max_nodes); memset(&jn, 0, sizeof(journal_node_t)); for(uint16_t i = 0; i < max_nodes; ++i) { if (!sfwrite(&jn, sizeof(journal_node_t), fd)) { fcntl(fd, F_SETLK, &fl); close(fd); if (remove(fn) < 0) { dbg_journal("journal: failed to remove journal file after error\n"); } return KNOT_ERROR; } } /* Recalculate CRC. */ if (journal_update_crc(fd) != KNOT_EOK) { fcntl(fd, F_SETLK, &fl); close(fd); if(remove(fn) < 0) { dbg_journal("journal: failed to remove journal file after error\n"); } return KNOT_ERROR; } /* Unlock and close. */ fcntl(fd, F_SETLK, &fl); close(fd); /* Journal file created. */ dbg_journal("journal: file '%s' initialized\n", fn); return KNOT_EOK; }