diff options
author | Zhihao Cheng <chengzhihao1@huawei.com> | 2024-11-11 17:08:12 +0800 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2024-11-11 10:32:46 +0100 |
commit | df5d5489aed7ae9de007776e19350bd5aebbfea2 (patch) | |
tree | e22d46cedff685cc8fa66bb695d14c5571bdfe45 /ubifs-utils/libubifs/journal.c | |
parent | 7e6ae3a8dcbedf0e65c091e985aff56f293cf8ec (diff) |
ubifs-utils: libubifs: Support some file operations
Add some file operations, such as ubifs_lookup, ubifs_mkdir, etc., this
is a preparation for recovering disconnected files or root dir in fsck.
File writing operations are based on the journal subsystem, generated
dirty data depends on a new commit in subsequent steps to update disk
content.
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'ubifs-utils/libubifs/journal.c')
-rw-r--r-- | ubifs-utils/libubifs/journal.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/ubifs-utils/libubifs/journal.c b/ubifs-utils/libubifs/journal.c index d3fdb76..e78ea14 100644 --- a/ubifs-utils/libubifs/journal.c +++ b/ubifs-utils/libubifs/journal.c @@ -47,9 +47,11 @@ */ #include "bitops.h" +#include "kmem.h" #include "ubifs.h" #include "defs.h" #include "debug.h" +#include "key.h" #include "misc.h" /** @@ -437,3 +439,195 @@ static void set_dent_cookie(struct ubifs_info *c, struct ubifs_dent_node *dent) else dent->cookie = 0; } + +/** + * pack_inode - pack an ubifs inode node. + * @c: UBIFS file-system description object + * @ino: buffer in which to pack inode node + * @ui: ubifs inode to pack + * @last: indicates the last node of the group + */ +static void pack_inode(struct ubifs_info *c, struct ubifs_ino_node *ino, + const struct ubifs_inode *ui, int last) +{ + const struct inode *inode = &ui->vfs_inode; + int data_len = 0, last_reference = !inode->nlink; + + ino->ch.node_type = UBIFS_INO_NODE; + ino_key_init_flash(c, &ino->key, inode->inum); + ino->creat_sqnum = cpu_to_le64(ui->creat_sqnum); + ino->atime_sec = cpu_to_le64(inode->atime_sec); + ino->atime_nsec = cpu_to_le32(inode->atime_nsec); + ino->ctime_sec = cpu_to_le64(inode->ctime_sec); + ino->ctime_nsec = cpu_to_le32(inode->ctime_nsec); + ino->mtime_sec = cpu_to_le64(inode->mtime_sec); + ino->mtime_nsec = cpu_to_le32(inode->mtime_nsec); + ino->uid = cpu_to_le32(inode->uid); + ino->gid = cpu_to_le32(inode->gid); + ino->mode = cpu_to_le32(inode->mode); + ino->flags = cpu_to_le32(ui->flags); + ino->size = cpu_to_le64(ui->ui_size); + ino->nlink = cpu_to_le32(inode->nlink); + ino->compr_type = cpu_to_le16(ui->compr_type); + ino->data_len = cpu_to_le32(ui->data_len); + ino->xattr_cnt = cpu_to_le32(ui->xattr_cnt); + ino->xattr_size = cpu_to_le32(ui->xattr_size); + ino->xattr_names = cpu_to_le32(ui->xattr_names); + zero_ino_node_unused(ino); + + /* + * Drop the attached data if this is a deletion inode, the data is not + * needed anymore. + */ + if (!last_reference) { + memcpy(ino->data, ui->data, ui->data_len); + data_len = ui->data_len; + } + + ubifs_prep_grp_node(c, ino, UBIFS_INO_NODE_SZ + data_len, last); +} + +/** + * ubifs_jnl_update_file - update file. + * @c: UBIFS file-system description object + * @dir_ui: parent ubifs inode + * @nm: directory entry name + * @ui: ubifs inode to update + * + * This function updates an file by writing a directory entry node, the inode + * node itself, and the parent directory inode node to the journal. If the + * @dir_ui and @nm are NULL, only update @ui. + * + * Returns zero on success. In case of failure, a negative error code is + * returned. + */ +int ubifs_jnl_update_file(struct ubifs_info *c, + const struct ubifs_inode *dir_ui, + const struct fscrypt_name *nm, + const struct ubifs_inode *ui) +{ + const struct inode *dir = NULL, *inode = &ui->vfs_inode; + int err, dlen, ilen, len, lnum, ino_offs, dent_offs, dir_ilen; + int aligned_dlen, aligned_ilen; + struct ubifs_dent_node *dent; + struct ubifs_ino_node *ino; + union ubifs_key dent_key, ino_key; + u8 hash_dent[UBIFS_HASH_ARR_SZ]; + u8 hash_ino[UBIFS_HASH_ARR_SZ]; + u8 hash_ino_dir[UBIFS_HASH_ARR_SZ]; + + ubifs_assert(c, (!nm && !dir_ui) || (nm && dir_ui)); + ubifs_assert(c, inode->nlink != 0); + + ilen = UBIFS_INO_NODE_SZ + ui->data_len; + + if (nm) + dlen = UBIFS_DENT_NODE_SZ + fname_len(nm) + 1; + else + dlen = 0; + + if (dir_ui) { + dir = &dir_ui->vfs_inode; + ubifs_assert(c, dir->nlink != 0); + dir_ilen = UBIFS_INO_NODE_SZ + dir_ui->data_len; + } else + dir_ilen = 0; + + aligned_dlen = ALIGN(dlen, 8); + aligned_ilen = ALIGN(ilen, 8); + len = aligned_dlen + aligned_ilen + dir_ilen; + if (ubifs_authenticated(c)) + len += ALIGN(dir_ilen, 8) + ubifs_auth_node_sz(c); + + dent = kzalloc(len, GFP_NOFS); + if (!dent) + return -ENOMEM; + + /* Make reservation before allocating sequence numbers */ + err = make_reservation(c, BASEHD, len); + if (err) + goto out_free; + + if (nm) { + dent->ch.node_type = UBIFS_DENT_NODE; + dent_key_init(c, &dent_key, dir->inum, nm); + + key_write(c, &dent_key, dent->key); + dent->inum = cpu_to_le64(inode->inum); + dent->type = ubifs_get_dent_type(inode->mode); + dent->nlen = cpu_to_le16(fname_len(nm)); + memcpy(dent->name, fname_name(nm), fname_len(nm)); + dent->name[fname_len(nm)] = '\0'; + set_dent_cookie(c, dent); + + zero_dent_node_unused(dent); + ubifs_prep_grp_node(c, dent, dlen, 0); + err = ubifs_node_calc_hash(c, dent, hash_dent); + if (err) + goto out_release; + } + + ino = (void *)dent + aligned_dlen; + pack_inode(c, ino, ui, dir_ui == NULL ? 1 : 0); + err = ubifs_node_calc_hash(c, ino, hash_ino); + if (err) + goto out_release; + + if (dir_ui) { + ino = (void *)ino + aligned_ilen; + pack_inode(c, ino, dir_ui, 1); + err = ubifs_node_calc_hash(c, ino, hash_ino_dir); + if (err) + goto out_release; + } + + err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, 0); + if (err) + goto out_release; + release_head(c, BASEHD); + kfree(dent); + ubifs_add_auth_dirt(c, lnum); + + if (nm) { + err = ubifs_tnc_add_nm(c, &dent_key, lnum, dent_offs, dlen, + hash_dent, nm); + if (err) { + ubifs_assert(c, !get_failure_reason_callback(c)); + goto out_ro; + } + } + + ino_key_init(c, &ino_key, inode->inum); + ino_offs = dent_offs + aligned_dlen; + err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ilen, hash_ino); + if (err) { + ubifs_assert(c, !get_failure_reason_callback(c)); + goto out_ro; + } + + if (dir_ui) { + ino_key_init(c, &ino_key, dir->inum); + ino_offs += aligned_ilen; + err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, dir_ilen, + hash_ino_dir); + if (err) { + ubifs_assert(c, !get_failure_reason_callback(c)); + goto out_ro; + } + } + + finish_reservation(c); + return 0; + +out_free: + kfree(dent); + return err; + +out_release: + release_head(c, BASEHD); + kfree(dent); +out_ro: + ubifs_ro_mode(c, err); + finish_reservation(c); + return err; +} |