blob: 7a9bf83f219c2c03fead7e446bf4087170e523ed [file] [log] [blame] [edit]
/*
* Copyright 2016, NICTA
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(NICTA_GPL)
*/
#include <bilbyfs.h>
static u8 inode_mode_to_dent_type(umode_t mode)
{
switch (mode & S_IFMT) {
case S_IFREG: return BILBYFS_ITYPE_REG;
case S_IFDIR: return BILBYFS_ITYPE_DIR;
case S_IFLNK: return BILBYFS_ITYPE_LNK;
case S_IFSOCK: return BILBYFS_ITYPE_SOCK;
case S_IFIFO: return BILBYFS_ITYPE_FIFO;
case S_IFBLK: return BILBYFS_ITYPE_BLK;
case S_IFCHR: return BILBYFS_ITYPE_CHR;
default: bilbyfs_assert(0);
}
return 0;
}
int check_obj_header(void *obj, int max_obj_sz)
{
struct obj_ch *ch = obj;
u32 offs;
u32 crc;
if (max_obj_sz < BILBYFS_CH_SZ)
return -ENOENT;
if (le32_to_cpu(ch->magic) != BILBYFS_OBJ_MAGIC)
return -ENOENT;
if (le32_to_cpu(ch->len) < BILBYFS_CH_SZ ||
le32_to_cpu(ch->len) > max_obj_sz) {
bilbyfs_err("Invalid object size (%d vs %d)", le32_to_cpu(ch->len), max_obj_sz);
return -EINVAL;
}
offs = offsetof(struct obj_ch, crc) + sizeof(ch->crc);
crc = crc32(BILBYFS_CRC32_INIT, obj + offs, le32_to_cpu(ch->len) - offs);
if (crc != le32_to_cpu(ch->crc)) {
bilbyfs_err("Invalid CRC32 for object %x != %x, obj->type=%d\n", crc, le32_to_cpu(ch->crc), ch->type);
return -EINVAL;
}
/* FIXME: More sanity checking?? */
return 0;
}
void pack_obj_header(void *obj, u64 sqnum, u8 trans_pos)
{
struct obj_ch *ch = obj;
uint32_t crc;
int offs;
bilbyfs_assert(ch->type < BILBYFS_OBJ_TYPES_CNT);
ch->magic = cpu_to_le32(BILBYFS_OBJ_MAGIC);
ch->sqnum = cpu_to_le64(sqnum);
ch->trans = trans_pos;
zero_obj_ch_unused(ch);
/* we CRC right after the field crc to the end of the object */
offs = offsetof(struct obj_ch, crc) + sizeof(ch->crc);
crc = crc32(BILBYFS_CRC32_INIT, obj + offs, le32_to_cpu(ch->len) - offs);
ch->crc = cpu_to_le32(crc);
}
__le32 len_to_le32(int len)
{
bilbyfs_assert(len >= BILBYFS_CH_SZ);
return cpu_to_le32(ALIGN(len, BILBYFS_OBJ_PADDING));
}
void pack_obj_inode(struct obj_inode *ino, struct inode *inode)
{
struct bilbyfs_inode *binode = inode_to_binode(inode);
ino->ch.type = BILBYFS_INODE_OBJ;
ino->ch.len = len_to_le32(BILBYFS_INODE_SZ);
ino->id = cpu_to_le64(inode_id_init(inode->i_ino));
ino->creat_sqnum = cpu_to_le64(binode->creat_sqnum);
ino->size = cpu_to_le64(inode->i_size);
ino->atime_sec = cpu_to_le64(inode->i_atime.tv_sec);
ino->ctime_sec = cpu_to_le64(inode->i_ctime.tv_sec);
ino->mtime_sec = cpu_to_le64(inode->i_mtime.tv_sec);
ino->nlink = cpu_to_le32(inode->i_nlink);
ino->uid = cpu_to_le32(i_uid_read(inode));
ino->gid = cpu_to_le32(i_gid_read(inode));
ino->mode = cpu_to_le32(inode->i_mode);
ino->flags = cpu_to_le32(binode->flags);
zero_obj_inode_unused(ino);
}
void pack_obj_dentarr(struct obj_dentarr *dentarr, obj_id id,
int nbdentry, int size)
{
dentarr->ch.type = BILBYFS_DENTARR_OBJ;
dentarr->ch.len = len_to_le32(size);
dentarr->id = cpu_to_le64(id);
dentarr->nb_dentry = cpu_to_le32(nbdentry);
dentarr->size = cpu_to_le32(size);
zero_obj_dentarr_unused(dentarr);
}
void pack_obj_data(struct obj_data *odata, obj_id id, int sz_data,
const void *data)
{
odata->ch.type = BILBYFS_DATA_OBJ;
odata->ch.len = len_to_le32(BILBYFS_DATA_SZ + sz_data);
odata->id = cpu_to_le64(id);
odata->size = cpu_to_le32(sz_data);
memcpy(odata->data, data, sz_data);
zero_obj_data_unused(odata);
}
void pack_obj_dentry(struct obj_dentry *de, struct inode *inode,
const char *name)
{
de->ino = cpu_to_le32(inode->i_ino);
de->type = inode_mode_to_dent_type(inode->i_mode);
/* The dentry.nlen field does not include the \0 */
de->nlen = cpu_to_le16(strlen(name));
strcpy(de->name, name);
zero_obj_dentry_unused(de);
}
void pack_obj_pad(struct obj_ch *pad, int pad_sz)
{
pad->type = BILBYFS_PAD_OBJ;
pad->len = len_to_le32(pad_sz);
memset(pad + 1, BILBYFS_PAD_BYTE, pad_sz - BILBYFS_CH_SZ);
}
void unpack_obj_inode(struct inode *inode, struct obj_inode *ino)
{
struct bilbyfs_inode *binode = inode_to_binode(inode);
inode->i_flags |= (S_NOCMTIME | S_NOATIME);
set_nlink(inode, le32_to_cpu(ino->nlink));
i_uid_write(inode, le32_to_cpu(ino->uid));
i_gid_write(inode, le32_to_cpu(ino->gid));
inode->i_atime.tv_sec = (int64_t)le64_to_cpu(ino->atime_sec);
inode->i_mtime.tv_sec = (int64_t)le64_to_cpu(ino->mtime_sec);
inode->i_ctime.tv_sec = (int64_t)le64_to_cpu(ino->ctime_sec);
inode->i_mode = le32_to_cpu(ino->mode);
inode->i_size = le64_to_cpu(ino->size);
binode->flags = le32_to_cpu(ino->flags);
binode->creat_sqnum = le64_to_cpu(ino->creat_sqnum);
}
void pack_obj_super(struct obj_super *super, const struct bilbyfs_super *bsuper)
{
super->ch.type = BILBYFS_SUP_OBJ;
super->ch.len = len_to_le32(BILBYFS_SUPER_SZ);
super->flags = cpu_to_le32(bsuper->flags);
super->leb_cnt = cpu_to_le32(bsuper->leb_cnt);
super->nb_reserved_del = cpu_to_le32(bsuper->nb_reserved_del);
super->nb_reserved_gc = cpu_to_le32(bsuper->nb_reserved_gc);
super->leb_size = cpu_to_le32(bsuper->leb_size);
super->log_head_leb = cpu_to_le32(bsuper->log_lnum);
super->log_head_offs = cpu_to_le32(bsuper->log_offs);
super->lowest_sqnum = cpu_to_le64(bsuper->lowest_sqnum);
zero_obj_super_unused(super);
}
void unpack_obj_super(struct bilbyfs_super *bsuper, struct obj_super *super)
{
bsuper->sqnum = le64_to_cpu(super->ch.sqnum);
bsuper->flags = le32_to_cpu(super->flags);
bsuper->leb_cnt = le32_to_cpu(super->leb_cnt);
bsuper->nb_reserved_del = le32_to_cpu(super->nb_reserved_del);
bsuper->nb_reserved_gc = le32_to_cpu(super->nb_reserved_gc);
bsuper->leb_size = le32_to_cpu(super->leb_size);
bsuper->log_lnum = le32_to_cpu(super->log_head_leb);
bsuper->log_offs = le32_to_cpu(super->log_head_offs);
bsuper->lowest_sqnum = le64_to_cpu(super->lowest_sqnum);
bsuper->last_inum = le64_to_cpu(super->last_inum);
}
void pack_obj_del(void *obj, obj_id id)
{
struct obj_del *del = (struct obj_del *) obj;
del->ch.type = BILBYFS_DEL_OBJ;
del->ch.len = len_to_le32(BILBYFS_DEL_SZ);
del->id = cpu_to_le64(id);
zero_obj_del_unused(del);
}
void pack_obj_sum(struct obj_sum *sum, u32 offs)
{
u32 len = obj_sum_size(sum);
sum->ch.type = BILBYFS_SUM_OBJ;
sum->ch.len = len_to_le32(len);
memset((void *)sum + len, BILBYFS_PAD_BYTE, le32_to_cpu(sum->ch.len) - len);
*obj_sum_offs(sum) = cpu_to_le32(offs);
zero_obj_sum_unused(sum);
}