blob: 285e7ca563b152f75462dc0fa3a3fd1ef7c95e03 [file] [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>
struct obj_dentry *dentarr_first_dentry(struct obj_dentarr *dentarr)
{
if (le32_to_cpu(dentarr->nb_dentry) == 0)
return NULL;
return (void *)dentarr + BILBYFS_DENTARR_SZ;
}
static struct obj_dentry *dentarr_end(struct obj_dentarr *dentarr)
{
return ((void *)dentarr + obj_dentarr_size(dentarr));
}
struct obj_dentry *dentarr_next_dentry(struct obj_dentarr *dentarr,
struct obj_dentry *dentry)
{
struct obj_dentry *next_de;
next_de = (void *) dentry + obj_dentry_size(dentry);
if (next_de == dentarr_end(dentarr))
return NULL;
return next_de;
}
int dentarr_check_empty(struct bilbyfs_info *bi, struct obj_dentarr *dentarr)
{
return (!dentarr_first_dentry(dentarr) ? 0 : -ENOTEMPTY);
}
int dentarr_add_dentry(struct bilbyfs_info *bi, struct obj_dentarr *dentarr,
struct inode *inode, const char *name)
{
struct obj_dentry *de;
int sz_change;
int nb_dentry;
obj_id id;
int len;
sz_change = obj_dentry_size_from_nm(name);
id = le64_to_cpu(dentarr->id);
nb_dentry = le32_to_cpu(dentarr->nb_dentry) + 1;
len = obj_dentarr_size(dentarr);
de = dentarr_end(dentarr);
pack_obj_dentry(de, inode, name);
pack_obj_dentarr(dentarr, id, nb_dentry, len + sz_change);
return sz_change;
}
int dentarr_del_dentry(struct bilbyfs_info *bi, struct obj_dentarr *dentarr,
const char *name)
{
struct obj_dentarr *copy_dentarr;
struct obj_dentry *de;
struct obj_dentry *copy_de;
int sz_change;
int nb_dentry;
obj_id id;
int delen;
int len;
sz_change = obj_dentry_size_from_nm(name);
id = le64_to_cpu(dentarr->id);
nb_dentry = le32_to_cpu(dentarr->nb_dentry);
len = obj_dentarr_size(dentarr);
copy_dentarr = kmalloc(len);
if (!copy_dentarr)
return -ENOMEM;
memcpy(copy_dentarr, dentarr, len);
copy_de = dentarr_lookup_nm(bi, copy_dentarr, name);
de = dentarr_lookup_nm(bi, dentarr, name);
if (nb_dentry <= 0 || !copy_de) {
kfree(copy_dentarr);
return 0;
}
copy_de = dentarr_next_dentry(copy_dentarr, copy_de);
while (copy_de) {
delen = obj_dentry_size(de);
memcpy(de, copy_de, delen);
de = (void *) de + delen;
copy_de = dentarr_next_dentry(copy_dentarr, copy_de);
}
kfree(copy_dentarr);
nb_dentry--;
if (nb_dentry == 0) {
memset(dentarr, 0, len);
pack_obj_del(dentarr, id);
} else {
pack_obj_dentarr(dentarr, id, nb_dentry, len - sz_change);
}
return sz_change;
}
struct obj_dentry *dentarr_lookup_nm(struct bilbyfs_info *bi,
struct obj_dentarr *dentarr,
const char *name)
{
struct obj_dentry *de;
de = dentarr_first_dentry(dentarr);
while (de) {
if (!strcmp(de->name, name))
return de;
de = dentarr_next_dentry(dentarr, de);
}
return ERR_PTR(-ENOENT);
}
struct obj_dentarr *dentarr_read(struct bilbyfs_info *bi, obj_id id)
{
struct obj_dentarr *dentarr;
int err;
/* We need to allocate enough to be able to add an entry */
int size = BILBYFS_MAX_DENTARR_SZ;
bilbyfs_debug("[S] dentarr_read(0x%llx)\n", id);
dentarr = kmalloc(size);
if (!dentarr)
return ERR_PTR(-ENOMEM);
err = ostore_read_obj(bi, id, dentarr, size);
if (err) {
kfree(dentarr);
return ERR_PTR(err);
}
/* Sanity checking */
if (le32_to_cpu(dentarr->nb_dentry) > BILBYFS_MAX_DENTARR_ENTRIES ||
le32_to_cpu(dentarr->size) > BILBYFS_MAX_DENTARR_SZ) {
kfree(dentarr);
bilbyfs_err("dentarr_read: lookup err nb_dentry=%d, size=%d\n", le32_to_cpu(dentarr->nb_dentry), le32_to_cpu(dentarr->size));
return ERR_PTR(-EINVAL);
}
return dentarr;
}
struct obj_dentarr *dentarr_read_or_create(struct bilbyfs_info *bi, obj_id id)
{
struct obj_dentarr *dentarr;
dentarr = dentarr_read(bi, id);
if (IS_ERR(dentarr)) {
if (PTR_ERR(dentarr) != -ENOENT)
return dentarr;
dentarr = kmalloc(BILBYFS_DENTARR_SZ + BILBYFS_MAX_DENTRY_SZ);
if (!dentarr)
return ERR_PTR(-ENOMEM);
pack_obj_dentarr(dentarr, id, 0, BILBYFS_DENTARR_SZ);
}
return dentarr;
}