diff options
Diffstat (limited to 'quotacheck_v2.c')
-rw-r--r-- | quotacheck_v2.c | 136 |
1 files changed, 98 insertions, 38 deletions
diff --git a/quotacheck_v2.c b/quotacheck_v2.c index 7788237..b6a2d7f 100644 --- a/quotacheck_v2.c +++ b/quotacheck_v2.c @@ -18,8 +18,9 @@ #include "quotaio.h" #include "quotaio_v2.h" #include "quotacheck.h" +#include "quota_tree.h" -#define getdqbuf() smalloc(V2_DQBLKSIZE) +#define getdqbuf() smalloc(QT_BLKSIZE) #define freedqbuf(buf) free(buf) #define SET_BLK(blk) (blkbmp[(blk) >> 3] |= 1 << ((blk) & 7)) @@ -28,14 +29,15 @@ typedef char *dqbuf_t; static const int magics[MAXQUOTAS] = INITQMAGICS; /* Magics we should look for */ -static const int known_versions[MAXQUOTAS] = INITKNOWNVERSIONS; /* Versions we accept */ +static const int known_versions[MAXQUOTAS] = INIT_V2_VERSIONS; /* Versions we accept */ static char *blkbmp; /* Bitmap of checked blocks */ +static int detected_versions[MAXQUOTAS]; static int check_blkref(uint blk, uint blocks) { if (blk >= blocks) return -1; - if (blk && blk < V2_DQTREEOFF) + if (blk && blk < QT_TREEOFF) return -1; return 0; } @@ -69,25 +71,32 @@ static int check_info(char *filename, int fd, int type) dflags = __le32_to_cpu(dinfo.dqi_flags); filesize = lseek(fd, 0, SEEK_END); if (check_blkref(freeblk, blocks) < 0 || dflags & ~V2_DQF_MASK || - check_blkref(freeent, blocks) < 0 || (filesize + V2_DQBLKSIZE - 1) >> V2_DQBLKSIZE_BITS != blocks) { + check_blkref(freeent, blocks) < 0 || (filesize + QT_BLKSIZE - 1) >> QT_BLKSIZE_BITS != blocks) { errstr(_("WARNING - Quota file info was corrupted.\n")); debug(FL_DEBUG, _("Size of file: %lu\nBlocks: %u Free block: %u Block with free entry: %u Flags: %x\n"), (unsigned long)filesize, blocks, freeblk, freeent, dflags); old_info[type].dqi_bgrace = MAX_DQ_TIME; old_info[type].dqi_igrace = MAX_IQ_TIME; - old_info[type].u.v2_mdqi.dqi_blocks = - (filesize + V2_DQBLKSIZE - 1) >> V2_DQBLKSIZE_BITS; + old_info[type].u.v2_mdqi.dqi_qtree.dqi_blocks = + (filesize + QT_BLKSIZE - 1) >> QT_BLKSIZE_BITS; old_info[type].u.v2_mdqi.dqi_flags = 0; printf(_("Setting grace times and other flags to default values.\nAssuming number of blocks is %u.\n"), - old_info[type].u.v2_mdqi.dqi_blocks); + old_info[type].u.v2_mdqi.dqi_qtree.dqi_blocks); } else { old_info[type].dqi_bgrace = __le32_to_cpu(dinfo.dqi_bgrace); old_info[type].dqi_igrace = __le32_to_cpu(dinfo.dqi_igrace); - old_info[type].u.v2_mdqi.dqi_blocks = blocks; + old_info[type].u.v2_mdqi.dqi_qtree.dqi_blocks = blocks; old_info[type].u.v2_mdqi.dqi_flags = dflags; } - old_info[type].u.v2_mdqi.dqi_free_blk = old_info[type].u.v2_mdqi.dqi_free_entry = 0; /* This won't be needed */ + if (detected_versions[type] == 0) + old_info[type].u.v2_mdqi.dqi_qtree.dqi_entry_size = sizeof(struct v2r0_disk_dqblk); + else if (detected_versions[type] == 1) + old_info[type].u.v2_mdqi.dqi_qtree.dqi_entry_size = sizeof(struct v2r1_disk_dqblk); + /* Won't be needed */ + old_info[type].u.v2_mdqi.dqi_qtree.dqi_free_blk = 0; + old_info[type].u.v2_mdqi.dqi_qtree.dqi_free_entry = 0; + debug(FL_DEBUG, _("File info done.\n")); return 0; } @@ -120,7 +129,7 @@ static void blk_corrupted(int *corrupted, uint * lblk, uint blk, char *fmtstr, . } /* Convert dist quota format to utility one - copy just needed fields */ -static inline void disk2utildqblk(struct util_dqblk *u, struct v2_disk_dqblk *d) +static void v2r0_disk2utildqblk(struct util_dqblk *u, struct v2r0_disk_dqblk *d) { u->dqb_ihardlimit = __le32_to_cpu(d->dqb_ihardlimit); u->dqb_isoftlimit = __le32_to_cpu(d->dqb_isoftlimit); @@ -130,23 +139,34 @@ static inline void disk2utildqblk(struct util_dqblk *u, struct v2_disk_dqblk *d) u->dqb_btime = __le64_to_cpu(d->dqb_btime); } -/* Check whether given dquot is empty */ -static int empty_dquot(struct v2_disk_dqblk *d) +/* Convert dist quota format to utility one - copy just needed fields */ +static void v2r1_disk2utildqblk(struct util_dqblk *u, struct v2r1_disk_dqblk *d) { - static struct v2_disk_dqblk fakedq; - - return !memcmp(&fakedq, d, sizeof(fakedq)); + u->dqb_ihardlimit = __le64_to_cpu(d->dqb_ihardlimit); + u->dqb_isoftlimit = __le64_to_cpu(d->dqb_isoftlimit); + u->dqb_bhardlimit = __le64_to_cpu(d->dqb_bhardlimit); + u->dqb_bsoftlimit = __le64_to_cpu(d->dqb_bsoftlimit); + u->dqb_itime = __le64_to_cpu(d->dqb_itime); + u->dqb_btime = __le64_to_cpu(d->dqb_btime); } /* Put one entry info memory */ static int buffer_entry(dqbuf_t buf, uint blk, int *corrupted, uint * lblk, int cnt, int type) { - struct util_dqblk mdq, *fdq; + struct util_dqblk *fdq, mdq; qid_t id; struct dquot *cd; + struct qtree_mem_dqinfo *info = &old_info[type].u.v2_mdqi.dqi_qtree; + char *ddq = (char *)buf + sizeof(struct qt_disk_dqdbheader) + cnt * info->dqi_entry_size; + + if (detected_versions[type] == 0) { + v2r0_disk2utildqblk(&mdq, (struct v2r0_disk_dqblk *)ddq); + id = __le32_to_cpu(((struct v2r0_disk_dqblk *)ddq)->dqb_id); + } else { + v2r1_disk2utildqblk(&mdq, (struct v2r1_disk_dqblk *)ddq); + id = __le32_to_cpu(((struct v2r1_disk_dqblk *)ddq)->dqb_id); + } - disk2utildqblk(&mdq, ((struct v2_disk_dqblk *)(((char *)buf) + sizeof(struct v2_disk_dqdbheader))) + cnt); - id = __le32_to_cpu(((struct v2_disk_dqblk *)(((char *)buf) + sizeof(struct v2_disk_dqdbheader)))[cnt].dqb_id); cd = lookup_dquot(id, type); if (cd != NODQUOT) { fdq = &cd->dq_dqb; @@ -213,13 +233,13 @@ static void check_read_blk(int fd, uint blk, dqbuf_t buf) { size_t rd; - lseek(fd, blk << V2_DQBLKSIZE_BITS, SEEK_SET); - rd = read(fd, buf, V2_DQBLKSIZE); + lseek(fd, blk << QT_BLKSIZE_BITS, SEEK_SET); + rd = read(fd, buf, QT_BLKSIZE); if (rd < 0) die(2, _("Cannot read block %u: %s\n"), blk, strerror(errno)); - if (rd != V2_DQBLKSIZE) { + if (rd != QT_BLKSIZE) { debug(FL_VERBOSE | FL_DEBUG, _("Block %u is truncated.\n"), blk); - memset(buf + rd, 0, V2_DQBLKSIZE - rd); + memset(buf + rd, 0, QT_BLKSIZE - rd); } } @@ -242,20 +262,21 @@ static int check_tree_ref(uint blk, uint ref, uint blocks, int check_use, int * static int check_data_blk(int fd, uint blk, int type, uint blocks, int * corrupted, uint * lblk) { dqbuf_t buf = getdqbuf(); - struct v2_disk_dqdbheader *head = (struct v2_disk_dqdbheader *)buf; + struct qt_disk_dqdbheader *head = (struct qt_disk_dqdbheader *)buf; int i; - struct v2_disk_dqblk *dd = (struct v2_disk_dqblk *)(head + 1); + char *dd = (char *)(head + 1); + struct qtree_mem_dqinfo *info = &old_info[type].u.v2_mdqi.dqi_qtree; SET_BLK(blk); check_read_blk(fd, blk, buf); if (check_blkref(__le32_to_cpu(head->dqdh_next_free), blocks) < 0) blk_corrupted(corrupted, lblk, blk, _("Illegal free block reference to block %u"), __le32_to_cpu(head->dqdh_next_free)); - if (__le16_to_cpu(head->dqdh_entries) > V2_DQSTRINBLK) + if (__le16_to_cpu(head->dqdh_entries) > qtree_dqstr_in_blk(info)) blk_corrupted(corrupted, lblk, blk, _("Corrupted number of used entries (%u)"), (uint) __le16_to_cpu(head->dqdh_entries)); - for (i = 0; i < V2_DQSTRINBLK; i++) - if (!empty_dquot(dd + i)) + for (i = 0; i < qtree_dqstr_in_blk(info); i++) + if (!qtree_entry_unused(info, dd + i * info->dqi_entry_size)) if (buffer_entry(buf, blk, corrupted, lblk, i, type) < 0) { freedqbuf(buf); return -1; @@ -274,8 +295,8 @@ static int check_tree_blk(int fd, uint blk, int depth, int type, uint blocks, in SET_BLK(blk); check_read_blk(fd, blk, buf); - for (i = 0; i < V2_DQBLKSIZE >> 2; i++) - if (depth < V2_DQTREEDEPTH - 1) { + for (i = 0; i < QT_BLKSIZE >> 2; i++) + if (depth < QT_TREEDEPTH - 1) { if (check_tree_ref(blk, __le32_to_cpu(r[i]), blocks, 1, corrupted, lblk) >= 0 && __le32_to_cpu(r[i])) /* Isn't block OK? */ if (check_tree_blk(fd, __le32_to_cpu(r[i]), depth + 1, type, blocks, corrupted, lblk) < 0) { @@ -292,8 +313,26 @@ static int check_tree_blk(int fd, uint blk, int depth, int type, uint blocks, in return 0; } +int v2_detect_version(char *filename, int fd, int type) +{ + struct v2_disk_dqheader head; + int err; + + lseek(fd, 0, SEEK_SET); + err = read(fd, &head, sizeof(head)); + if (err < 0 || err != sizeof(head)) + return -1; + if (__le32_to_cpu(head.dqh_magic) != magics[type] || + __le32_to_cpu(head.dqh_version) > known_versions[type]) { + errstr(_("Quota file %s has corrupted headers. You have to specify quota format on command line.\n"), + filename); + return -1; + } + return __le32_to_cpu(head.dqh_version); +} + /* Check basic header */ -static int check_header(char *filename, int fd, int type) +static int check_header(char *filename, int fd, int type, int version) { int err; struct v2_disk_dqheader head; @@ -308,34 +347,55 @@ static int check_header(char *filename, int fd, int type) filename); return -1; } - if (__le32_to_cpu(head.dqh_magic) != magics[type] || __le32_to_cpu(head.dqh_version) > known_versions[type]) + if (__le32_to_cpu(head.dqh_magic) != magics[type] || + __le32_to_cpu(head.dqh_version) > known_versions[type]) { errstr(_("WARNING - Quota file %s has corrupted headers\n"), filename); + } + if (__le32_to_cpu(head.dqh_version) != version) { + errstr(_("Quota file format version %d does not match the one " + "specified on command line (%d). Quota file header " + "may be corrupted.\n"), + __le32_to_cpu(head.dqh_version), version); + if (!ask_yn(_("Continue checking assuming version from command line?"), 1)) + return -1; + detected_versions[type] = version; + } else + detected_versions[type] = __le32_to_cpu(head.dqh_version); + debug(FL_DEBUG, _("Headers checked.\n")); return 0; } /* Load data from file to memory */ -int v2_buffer_file(char *filename, int fd, int type) +int v2_buffer_file(char *filename, int fd, int type, int fmt) { uint blocks, lastblk = 0; int corrupted = 0, ret = 0; + int version; + + if (fmt == QF_VFSV0) + version = 0; + else if (fmt == QF_VFSV1) + version = 1; + else + die(3, _("Do not know how to buffer format %d\n"), fmt); old_info[type].dqi_bgrace = MAX_DQ_TIME; old_info[type].dqi_igrace = MAX_IQ_TIME; if (flags & FL_NEWFILE) return 0; - if (check_header(filename, fd, type) < 0) - return 0; + if (check_header(filename, fd, type, version) < 0) + return -1; if (check_info(filename, fd, type) < 0) - return 0; + return -1; debug(FL_DEBUG, _("Headers of file %s checked. Going to load data...\n"), filename); - blocks = old_info[type].u.v2_mdqi.dqi_blocks; + blocks = old_info[type].u.v2_mdqi.dqi_qtree.dqi_blocks; blkbmp = xmalloc((blocks + 7) >> 3); memset(blkbmp, 0, (blocks + 7) >> 3); - if (check_tree_ref(0, V2_DQTREEOFF, blocks, 1, &corrupted, &lastblk) >= 0) - ret = check_tree_blk(fd, V2_DQTREEOFF, 0, type, blocks, &corrupted, &lastblk); + if (check_tree_ref(0, QT_TREEOFF, blocks, 1, &corrupted, &lastblk) >= 0) + ret = check_tree_blk(fd, QT_TREEOFF, 0, type, blocks, &corrupted, &lastblk); else errstr(_("Cannot gather quota data. Tree root node corrupted.\n")); #ifdef DEBUG_MALLOC |