#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <asm/byteorder.h>
#include "common.h"
#include "quotaio_tree.h"
typedef char *dqbuf_t;
-#define getdqbuf() smalloc(QT_BLKSIZE)
-#define freedqbuf(buf) free(buf)
+#define freedqbuf(buf) ext2fs_free_mem(&buf)
+
+static inline dqbuf_t getdqbuf(void)
+{
+ dqbuf_t buf;
+ if (ext2fs_get_memzero(QT_BLKSIZE, &buf)) {
+ log_err("Failed to allocate dqbuf");
+ return NULL;
+ }
+
+ return buf;
+}
/* Is given dquot empty? */
int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk)
return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff;
}
+static inline void mark_quotafile_info_dirty(struct quota_handle *h)
+{
+ h->qh_io_flags |= IOFL_INFODIRTY;
+}
+
/* Read given block */
static void read_blk(struct quota_handle *h, uint blk, dqbuf_t buf)
{
err = h->e2fs_read(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf,
QT_BLKSIZE);
if (err < 0)
- log_fatal(2, "Cannot read block %u: %s", blk, strerror(errno));
+ log_err("Cannot read block %u: %s", blk, strerror(errno));
else if (err != QT_BLKSIZE)
memset(buf + err, 0, QT_BLKSIZE - err);
}
err = h->e2fs_write(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf,
QT_BLKSIZE);
if (err < 0 && errno != ENOSPC)
- log_fatal(2, "Cannot write block (%u): %s",
- blk, strerror(errno));
+ log_err("Cannot write block (%u): %s", blk, strerror(errno));
if (err != QT_BLKSIZE)
return -ENOSPC;
return 0;
struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
int blk;
+ if (!buf)
+ return -ENOMEM;
+
if (info->dqi_free_blk) {
blk = info->dqi_free_blk;
read_blk(h, blk, buf);
- info->dqi_free_blk = __le32_to_cpu(dh->dqdh_next_free);
+ info->dqi_free_blk = ext2fs_le32_to_cpu(dh->dqdh_next_free);
} else {
memset(buf, 0, QT_BLKSIZE);
/* Assure block allocation... */
if (write_blk(h, info->dqi_blocks, buf) < 0) {
freedqbuf(buf);
log_err("Cannot allocate new quota block "
- "(out of disk space).", "");
+ "(out of disk space).");
return -ENOSPC;
}
blk = info->dqi_blocks++;
struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
- dh->dqdh_next_free = __cpu_to_le32(info->dqi_free_blk);
- dh->dqdh_prev_free = __cpu_to_le32(0);
- dh->dqdh_entries = __cpu_to_le16(0);
+ dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_blk);
+ dh->dqdh_prev_free = ext2fs_cpu_to_le32(0);
+ dh->dqdh_entries = ext2fs_cpu_to_le16(0);
info->dqi_free_blk = blk;
mark_quotafile_info_dirty(h);
write_blk(h, blk, buf);
{
dqbuf_t tmpbuf = getdqbuf();
struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
- uint nextblk = __le32_to_cpu(dh->dqdh_next_free), prevblk =
+ uint nextblk = ext2fs_le32_to_cpu(dh->dqdh_next_free), prevblk =
+
+ ext2fs_le32_to_cpu(dh->dqdh_prev_free);
- __le32_to_cpu(dh->dqdh_prev_free);
+ if (!tmpbuf)
+ return;
if (nextblk) {
read_blk(h, nextblk, tmpbuf);
mark_quotafile_info_dirty(h);
}
freedqbuf(tmpbuf);
- dh->dqdh_next_free = dh->dqdh_prev_free = __cpu_to_le32(0);
+ dh->dqdh_next_free = dh->dqdh_prev_free = ext2fs_cpu_to_le32(0);
write_blk(h, blk, buf); /* No matter whether write succeeds
* block is out of list */
}
struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
- dh->dqdh_next_free = __cpu_to_le32(info->dqi_free_entry);
- dh->dqdh_prev_free = __cpu_to_le32(0);
+ if (!tmpbuf)
+ return;
+
+ dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_entry);
+ dh->dqdh_prev_free = ext2fs_cpu_to_le32(0);
write_blk(h, blk, buf);
if (info->dqi_free_entry) {
read_blk(h, info->dqi_free_entry, tmpbuf);
((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
- __cpu_to_le32(blk);
+ ext2fs_cpu_to_le32(blk);
write_blk(h, info->dqi_free_entry, tmpbuf);
}
freedqbuf(tmpbuf);
*err = 0;
buf = getdqbuf();
+ if (!buf) {
+ *err = -ENOMEM;
+ return 0;
+ }
+
dh = (struct qt_disk_dqdbheader *)buf;
if (info->dqi_free_entry) {
blk = info->dqi_free_entry;
}
/* Block will be full? */
- if (__le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info))
+ if (ext2fs_le16_to_cpu(dh->dqdh_entries) + 1 >=
+ qtree_dqstr_in_blk(info))
remove_free_dqentry(h, buf, blk);
- dh->dqdh_entries = __cpu_to_le16(__le16_to_cpu(dh->dqdh_entries) + 1);
+ dh->dqdh_entries =
+ ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) + 1);
/* Find free structure in block */
ddquot = buf + sizeof(struct qt_disk_dqdbheader);
for (i = 0;
ddquot += info->dqi_entry_size;
if (i == qtree_dqstr_in_blk(info))
- log_fatal(2, "find_free_dqentry(): Data block full but it "
- "shouldn't.", "");
+ log_err("find_free_dqentry(): Data block full unexpectedly.");
write_blk(h, blk, buf);
dquot->dq_dqb.u.v2_mdqb.dqb_off =
log_debug("inserting in tree: treeblk=%u, depth=%d", *treeblk, depth);
buf = getdqbuf();
+ if (!buf)
+ return -ENOMEM;
+
if (!*treeblk) {
ret = get_free_dqblk(h);
if (ret < 0)
}
ref = (u_int32_t *) buf;
- newblk = __le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);
+ newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);
if (!newblk)
newson = 1;
if (depth == QT_TREEDEPTH - 1) {
if (newblk)
- log_fatal(2, "Inserting already present quota entry "
- "(block %u).",
- ref[get_index(dquot->dq_id, depth)]);
+ log_err("Inserting already present quota entry "
+ "(block %u).",
+ ref[get_index(dquot->dq_id, depth)]);
newblk = find_free_dqentry(h, dquot, &ret);
} else {
ret = do_insert_tree(h, dquot, &newblk, depth + 1);
}
if (newson && ret >= 0) {
- ref[get_index(dquot->dq_id, depth)] = __cpu_to_le32(newblk);
+ ref[get_index(dquot->dq_id, depth)] =
+ ext2fs_cpu_to_le32(newblk);
write_blk(h, *treeblk, buf);
} else if (newact && ret < 0) {
put_free_dqblk(h, buf, *treeblk);
uint tmp = QT_TREEOFF;
if (do_insert_tree(h, dquot, &tmp, 0) < 0)
- log_fatal(2, "Cannot write quota (id %u): %s",
- (uint) dquot->dq_id, strerror(errno));
+ log_err("Cannot write quota (id %u): %s",
+ (uint) dquot->dq_id, strerror(errno));
}
/* Write dquot to file */
void qtree_write_dquot(struct dquot *dquot)
{
ssize_t ret;
+ char *ddquot;
struct quota_handle *h = dquot->dq_h;
struct qtree_mem_dqinfo *info =
&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree;
log_debug("writing ddquot 1: off=%llu, info->dqi_entry_size=%u",
dquot->dq_dqb.u.v2_mdqb.dqb_off,
info->dqi_entry_size);
- char *ddquot = (char *)smalloc(info->dqi_entry_size);
+ ret = ext2fs_get_mem(info->dqi_entry_size, &ddquot);
+ if (ret) {
+ errno = ENOMEM;
+ log_err("Quota write failed (id %u): %s",
+ (uint)dquot->dq_id, strerror(errno));
+ return;
+ }
if (!dquot->dq_dqb.u.v2_mdqb.dqb_off)
dq_insert_tree(dquot->dq_h, dquot);
if (ret != info->dqi_entry_size) {
if (ret > 0)
errno = ENOSPC;
- log_fatal(2, "Quota write failed (id %u): %s",
- (uint)dquot->dq_id, strerror(errno));
+ log_err("Quota write failed (id %u): %s",
+ (uint)dquot->dq_id, strerror(errno));
}
+ ext2fs_free_mem(&ddquot);
}
/* Free dquot entry in data block */
struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
dqbuf_t buf = getdqbuf();
+ if (!buf)
+ return;
+
if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk)
- log_fatal(2, "Quota structure has offset to other block (%u) "
- "than it should (%u).", blk,
+ log_err("Quota structure has offset to other block (%u) "
+ "than it should (%u).", blk,
(uint) (dquot->dq_dqb.u.v2_mdqb.dqb_off >>
QT_BLKSIZE_BITS));
read_blk(h, blk, buf);
dh = (struct qt_disk_dqdbheader *)buf;
- dh->dqdh_entries = __cpu_to_le16(__le16_to_cpu(dh->dqdh_entries) - 1);
+ dh->dqdh_entries =
+ ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) - 1);
- if (!__le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
+ if (!ext2fs_le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
remove_free_dqentry(h, buf, blk);
put_free_dqblk(h, buf, blk);
} else {
0, info->dqi_entry_size);
/* First free entry? */
- if (__le16_to_cpu(dh->dqdh_entries) ==
+ if (ext2fs_le16_to_cpu(dh->dqdh_entries) ==
qtree_dqstr_in_blk(info) - 1)
/* This will also write data block */
insert_free_dqentry(h, buf, blk);
uint newblk;
u_int32_t *ref = (u_int32_t *) buf;
+ if (!buf)
+ return;
+
read_blk(h, *blk, buf);
- newblk = __le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);
+ newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);
if (depth == QT_TREEDEPTH - 1) {
free_dqentry(h, dquot, newblk);
newblk = 0;
if (!newblk) {
int i;
- ref[get_index(dquot->dq_id, depth)] = __cpu_to_le32(0);
+ ref[get_index(dquot->dq_id, depth)] = ext2fs_cpu_to_le32(0);
/* Block got empty? */
for (i = 0; i < QT_BLKSIZE && !buf[i]; i++);
}
/* Find entry in block */
-static loff_t find_block_dqentry(struct quota_handle *h,
- struct dquot *dquot, uint blk)
+static ext2_loff_t find_block_dqentry(struct quota_handle *h,
+ struct dquot *dquot, uint blk)
{
struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
dqbuf_t buf = getdqbuf();
int i;
char *ddquot = buf + sizeof(struct qt_disk_dqdbheader);
+ if (!buf)
+ return -ENOMEM;
+
read_blk(h, blk, buf);
for (i = 0;
i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot);
ddquot += info->dqi_entry_size;
if (i == qtree_dqstr_in_blk(info))
- log_fatal(2, "Quota for id %u referenced but not present.",
- dquot->dq_id);
+ log_err("Quota for id %u referenced but not present.",
+ dquot->dq_id);
freedqbuf(buf);
return (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) +
i * info->dqi_entry_size;
}
/* Find entry for given id in the tree */
-static loff_t find_tree_dqentry(struct quota_handle *h, struct dquot *dquot,
- uint blk, int depth)
+static ext2_loff_t find_tree_dqentry(struct quota_handle *h,
+ struct dquot *dquot,
+ uint blk, int depth)
{
dqbuf_t buf = getdqbuf();
- loff_t ret = 0;
+ ext2_loff_t ret = 0;
u_int32_t *ref = (u_int32_t *) buf;
+ if (!buf)
+ return -ENOMEM;
+
read_blk(h, blk, buf);
ret = 0;
- blk = __le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);
+ blk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);
if (!blk) /* No reference? */
goto out_buf;
if (depth < QT_TREEDEPTH - 1)
}
/* Find entry for given id in the tree - wrapper function */
-static inline loff_t find_dqentry(struct quota_handle *h, struct dquot *dquot)
+static inline ext2_loff_t find_dqentry(struct quota_handle *h,
+ struct dquot *dquot)
{
return find_tree_dqentry(h, dquot, QT_TREEOFF, 0);
}
/*
- * Read dquot (either from disk or from kernel)
- * User can use errno to detect errstr when NULL is returned
+ * Read dquot from disk.
*/
struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id)
{
struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
- loff_t offset;
+ ext2_loff_t offset;
ssize_t ret;
- char *ddquot = smalloc(info->dqi_entry_size);
+ char *ddquot;
struct dquot *dquot = get_empty_dquot();
+ if (!dquot)
+ return NULL;
+ if (ext2fs_get_mem(info->dqi_entry_size, &ddquot)) {
+ ext2fs_free_mem(&dquot);
+ return NULL;
+ }
+
dquot->dq_id = id;
dquot->dq_h = h;
dquot->dq_dqb.u.v2_mdqb.dqb_off = 0;
if (ret != info->dqi_entry_size) {
if (ret > 0)
errno = EIO;
- log_fatal(2,
- "Cannot read quota structure for id %u: %s",
+ log_err("Cannot read quota structure for id %u: %s",
dquot->dq_id, strerror(errno));
}
info->dqi_ops->disk2mem_dqblk(dquot, ddquot);
}
+ ext2fs_free_mem(&ddquot);
return dquot;
}
/*
- * Scan all dquots in file and call callback on each
+ * Scan all dquots in file and call callback on each
*/
#define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7)))
#define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7)))
static int report_block(struct dquot *dquot, uint blk, char *bitmap,
- int (*process_dquot) (struct dquot *, char *))
+ int (*process_dquot) (struct dquot *, void *),
+ void *data)
{
struct qtree_mem_dqinfo *info =
&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree;
char *ddata;
int entries, i;
+ if (!buf)
+ return 0;
+
set_bit(bitmap, blk);
read_blk(dquot->dq_h, blk, buf);
dh = (struct qt_disk_dqdbheader *)buf;
ddata = buf + sizeof(struct qt_disk_dqdbheader);
- entries = __le16_to_cpu(dh->dqdh_entries);
+ entries = ext2fs_le16_to_cpu(dh->dqdh_entries);
for (i = 0; i < qtree_dqstr_in_blk(info);
i++, ddata += info->dqi_entry_size)
if (!qtree_entry_unused(info, ddata)) {
+ dquot->dq_dqb.u.v2_mdqb.dqb_off =
+ (blk << QT_BLKSIZE_BITS) +
+ sizeof(struct qt_disk_dqdbheader) +
+ i * info->dqi_entry_size;
info->dqi_ops->disk2mem_dqblk(dquot, ddata);
- if (process_dquot(dquot, NULL) < 0)
+ if (process_dquot(dquot, data) < 0)
break;
}
freedqbuf(buf);
static void check_reference(struct quota_handle *h, uint blk)
{
if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks)
- log_fatal(2, "Illegal reference (%u >= %u) in %s quota file. "
- "Quota file is probably corrupted.\n"
- "Please run e2fsck (8) to fix it.",
- blk,
- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks,
- type2name(h->qh_type));
+ log_err("Illegal reference (%u >= %u) in %s quota file. "
+ "Quota file is probably corrupted.\n"
+ "Please run e2fsck (8) to fix it.",
+ blk,
+ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks,
+ type2name(h->qh_type));
}
static int report_tree(struct dquot *dquot, uint blk, int depth, char *bitmap,
- int (*process_dquot) (struct dquot *, char *))
+ int (*process_dquot) (struct dquot *, void *),
+ void *data)
{
int entries = 0, i;
dqbuf_t buf = getdqbuf();
u_int32_t *ref = (u_int32_t *) buf;
+ if (!buf)
+ return 0;
+
read_blk(dquot->dq_h, blk, buf);
if (depth == QT_TREEDEPTH - 1) {
for (i = 0; i < QT_BLKSIZE >> 2; i++) {
- blk = __le32_to_cpu(ref[i]);
+ blk = ext2fs_le32_to_cpu(ref[i]);
check_reference(dquot->dq_h, blk);
if (blk && !get_bit(bitmap, blk))
entries += report_block(dquot, blk, bitmap,
- process_dquot);
+ process_dquot, data);
}
} else {
- for (i = 0; i < QT_BLKSIZE >> 2; i++)
- blk = __le32_to_cpu(ref[i]);
+ for (i = 0; i < QT_BLKSIZE >> 2; i++) {
+ blk = ext2fs_le32_to_cpu(ref[i]);
if (blk) {
check_reference(dquot->dq_h, blk);
entries += report_tree(dquot, blk, depth + 1,
- bitmap, process_dquot);
+ bitmap, process_dquot,
+ data);
}
+ }
}
freedqbuf(buf);
return entries;
}
int qtree_scan_dquots(struct quota_handle *h,
- int (*process_dquot) (struct dquot *, char *))
+ int (*process_dquot) (struct dquot *, void *),
+ void *data)
{
char *bitmap;
struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi;
struct qtree_mem_dqinfo *info = &v2info->dqi_qtree;
struct dquot *dquot = get_empty_dquot();
+ if (!dquot)
+ return -1;
+
dquot->dq_h = h;
- bitmap = smalloc((info->dqi_blocks + 7) >> 3);
- memset(bitmap, 0, (info->dqi_blocks + 7) >> 3);
+ if (ext2fs_get_memzero((info->dqi_blocks + 7) >> 3, &bitmap)) {
+ ext2fs_free_mem(&dquot);
+ return -1;
+ }
v2info->dqi_used_entries = report_tree(dquot, QT_TREEOFF, 0, bitmap,
- process_dquot);
+ process_dquot, data);
v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks);
- free(bitmap);
- free(dquot);
+ ext2fs_free_mem(&bitmap);
+ ext2fs_free_mem(&dquot);
return 0;
}