"Fossies" - the Fresh Open Source Software Archive

Member "quotactl-1.00/quotause/quotause_v2.c" (9 Oct 2005, 16384 Bytes) of package /linux/privat/old/quotactl-1.00.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "quotause_v2.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  *
    3  *  Checking routines for new VFS quota format
    4  *
    5  */
    6 #define _GNU_SOURCE
    7 #define _FILE_OFFSET_BITS 64
    8 
    9 #include <stdbool.h>
   10 #include <stdio.h>
   11 #include <unistd.h>
   12 #include <string.h>
   13 #include <errno.h>
   14 #include <stdarg.h>
   15 #include <stdlib.h>
   16 #include <asm/byteorder.h>
   17 
   18 #include <giraffe/girtypes.h>
   19 #include <giraffe/girstring.h>
   20 #include <giraffe/fatal.h>
   21 #include <giraffe/mallocvar.h>
   22 
   23 #include "quotaio.h"
   24 #include "quotaio_v2.h"
   25 #include "quotacheck.h"
   26 #include "quotause_v2.h"
   27 #include "dquothash.h"
   28 #include "misc.h"
   29 
   30 
   31 
   32 
   33 #define SET_BLK(blk) (blkbmp[(blk) >> 3] |= 1 << ((blk) & 7))
   34 #define GET_BLK(blk) (blkbmp[(blk) >> 3] & (1 << ((blk) & 7)))
   35 
   36 static char * blkbmp;       /* Bitmap of checked blocks */
   37 
   38 static int
   39 check_blkref(uint const blk,
   40              uint const blocks) {
   41 /*----------------------------------------------------------------------------
   42    Determine whether the block reference 'blk' is valid, given that there
   43    are 'blocks' blocks in the quota file.
   44 
   45    A block reference is just a block number.  So a valid block reference
   46    is one that isn't beyond the end of the file and isn't in the header
   47    region of the file.
   48 -----------------------------------------------------------------------------*/
   49     int retval;
   50 
   51     if (blk >= blocks)
   52         retval = -1;
   53     else {
   54         if (blk && blk < V2_DQTREEOFF)
   55             retval = -1;
   56         else
   57             retval = 0;
   58     }
   59     return retval;
   60 }
   61 
   62 
   63 
   64 static void
   65 checkForCorruption(off_t  const filesize,
   66                    uint   const blocks,
   67                    uint   const freeblk,
   68                    uint   const freeent,
   69                    uint   const dflags,
   70                    bool * const corruptedP) {
   71 
   72     bool corrupted;
   73 
   74     corrupted = false;  // initial assumption
   75 
   76     if ((dflags & ~V2_DQF_MASK) != 0) {
   77         msg("WARNING: illegal dflags %08x", dflags & ~V2_DQF_MASK);
   78         corrupted = true;
   79     }
   80     if (check_blkref(freeblk, blocks)) {
   81         msg("WARNING: freeblk (%u) is not within the tree region of "
   82             "the quota file.", freeblk);
   83         corrupted = true;
   84     }
   85     if (check_blkref(freeent, blocks)) {
   86         msg("WARNING: freeent (%u) is not within the tree region of "
   87             "the quota file.", freeblk);
   88         corrupted = true;
   89     }
   90     if ((filesize + V2_DQBLKSIZE - 1) >> V2_DQBLKSIZE_BITS != blocks) {
   91         msg("WARNING: filesize %llu is wrong for %u blocks of "
   92             "%u bytes each", filesize, blocks, V2_DQBLKSIZE);
   93         corrupted = true;
   94     }
   95     *corruptedP = corrupted;
   96 }
   97 
   98 
   99 
  100 static void
  101 checkInfoWithData(struct v2_disk_dqinfo const dinfo,
  102                   off_t                 const filesize,
  103                   int                   const type) {
  104 
  105     uint const blocks  = __le32_to_cpu(dinfo.dqi_blocks);
  106     uint const freeblk = __le32_to_cpu(dinfo.dqi_free_blk);
  107     uint const freeent = __le32_to_cpu(dinfo.dqi_free_entry);
  108     uint const dflags  = __le32_to_cpu(dinfo.dqi_flags);
  109 
  110     bool corrupted;
  111 
  112     checkForCorruption(filesize, blocks, freeblk, freeent, dflags, &corrupted);
  113     
  114     if (corrupted) {
  115         old_info[type].dqi_bgrace = MAX_DQ_TIME;
  116         old_info[type].dqi_igrace = MAX_IQ_TIME;
  117         old_info[type].u.v2_mdqi.dqi_blocks =
  118             (filesize + V2_DQBLKSIZE - 1) >> V2_DQBLKSIZE_BITS;
  119         old_info[type].u.v2_mdqi.dqi_flags = 0;
  120         msg("WARNING: Quota file is corrupted (as explained by "
  121             "previous warnings), so we will be setting grace times "
  122             "and certain flags to default values and assuming "
  123             "the number of blocks is %u.  "
  124             "The output file will be pure.", 
  125             old_info[type].u.v2_mdqi.dqi_blocks);
  126     } else {
  127         old_info[type].dqi_bgrace = __le32_to_cpu(dinfo.dqi_bgrace);
  128         old_info[type].dqi_igrace = __le32_to_cpu(dinfo.dqi_igrace);
  129         old_info[type].u.v2_mdqi.dqi_blocks = blocks;
  130         old_info[type].u.v2_mdqi.dqi_flags = dflags;
  131     }
  132     old_info[type].u.v2_mdqi.dqi_free_blk =
  133         old_info[type].u.v2_mdqi.dqi_free_entry = 0;
  134         /* This won't be needed */
  135 }
  136 
  137 
  138 
  139 /* Load and check basic info about quotas */
  140 static int
  141 check_info(const char * const filename,
  142            int          const fd,
  143            int          const type) {
  144 
  145     struct v2_disk_dqinfo dinfo;
  146     int retval;
  147     ssize_t rc;
  148 
  149     debug("Checking quotafile info...");
  150 
  151     lseek(fd, V2_DQINFOOFF, SEEK_SET);
  152     rc = read(fd, &dinfo, sizeof(dinfo));
  153 
  154     if (rc < 0) {
  155         msg("Can't read info from quota file '%s'.  errno=%d (%s)",
  156             filename, errno, strerror(errno));
  157         retval = -1;
  158     } else {
  159         size_t const bytesRead = rc;
  160 
  161         if (bytesRead != sizeof(struct v2_disk_dqinfo)) {
  162             msg("WARNING - Quota file '%s' was probably truncated.  "
  163                 "Can't save quota settings...",
  164                 filename);
  165             retval = -1;
  166         } else {
  167             off_t rc;
  168 
  169             rc = lseek(fd, 0, SEEK_END);
  170             if (rc < 0) {
  171                 msg("lseek() failed. errno=%d (%s)", errno, strerror(errno));
  172                 retval = -1;
  173             } else {
  174                 off_t const filesize = rc;
  175 
  176                 checkInfoWithData(dinfo, filesize, type);
  177 
  178                 retval = 0;
  179             }
  180         }
  181     }
  182     debug("File info done.");
  183     return retval;
  184 }
  185 
  186 
  187 
  188 static void
  189 blk_corrupted(int *        const corruptedP,
  190               uint *       const lblkP,
  191               uint         const blk,
  192               const char * const fmtstr, ...) {
  193 
  194     va_list args;
  195 
  196     if (flags & FL_VERBOSE) {
  197         const char * argmsg;
  198         if (!*corruptedP)
  199             msg("Corrupted blocks: ");
  200 
  201         va_start(args, fmtstr);
  202         cvasprintf(&argmsg, fmtstr, args);
  203         va_end(args);
  204         
  205         msg("Block %u: %s", blk, argmsg);
  206         strfree(argmsg);
  207     } else if (*lblkP != blk) {
  208         if (!*corruptedP)
  209             fprintf(stderr, "%u", blk);
  210         else
  211             fprintf(stderr, ", %u", blk);
  212     }
  213     *corruptedP = true;
  214     *lblkP = blk;
  215     fflush(stderr);
  216 }
  217 
  218 
  219 
  220 /* Convert dist quota format to utility one - copy just needed fields */
  221 static inline void
  222 disk2utildqblk(struct util_dqblk *    const u,
  223                struct v2_disk_dqblk * const d) {
  224 
  225     u->dqb_ihardlimit = __le32_to_cpu(d->dqb_ihardlimit);
  226     u->dqb_isoftlimit = __le32_to_cpu(d->dqb_isoftlimit);
  227     u->dqb_bhardlimit = __le32_to_cpu(d->dqb_bhardlimit);
  228     u->dqb_bsoftlimit = __le32_to_cpu(d->dqb_bsoftlimit);
  229     u->dqb_itime = __le64_to_cpu(d->dqb_itime);
  230     u->dqb_btime = __le64_to_cpu(d->dqb_btime);
  231 }
  232 
  233 
  234 
  235 /* Check whether given dquot is empty */
  236 static int
  237 empty_dquot(struct v2_disk_dqblk * const d) {
  238 
  239     static struct v2_disk_dqblk fakedq;
  240 
  241     return !memcmp(&fakedq, d, sizeof(fakedq));
  242 }
  243 
  244 
  245 
  246 /* Put one entry info memory */
  247 static int
  248 buffer_entry(const dqbuf * const bufP,
  249              uint          const blk,
  250              int *         const corrupted,
  251              uint *        const lblk,
  252              int           const cnt,
  253              int           const type) {
  254 
  255     struct util_dqblk mdq, *fdq;
  256     qid_t id;
  257     struct dquot *cd;
  258 
  259     disk2utildqblk(&mdq, 
  260                    ((struct v2_disk_dqblk *)
  261                     (&bufP->bytes[0] + sizeof(struct v2_disk_dqdbheader))) +
  262                    cnt);
  263     id = __le32_to_cpu(((struct v2_disk_dqblk *)
  264                         (&bufP->bytes[0] +
  265                          sizeof(struct v2_disk_dqdbheader)))[cnt].dqb_id);
  266     cd = lookup_dquot(id, type);
  267     if (cd) {
  268         fdq = &cd->dq_dqb;
  269         if (mdq.dqb_bhardlimit != fdq->dqb_bhardlimit
  270             || mdq.dqb_bsoftlimit != fdq->dqb_bsoftlimit
  271             || mdq.dqb_ihardlimit != fdq->dqb_ihardlimit
  272             || mdq.dqb_isoftlimit != fdq->dqb_isoftlimit) {
  273             blk_corrupted(corrupted, lblk, blk, "Duplicated entries.");
  274             if (flags & FL_GUESSDQ) {
  275                 if (!(flags & FL_VERBOSE))
  276                     fputc('\n', stderr);
  277                 msg("Found more structures for ID %u.  "
  278                     "Using values: BHARD: %Ld BSOFT: %Ld "
  279                     "IHARD: %Ld ISOFT: %Ld",
  280                     (uint) id, (long long)fdq->dqb_bhardlimit,
  281                     (long long)fdq->dqb_bsoftlimit,
  282                     (long long)fdq->dqb_ihardlimit,
  283                     (long long)fdq->dqb_isoftlimit);
  284                 return 0;
  285             } else if (flags & FL_INTERACTIVE) {
  286                 if (!(flags & FL_VERBOSE))
  287                     fputc('\n', stderr);
  288                 msg("Found more structures for ID %u.  "
  289                     "Values: BHARD: %Ld/%Ld BSOFT: %Ld/%Ld "
  290                     "IHARD: %Ld/%Ld ISOFT: %Ld/%Ld",
  291                     (uint) id, (long long)fdq->dqb_bhardlimit,
  292                     (long long)mdq.dqb_bhardlimit,
  293                     (long long)fdq->dqb_bsoftlimit,
  294                     (long long)mdq.dqb_bsoftlimit,
  295                     (long long)fdq->dqb_ihardlimit,
  296                     (long long)mdq.dqb_ihardlimit,
  297                     (long long)fdq->dqb_isoftlimit,
  298                     (long long)mdq.dqb_isoftlimit);
  299                 if (ask_yn("Should I use new values", 0)) {
  300                     fdq->dqb_bhardlimit = mdq.dqb_bhardlimit;
  301                     fdq->dqb_bsoftlimit = mdq.dqb_bsoftlimit;
  302                     fdq->dqb_ihardlimit = mdq.dqb_ihardlimit;
  303                     fdq->dqb_isoftlimit = mdq.dqb_isoftlimit;
  304                     fdq->dqb_btime = mdq.dqb_btime;
  305                     fdq->dqb_itime = mdq.dqb_itime;
  306                 }
  307             } else {
  308                 msg("ID %u has more structures.  User intervention needed "
  309                     "(use -i for interactive mode or -n "
  310                     "for automatic answer).",
  311                     (uint) id);
  312                 return -1;
  313             }
  314         } else if (mdq.dqb_itime != fdq->dqb_itime ||
  315                    mdq.dqb_btime != fdq->dqb_btime) {
  316             if (fdq->dqb_btime < mdq.dqb_btime)
  317                 fdq->dqb_btime = mdq.dqb_btime;
  318             if (fdq->dqb_itime < mdq.dqb_itime)
  319                 fdq->dqb_itime = mdq.dqb_itime;
  320         }
  321     } else {
  322         cd = create_dquot(id);
  323         add_dquot(cd, type);
  324         fdq = &cd->dq_dqb;
  325         fdq->dqb_bhardlimit = mdq.dqb_bhardlimit;
  326         fdq->dqb_bsoftlimit = mdq.dqb_bsoftlimit;
  327         fdq->dqb_ihardlimit = mdq.dqb_ihardlimit;
  328         fdq->dqb_isoftlimit = mdq.dqb_isoftlimit;
  329 
  330         /* Add grace times only if there are limits... */
  331         if (mdq.dqb_bsoftlimit)
  332             fdq->dqb_btime = mdq.dqb_btime;
  333         if (mdq.dqb_isoftlimit)
  334             fdq->dqb_itime = mdq.dqb_itime;
  335     }
  336     return 0;
  337 }
  338 
  339 
  340 
  341 static void
  342 check_read_blk(int     const fd,
  343                uint    const blk,
  344                dqbuf * const bufP) {
  345 
  346     ssize_t readRc;
  347 
  348     lseek(fd, blk << V2_DQBLKSIZE_BITS, SEEK_SET);
  349     readRc = read(fd, bufP, V2_DQBLKSIZE);
  350     if (readRc < 0)
  351         fatal("Can't read block %u.  read() errno is %d (%s)",
  352               blk, errno, strerror(errno));
  353     else {
  354         size_t const bytesRead = readRc;
  355         
  356         if (bytesRead != V2_DQBLKSIZE) {
  357             debug("Block %u is truncated.", blk);
  358             memset(bufP + bytesRead, 0, V2_DQBLKSIZE - bytesRead);
  359         }
  360     }
  361 }
  362 
  363 
  364 
  365 static int
  366 check_tree_ref(uint   const blk,
  367                uint   const ref,
  368                uint   const blocks,
  369                int    const check_use,
  370                uint * const corrupted,
  371                uint * const lblk) {
  372 
  373     if (check_blkref(ref, blocks) < 0) {
  374         blk_corrupted(corrupted, lblk, blk,
  375                       "Reference to illegal block %u", ref);
  376         return -1;
  377     }
  378     if (!ref)
  379         return 0;
  380     if (!check_use || !GET_BLK(ref))
  381         return 0;
  382     blk_corrupted(corrupted, lblk, blk,
  383                   "Block %u in tree referenced twice", ref);
  384     return -1;
  385 }
  386 
  387 
  388 
  389 /* Check block with structures */
  390 static int
  391 check_data_blk(int    const fd,
  392                uint   const blk,
  393                int    const type,
  394                uint   const blocks,
  395                uint * const corrupted,
  396                uint * const lblk) {
  397 
  398     dqbuf buf;
  399     struct v2_disk_dqdbheader * const head = 
  400         (struct v2_disk_dqdbheader *)&buf.bytes[0];
  401     struct v2_disk_dqblk * const dd = (struct v2_disk_dqblk *)(head + 1);
  402 
  403     unsigned int i;
  404 
  405     SET_BLK(blk);
  406     check_read_blk(fd, blk, &buf);
  407     if (check_blkref(__le32_to_cpu(head->dqdh_next_free), blocks) < 0)
  408         blk_corrupted(corrupted, lblk, blk,
  409                       "Illegal free block reference to block %u",
  410                       __le32_to_cpu(head->dqdh_next_free));
  411     if (__le16_to_cpu(head->dqdh_entries) > V2_DQSTRINBLK)
  412         blk_corrupted(corrupted, lblk, blk,
  413                       "Corrupted number of used entries (%u)",
  414                       (uint) __le16_to_cpu(head->dqdh_entries));
  415     for (i = 0; i < V2_DQSTRINBLK; ++i)
  416         if (!empty_dquot(dd + i))
  417             if (buffer_entry(&buf, blk, corrupted, lblk, i, type) < 0)
  418                 return -1;
  419     return 0;
  420 }
  421 
  422 
  423 
  424 /* Check one tree block */
  425 static int
  426 check_tree_blk(int    const fd,
  427                uint   const blk,
  428                int    const depth,
  429                int    const type,
  430                uint   const blocks,
  431                uint * const corruptedP,
  432                uint * const lblk) {
  433 
  434     dqbuf buf;
  435 
  436     unsigned int i;
  437 
  438     SET_BLK(blk);
  439     check_read_blk(fd, blk, &buf);
  440     for (i = 0; i < ARRAY_SIZE(buf.words); ++i) {
  441         uint const thisInt = __le32_to_cpu(buf.words[i]);
  442 
  443         if (depth < V2_DQTREEDEPTH - 1) {
  444             int rc;
  445             rc = check_tree_ref(blk, thisInt, blocks, 1, corruptedP, lblk);
  446 
  447             if (rc >= 0 && thisInt != 0) {
  448                 int rc;
  449                 
  450                 rc = check_tree_blk(fd, thisInt, depth + 1, type,
  451                                     blocks, corruptedP, lblk);
  452                 if (rc < 0)
  453                     return -1;
  454             }
  455         } else {
  456             int rc;
  457 
  458             rc = check_tree_ref(blk, thisInt, blocks, 0, corruptedP, lblk);
  459             if (rc >= 0 && thisInt != 0) {
  460                 if (!GET_BLK(thisInt)) {
  461                     int rc;
  462                     
  463                     rc = check_data_blk(fd, thisInt,
  464                                         type, blocks, corruptedP, lblk);
  465                     if (rc < 0)
  466                         return -1;
  467                 }
  468             }
  469         }
  470     }
  471     return 0;
  472 }
  473 
  474 
  475 
  476 /* Check basic header */
  477 static int
  478 check_header(const char * const filename,
  479              int          const fd,
  480              int          const type) {
  481 
  482     bool ok;
  483 
  484     ok = quotafile_ops_2.check_file(fd, type);
  485 
  486     if (!ok)
  487         fatal("Quota file header in file '%s' is not a valid Version 2 "
  488               "header or we could not read it.", filename);
  489 
  490     return 0;
  491 }
  492 
  493 
  494 
  495 /* Load data from file to memory */
  496 int
  497 v2_buffer_file(const char * const filename,
  498                int          const fd,
  499                int          const type) {
  500 
  501     uint blocks, lastblk = 0;
  502     int corrupted = 0, ret = 0;
  503     unsigned int bitmapSize;
  504 
  505     old_info[type].dqi_bgrace = MAX_DQ_TIME;
  506     old_info[type].dqi_igrace = MAX_IQ_TIME;
  507     if (flags & FL_NEWFILE)
  508         return 0;
  509     if (check_header(filename, fd, type) < 0)
  510         return 0;
  511     if (check_info(filename, fd, type) < 0)
  512         return 0;
  513     debug("Headers of file %s checked. Going to load data...",
  514           filename);
  515     blocks = old_info[type].u.v2_mdqi.dqi_blocks;
  516     bitmapSize = (blocks + 7)/8;  /* # of bytes to bold 'blocks' bits */
  517     MALLOCARRAY_NOFAIL(blkbmp, bitmapSize);
  518     memset(blkbmp, 0, bitmapSize);
  519     if (check_tree_ref(0, V2_DQTREEOFF, blocks, 1, &corrupted, &lastblk) >= 0)
  520         ret = check_tree_blk(fd, V2_DQTREEOFF, 0, type, blocks, &corrupted,
  521                              &lastblk);
  522     else
  523         msg("Can't gather quota data.  Tree root node corrupted.");
  524     free(blkbmp);
  525     if (corrupted) {
  526         if (!(flags & FL_VERBOSE))
  527             fputc('\n', stderr);
  528         msg("WARNING - Some data might be changed due to corruption.");
  529     } else
  530         debug("No corrupted blocks found in '%s'.", filename);
  531     return ret;
  532 }
  533 
  534 
  535 
  536 /* Merge quotafile info from old and new file */
  537 void
  538 v2_merge_info(struct util_dqinfo * const new,
  539               struct util_dqinfo * const old) {
  540     new->u.v2_mdqi.dqi_flags = old->u.v2_mdqi.dqi_flags;
  541 }