home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / fs / minix / truncate.c < prev   
Encoding:
C/C++ Source or Header  |  1993-12-27  |  3.8 KB  |  185 lines

  1. /*
  2.  *  linux/fs/truncate.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6.  
  7. #include <linux/errno.h>
  8. #include <linux/sched.h>
  9. #include <linux/minix_fs.h>
  10. #include <linux/stat.h>
  11. #include <linux/fcntl.h>
  12.  
  13. /*
  14.  * Truncate has the most races in the whole filesystem: coding it is
  15.  * a pain in the a**. Especially as I don't do any locking...
  16.  *
  17.  * The code may look a bit weird, but that's just because I've tried to
  18.  * handle things like file-size changes in a somewhat graceful manner.
  19.  * Anyway, truncating a file at the same time somebody else writes to it
  20.  * is likely to result in pretty weird behaviour...
  21.  *
  22.  * The new code handles normal truncates (size = 0) as well as the more
  23.  * general case (size = XXX). I hope.
  24.  */
  25.  
  26. static int trunc_direct(struct inode * inode)
  27. {
  28.     unsigned short * p;
  29.     struct buffer_head * bh;
  30.     int i, tmp;
  31.     int retry = 0;
  32. #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
  33.  
  34. repeat:
  35.     for (i = DIRECT_BLOCK ; i < 7 ; i++) {
  36.         p = i + inode->u.minix_i.i_data;
  37.         if (!(tmp = *p))
  38.             continue;
  39.         bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
  40.         if (i < DIRECT_BLOCK) {
  41.             brelse(bh);
  42.             goto repeat;
  43.         }
  44.         if ((bh && bh->b_count != 1) || tmp != *p) {
  45.             retry = 1;
  46.             brelse(bh);
  47.             continue;
  48.         }
  49.         *p = 0;
  50.         inode->i_dirt = 1;
  51.         brelse(bh);
  52.         minix_free_block(inode->i_sb,tmp);
  53.     }
  54.     return retry;
  55. }
  56.  
  57. static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
  58. {
  59.     struct buffer_head * bh;
  60.     int i, tmp;
  61.     struct buffer_head * ind_bh;
  62.     unsigned short * ind;
  63.     int retry = 0;
  64. #define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
  65.  
  66.     tmp = *p;
  67.     if (!tmp)
  68.         return 0;
  69.     ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  70.     if (tmp != *p) {
  71.         brelse(ind_bh);
  72.         return 1;
  73.     }
  74.     if (!ind_bh) {
  75.         *p = 0;
  76.         return 0;
  77.     }
  78. repeat:
  79.     for (i = INDIRECT_BLOCK ; i < 512 ; i++) {
  80.         if (i < 0)
  81.             i = 0;
  82.         if (i < INDIRECT_BLOCK)
  83.             goto repeat;
  84.         ind = i+(unsigned short *) ind_bh->b_data;
  85.         tmp = *ind;
  86.         if (!tmp)
  87.             continue;
  88.         bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
  89.         if (i < INDIRECT_BLOCK) {
  90.             brelse(bh);
  91.             goto repeat;
  92.         }
  93.         if ((bh && bh->b_count != 1) || tmp != *ind) {
  94.             retry = 1;
  95.             brelse(bh);
  96.             continue;
  97.         }
  98.         *ind = 0;
  99.         ind_bh->b_dirt = 1;
  100.         brelse(bh);
  101.         minix_free_block(inode->i_sb,tmp);
  102.     }
  103.     ind = (unsigned short *) ind_bh->b_data;
  104.     for (i = 0; i < 512; i++)
  105.         if (*(ind++))
  106.             break;
  107.     if (i >= 512)
  108.         if (ind_bh->b_count != 1)
  109.             retry = 1;
  110.         else {
  111.             tmp = *p;
  112.             *p = 0;
  113.             minix_free_block(inode->i_sb,tmp);
  114.         }
  115.     brelse(ind_bh);
  116.     return retry;
  117. }
  118.         
  119. static int trunc_dindirect(struct inode * inode)
  120. {
  121.     int i, tmp;
  122.     struct buffer_head * dind_bh;
  123.     unsigned short * dind, * p;
  124.     int retry = 0;
  125. #define DINDIRECT_BLOCK ((DIRECT_BLOCK-(512+7))>>9)
  126.  
  127.     p = 8 + inode->u.minix_i.i_data;
  128.     if (!(tmp = *p))
  129.         return 0;
  130.     dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  131.     if (tmp != *p) {
  132.         brelse(dind_bh);
  133.         return 1;
  134.     }
  135.     if (!dind_bh) {
  136.         *p = 0;
  137.         return 0;
  138.     }
  139. repeat:
  140.     for (i = DINDIRECT_BLOCK ; i < 512 ; i ++) {
  141.         if (i < 0)
  142.             i = 0;
  143.         if (i < DINDIRECT_BLOCK)
  144.             goto repeat;
  145.         dind = i+(unsigned short *) dind_bh->b_data;
  146.         retry |= trunc_indirect(inode,7+512+(i<<9),dind);
  147.         dind_bh->b_dirt = 1;
  148.     }
  149.     dind = (unsigned short *) dind_bh->b_data;
  150.     for (i = 0; i < 512; i++)
  151.         if (*(dind++))
  152.             break;
  153.     if (i >= 512)
  154.         if (dind_bh->b_count != 1)
  155.             retry = 1;
  156.         else {
  157.             tmp = *p;
  158.             *p = 0;
  159.             inode->i_dirt = 1;
  160.             minix_free_block(inode->i_sb,tmp);
  161.         }
  162.     brelse(dind_bh);
  163.     return retry;
  164. }
  165.         
  166. void minix_truncate(struct inode * inode)
  167. {
  168.     int retry;
  169.  
  170.     if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
  171.          S_ISLNK(inode->i_mode)))
  172.         return;
  173.     while (1) {
  174.         retry = trunc_direct(inode);
  175.         retry |= trunc_indirect(inode,7,inode->u.minix_i.i_data+7);
  176.         retry |= trunc_dindirect(inode);
  177.         if (!retry)
  178.             break;
  179.         current->counter = 0;
  180.         schedule();
  181.     }
  182.     inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  183.     inode->i_dirt = 1;
  184. }
  185.