home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / fs / ext2 / truncate.c < prev   
Encoding:
C/C++ Source or Header  |  1995-02-26  |  8.5 KB  |  350 lines

  1. /*
  2.  *  linux/fs/ext2/truncate.c
  3.  *
  4.  *  Copyright (C) 1992, 1993, 1994  Remy Card (card@masi.ibp.fr)
  5.  *                                  Laboratoire MASI - Institut Blaise Pascal
  6.  *                                  Universite Pierre et Marie Curie (Paris VI)
  7.  *
  8.  *  from
  9.  *
  10.  *  linux/fs/minix/truncate.c
  11.  *
  12.  *  Copyright (C) 1991, 1992  Linus Torvalds
  13.  */
  14.  
  15. /*
  16.  * Real random numbers for secure rm added 94/02/18
  17.  * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
  18.  */
  19.  
  20. #include <linux/errno.h>
  21. #include <linux/fs.h>
  22. #include <linux/ext2_fs.h>
  23. #include <linux/fcntl.h>
  24. #include <linux/sched.h>
  25. #include <linux/stat.h>
  26. #include <linux/locks.h>
  27. #include <linux/string.h>
  28.  
  29. static int ext2_secrm_seed = 152;    /* Random generator base */
  30.  
  31. #define RANDOM_INT (ext2_secrm_seed = ext2_secrm_seed * 69069l +1)
  32.  
  33. /*
  34.  * Truncate has the most races in the whole filesystem: coding it is
  35.  * a pain in the a**. Especially as I don't do any locking...
  36.  *
  37.  * The code may look a bit weird, but that's just because I've tried to
  38.  * handle things like file-size changes in a somewhat graceful manner.
  39.  * Anyway, truncating a file at the same time somebody else writes to it
  40.  * is likely to result in pretty weird behaviour...
  41.  *
  42.  * The new code handles normal truncates (size = 0) as well as the more
  43.  * general case (size = XXX). I hope.
  44.  */
  45.  
  46. static int trunc_direct (struct inode * inode)
  47. {
  48.     u32 * p;
  49.     int i, tmp;
  50.     struct buffer_head * bh;
  51.     unsigned long block_to_free = 0;
  52.     unsigned long free_count = 0;
  53.     int retry = 0;
  54.     int blocks = inode->i_sb->s_blocksize / 512;
  55. #define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \
  56.             inode->i_sb->s_blocksize)
  57.     int direct_block = DIRECT_BLOCK;
  58.  
  59. repeat:
  60.     for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) {
  61.         p = inode->u.ext2_i.i_data + i;
  62.         tmp = *p;
  63.         if (!tmp)
  64.             continue;
  65.         if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
  66.             bh = getblk (inode->i_dev, tmp,
  67.                      inode->i_sb->s_blocksize);
  68.         else
  69.             bh = get_hash_table (inode->i_dev, tmp,
  70.                          inode->i_sb->s_blocksize);
  71.         if (i < direct_block) {
  72.             brelse (bh);
  73.             goto repeat;
  74.         }
  75.         if ((bh && bh->b_count != 1) || tmp != *p) {
  76.             retry = 1;
  77.             brelse (bh);
  78.             continue;
  79.         }
  80.         *p = 0;
  81.         inode->i_blocks -= blocks;
  82.         inode->i_dirt = 1;
  83.         if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
  84.             memset(bh->b_data, RANDOM_INT, inode->i_sb->s_blocksize);
  85.             mark_buffer_dirty(bh, 1);
  86.         }
  87.         brelse (bh);
  88.         if (free_count == 0) {
  89.             block_to_free = tmp;
  90.             free_count++;
  91.         } else if (free_count > 0 && block_to_free == tmp - free_count)
  92.             free_count++;
  93.         else {
  94.             ext2_free_blocks (inode->i_sb, block_to_free, free_count);
  95.             block_to_free = tmp;
  96.             free_count = 1;
  97.         }
  98. /*        ext2_free_blocks (inode->i_sb, tmp, 1); */
  99.     }
  100.     if (free_count > 0)
  101.         ext2_free_blocks (inode->i_sb, block_to_free, free_count);
  102.     return retry;
  103. }
  104.  
  105. static int trunc_indirect (struct inode * inode, int offset, u32 * p)
  106. {
  107.     int i, tmp;
  108.     struct buffer_head * bh;
  109.     struct buffer_head * ind_bh;
  110.     u32 * ind;
  111.     unsigned long block_to_free = 0;
  112.     unsigned long free_count = 0;
  113.     int retry = 0;
  114.     int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
  115.     int blocks = inode->i_sb->s_blocksize / 512;
  116. #define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset)
  117.     int indirect_block = INDIRECT_BLOCK;
  118.  
  119.     tmp = *p;
  120.     if (!tmp)
  121.         return 0;
  122.     ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
  123.     if (tmp != *p) {
  124.         brelse (ind_bh);
  125.         return 1;
  126.     }
  127.     if (!ind_bh) {
  128.         *p = 0;
  129.         return 0;
  130.     }
  131. repeat:
  132.     for (i = indirect_block ; i < addr_per_block ; i++) {
  133.         if (i < 0)
  134.             i = 0;
  135.         if (i < indirect_block)
  136.             goto repeat;
  137.         ind = i + (u32 *) ind_bh->b_data;
  138.         tmp = *ind;
  139.         if (!tmp)
  140.             continue;
  141.         if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
  142.             bh = getblk (inode->i_dev, tmp,
  143.                      inode->i_sb->s_blocksize);
  144.         else
  145.             bh = get_hash_table (inode->i_dev, tmp,
  146.                          inode->i_sb->s_blocksize);
  147.         if (i < indirect_block) {
  148.             brelse (bh);
  149.             goto repeat;
  150.         }
  151.         if ((bh && bh->b_count != 1) || tmp != *ind) {
  152.             retry = 1;
  153.             brelse (bh);
  154.             continue;
  155.         }
  156.         *ind = 0;
  157.         mark_buffer_dirty(ind_bh, 1);
  158.         if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
  159.             memset(bh->b_data, RANDOM_INT, inode->i_sb->s_blocksize);
  160.             mark_buffer_dirty(bh, 1);
  161.         }
  162.         brelse (bh);
  163.         if (free_count == 0) {
  164.             block_to_free = tmp;
  165.             free_count++;
  166.         } else if (free_count > 0 && block_to_free == tmp - free_count)
  167.             free_count++;
  168.         else {
  169.             ext2_free_blocks (inode->i_sb, block_to_free, free_count);
  170.             block_to_free = tmp;
  171.             free_count = 1;
  172.         }
  173. /*        ext2_free_blocks (inode->i_sb, tmp, 1); */
  174.         inode->i_blocks -= blocks;
  175.         inode->i_dirt = 1;
  176.     }
  177.     if (free_count > 0)
  178.         ext2_free_blocks (inode->i_sb, block_to_free, free_count);
  179.     ind = (u32 *) ind_bh->b_data;
  180.     for (i = 0; i < addr_per_block; i++)
  181.         if (*(ind++))
  182.             break;
  183.     if (i >= addr_per_block)
  184.         if (ind_bh->b_count != 1)
  185.             retry = 1;
  186.         else {
  187.             tmp = *p;
  188.             *p = 0;
  189.             inode->i_blocks -= blocks;
  190.             inode->i_dirt = 1;
  191.             ext2_free_blocks (inode->i_sb, tmp, 1);
  192.         }
  193.     if (IS_SYNC(inode) && ind_bh->b_dirt) {
  194.         ll_rw_block (WRITE, 1, &ind_bh);
  195.         wait_on_buffer (ind_bh);
  196.     }
  197.     brelse (ind_bh);
  198.     return retry;
  199. }
  200.  
  201. static int trunc_dindirect (struct inode * inode, int offset,
  202.                 u32 * p)
  203. {
  204.     int i, tmp;
  205.     struct buffer_head * dind_bh;
  206.     u32 * dind;
  207.     int retry = 0;
  208.     int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
  209.     int blocks = inode->i_sb->s_blocksize / 512;
  210. #define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block)
  211.     int dindirect_block = DINDIRECT_BLOCK;
  212.  
  213.     tmp = *p;
  214.     if (!tmp)
  215.         return 0;
  216.     dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
  217.     if (tmp != *p) {
  218.         brelse (dind_bh);
  219.         return 1;
  220.     }
  221.     if (!dind_bh) {
  222.         *p = 0;
  223.         return 0;
  224.     }
  225. repeat:
  226.     for (i = dindirect_block ; i < addr_per_block ; i++) {
  227.         if (i < 0)
  228.             i = 0;
  229.         if (i < dindirect_block)
  230.             goto repeat;
  231.         dind = i + (u32 *) dind_bh->b_data;
  232.         tmp = *dind;
  233.         if (!tmp)
  234.             continue;
  235.         retry |= trunc_indirect (inode, offset + (i * addr_per_block),
  236.                       dind);
  237.         mark_buffer_dirty(dind_bh, 1);
  238.     }
  239.     dind = (u32 *) dind_bh->b_data;
  240.     for (i = 0; i < addr_per_block; i++)
  241.         if (*(dind++))
  242.             break;
  243.     if (i >= addr_per_block)
  244.         if (dind_bh->b_count != 1)
  245.             retry = 1;
  246.         else {
  247.             tmp = *p;
  248.             *p = 0;
  249.             inode->i_blocks -= blocks;
  250.             inode->i_dirt = 1;
  251.             ext2_free_blocks (inode->i_sb, tmp, 1);
  252.         }
  253.     if (IS_SYNC(inode) && dind_bh->b_dirt) {
  254.         ll_rw_block (WRITE, 1, &dind_bh);
  255.         wait_on_buffer (dind_bh);
  256.     }
  257.     brelse (dind_bh);
  258.     return retry;
  259. }
  260.  
  261. static int trunc_tindirect (struct inode * inode)
  262. {
  263.     int i, tmp;
  264.     struct buffer_head * tind_bh;
  265.     u32 * tind, * p;
  266.     int retry = 0;
  267.     int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
  268.     int blocks = inode->i_sb->s_blocksize / 512;
  269. #define TINDIRECT_BLOCK (((int)DIRECT_BLOCK - (addr_per_block * addr_per_block + \
  270.               addr_per_block + EXT2_NDIR_BLOCKS)) / \
  271.               (addr_per_block * addr_per_block))
  272.     int tindirect_block = TINDIRECT_BLOCK;
  273.  
  274.     p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK;
  275.     if (!(tmp = *p))
  276.         return 0;
  277.     tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
  278.     if (tmp != *p) {
  279.         brelse (tind_bh);
  280.         return 1;
  281.     }
  282.     if (!tind_bh) {
  283.         *p = 0;
  284.         return 0;
  285.     }
  286. repeat:
  287.     for (i = tindirect_block ; i < addr_per_block ; i++) {
  288.         if (i < 0)
  289.             i = 0;
  290.         if (i < tindirect_block)
  291.             goto repeat;
  292.         tind = i + (u32 *) tind_bh->b_data;
  293.         retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
  294.             addr_per_block + (i + 1) * addr_per_block * addr_per_block,
  295.             tind);
  296.         mark_buffer_dirty(tind_bh, 1);
  297.     }
  298.     tind = (u32 *) tind_bh->b_data;
  299.     for (i = 0; i < addr_per_block; i++)
  300.         if (*(tind++))
  301.             break;
  302.     if (i >= addr_per_block)
  303.         if (tind_bh->b_count != 1)
  304.             retry = 1;
  305.         else {
  306.             tmp = *p;
  307.             *p = 0;
  308.             inode->i_blocks -= blocks;
  309.             inode->i_dirt = 1;
  310.             ext2_free_blocks (inode->i_sb, tmp, 1);
  311.         }
  312.     if (IS_SYNC(inode) && tind_bh->b_dirt) {
  313.         ll_rw_block (WRITE, 1, &tind_bh);
  314.         wait_on_buffer (tind_bh);
  315.     }
  316.     brelse (tind_bh);
  317.     return retry;
  318. }
  319.         
  320. void ext2_truncate (struct inode * inode)
  321. {
  322.     int retry;
  323.  
  324.     if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
  325.         S_ISLNK(inode->i_mode)))
  326.         return;
  327.     if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
  328.         return;
  329.     ext2_discard_prealloc(inode);
  330.     while (1) {
  331.         down(&inode->i_sem);
  332.         retry = trunc_direct(inode);
  333.         retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
  334.             (u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
  335.         retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
  336.             EXT2_ADDR_PER_BLOCK(inode->i_sb),
  337.             (u32 *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
  338.         retry |= trunc_tindirect (inode);
  339.         up(&inode->i_sem);
  340.         if (!retry)
  341.             break;
  342.         if (IS_SYNC(inode) && inode->i_dirt)
  343.             ext2_sync_inode (inode);
  344.         current->counter = 0;
  345.         schedule ();
  346.     }
  347.     inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  348.     inode->i_dirt = 1;
  349. }
  350.