void exfat_put_node(struct exfat* ef, struct exfat_node* node) { if (--node->references < 0) { char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1]; exfat_get_name(node, buffer, sizeof(buffer) - 1); exfat_bug("reference counter of `%s' is below zero", buffer); } if (node->references == 0) { /* FIXME handle I/O error */ if (exfat_flush_node(ef, node) != 0) exfat_bug("node flush failed"); if (node->flags & EXFAT_ATTRIB_UNLINKED) { /* free all clusters and node structure itself */ exfat_truncate(ef, node, 0, true); free(node); } /* FIXME handle I/O error */ if (exfat_flush(ef) != 0) exfat_bug("flush failed"); } }
static int fuse_exfat_fsync(const char* path, int datasync, struct fuse_file_info *fi) { int rc; exfat_debug("[%s] %s", __func__, path); rc = exfat_flush(&ef); if (rc != 0) return rc; return exfat_fsync(ef.dev); }
void exfat_unmount(struct exfat* ef) { exfat_flush_nodes(ef); /* ignore return code */ exfat_flush(ef); /* ignore return code */ exfat_put_node(ef, ef->root); exfat_reset_cache(ef); free(ef->root); ef->root = NULL; finalize_super_block(ef); exfat_close(ef->dev); /* close descriptor immediately after fsync */ ef->dev = NULL; free(ef->zero_cluster); ef->zero_cluster = NULL; free(ef->cmap.chunk); ef->cmap.chunk = NULL; free(ef->sb); ef->sb = NULL; free(ef->upcase); ef->upcase = NULL; ef->upcase_chars = 0; }
int exfat_flush_node(struct exfat* ef, struct exfat_node* node) { cluster_t cluster; off_t offset; off_t meta1_offset, meta2_offset; struct exfat_entry_meta1 meta1; struct exfat_entry_meta2 meta2; if (!(node->flags & EXFAT_ATTRIB_DIRTY)) return 0; /* no need to flush */ if (ef->ro) exfat_bug("unable to flush node to read-only FS"); if (node->parent == NULL) return 0; /* do not flush unlinked node */ cluster = node->entry_cluster; offset = node->entry_offset; meta1_offset = co2o(ef, cluster, offset); if (!next_entry(ef, node->parent, &cluster, &offset)) return -EIO; meta2_offset = co2o(ef, cluster, offset); if (exfat_pread(ef->dev, &meta1, sizeof(meta1), meta1_offset) < 0) { exfat_error("failed to read meta1 entry on flush"); return -EIO; } if (meta1.type != EXFAT_ENTRY_FILE) exfat_bug("invalid type of meta1: 0x%hhx", meta1.type); meta1.attrib = cpu_to_le16(node->flags); exfat_unix2exfat(node->mtime, &meta1.mdate, &meta1.mtime, &meta1.mtime_cs); exfat_unix2exfat(node->atime, &meta1.adate, &meta1.atime, NULL); if (exfat_pread(ef->dev, &meta2, sizeof(meta2), meta2_offset) < 0) { exfat_error("failed to read meta2 entry on flush"); return -EIO; } if (meta2.type != EXFAT_ENTRY_FILE_INFO) exfat_bug("invalid type of meta2: 0x%hhx", meta2.type); meta2.size = meta2.valid_size = cpu_to_le64(node->size); meta2.start_cluster = cpu_to_le32(node->start_cluster); meta2.flags = EXFAT_FLAG_ALWAYS1; /* empty files must not be marked as contiguous */ if (node->size != 0 && IS_CONTIGUOUS(*node)) meta2.flags |= EXFAT_FLAG_CONTIGUOUS; /* name hash remains unchanged, no need to recalculate it */ meta1.checksum = exfat_calc_checksum(&meta1, &meta2, node->name); if (exfat_pwrite(ef->dev, &meta1, sizeof(meta1), meta1_offset) < 0) { exfat_error("failed to write meta1 entry on flush"); return -EIO; } if (exfat_pwrite(ef->dev, &meta2, sizeof(meta2), meta2_offset) < 0) { exfat_error("failed to write meta2 entry on flush"); return -EIO; } node->flags &= ~EXFAT_ATTRIB_DIRTY; return exfat_flush(ef); }