root/fs/minix/truncate.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. trunc_direct
  2. trunc_indirect
  3. trunc_dindirect
  4. minix_truncate
  5. minix_release
  6. check_char_dev
  7. minix_open

   1 /*
   2  *  linux/fs/truncate.c
   3  *
   4  *  (C) 1991  Linus Torvalds
   5  */
   6 
   7 #include <linux/sched.h>
   8 #include <linux/minix_fs.h>
   9 #include <linux/tty.h>
  10 
  11 #include <errno.h>
  12 #include <fcntl.h>
  13 #include <sys/stat.h>
  14 
  15 /*
  16  * Truncate has the most races in the whole filesystem: coding it is
  17  * a pain in the a**. Especially as I don't do any locking...
  18  *
  19  * The code may look a bit weird, but that's just because I've tried to
  20  * handle things like file-size changes in a somewhat graceful manner.
  21  * Anyway, truncating a file at the same time somebody else writes to it
  22  * is likely to result in pretty weird behaviour...
  23  *
  24  * The new code handles normal truncates (size = 0) as well as the more
  25  * general case (size = XXX). I hope.
  26  */
  27 
  28 static int trunc_direct(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  29 {
  30         int i;
  31         int result = 0;
  32 #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
  33 
  34 repeat:
  35         for (i = DIRECT_BLOCK ; i < 7 ; i++) {
  36                 if (i < DIRECT_BLOCK)
  37                         goto repeat;
  38                 if (!inode->i_data[i])
  39                         continue;
  40                 result = 1;
  41                 if (minix_free_block(inode->i_dev,inode->i_data[i]))
  42                         inode->i_data[i] = 0;
  43         }
  44         return result;
  45 }
  46 
  47 static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49         int i;
  50         struct buffer_head * bh = NULL;
  51         unsigned short * ind;
  52         int result = 0;
  53 #define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
  54 
  55         if (*p)
  56                 bh = bread(inode->i_dev,*p);
  57         if (!bh)
  58                 return 0;
  59 repeat:
  60         for (i = INDIRECT_BLOCK ; i < 512 ; i++) {
  61                 if (i < 0)
  62                         i = 0;
  63                 if (i < INDIRECT_BLOCK)
  64                         goto repeat;
  65                 ind = i+(unsigned short *) bh->b_data;
  66                 if (!*ind)
  67                         continue;
  68                 result = 1;
  69                 if (minix_free_block(inode->i_dev,*ind))
  70                         *ind = 0;
  71         }
  72         ind = (unsigned short *) bh->b_data;
  73         for (i = 0; i < 512; i++)
  74                 if (*(ind++))
  75                         break;
  76         brelse(bh);
  77         if (i >= 512) {
  78                 result = 1;
  79                 if (minix_free_block(inode->i_dev,*p))
  80                         *p = 0;
  81         }
  82         return result;
  83 }
  84                 
  85 static int trunc_dindirect(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87         int i;
  88         struct buffer_head * bh = NULL;
  89         unsigned short * dind;
  90         int result = 0;
  91 #define DINDIRECT_BLOCK ((DIRECT_BLOCK-(512+7))>>9)
  92 
  93         if (inode->i_data[8])
  94                 bh = bread(inode->i_dev,inode->i_data[8]);
  95         if (!bh)
  96                 return 0;
  97 repeat:
  98         for (i = DINDIRECT_BLOCK ; i < 512 ; i ++) {
  99                 if (i < 0)
 100                         i = 0;
 101                 if (i < DINDIRECT_BLOCK)
 102                         goto repeat;
 103                 dind = i+(unsigned short *) bh->b_data;
 104                 if (!*dind)
 105                         continue;
 106                 result |= trunc_indirect(inode,7+512+(i<<9),dind);
 107         }
 108         dind = (unsigned short *) bh->b_data;
 109         for (i = 0; i < 512; i++)
 110                 if (*(dind++))
 111                         break;
 112         brelse(bh);
 113         if (i >= 512) {
 114                 result = 1;
 115                 if (minix_free_block(inode->i_dev,inode->i_data[8]))
 116                         inode->i_data[8] = 0;
 117         }
 118         return result;
 119 }
 120                 
 121 void minix_truncate(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123         int flag;
 124 
 125         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 126              S_ISLNK(inode->i_mode)))
 127                 return;
 128         if (inode->i_data[7] & 0xffff0000)
 129                 printk("BAD! minix inode has 16 high bits set\n");
 130         while (1) {
 131                 flag = trunc_direct(inode);
 132                 flag |= trunc_indirect(inode,7,(unsigned short *)&inode->i_data[7]);
 133                 flag |= trunc_dindirect(inode);
 134                 if (!flag)
 135                         break;
 136                 current->counter = 0;
 137                 schedule();
 138         }
 139         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 140         inode->i_dirt = 1;
 141 }
 142 
 143 /*
 144  * Called when a inode is released. Note that this is different
 145  * from minix_open: open gets called at every open, but release
 146  * gets called only when /all/ the files are closed.
 147  */
 148 void minix_release(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150         printk("minix_release not implemented\n");
 151 }
 152 
 153 static int check_char_dev(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 154 {
 155         struct tty_struct *tty;
 156         int min, dev;
 157 
 158         dev = inode->i_rdev;
 159         if (MAJOR(dev) == 4 || MAJOR(dev) == 5) {
 160                 if (MAJOR(dev) == 5)
 161                         min = current->tty;
 162                 else
 163                         min = MINOR(dev);
 164                 if (min < 0)
 165                         return -1;
 166                 if ((IS_A_PTY_MASTER(min)) && (inode->i_count>1))
 167                         return -1;
 168                 tty = TTY_TABLE(min);
 169                 if (!(filp->f_flags & O_NOCTTY) &&
 170                     current->leader &&
 171                     current->tty<0 &&
 172                     tty->session==0) {
 173                         current->tty = min;
 174                         tty->session= current->session;
 175                         tty->pgrp = current->pgrp;
 176                 }
 177                 if (IS_A_SERIAL(min))
 178                         serial_open(min-64);
 179         }
 180         return 0;
 181 }
 182 
 183 /*
 184  * Called every time a minix-file is opened
 185  */
 186 int minix_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 187 {
 188         if (S_ISCHR(inode->i_mode)) {
 189                 if (check_char_dev(inode,filp))
 190                         return -EAGAIN;
 191         } else if (S_ISBLK(inode->i_mode))
 192                 check_disk_change(inode->i_rdev);
 193         else if (S_ISREG(inode->i_mode))
 194                 filp->f_op = &minix_file_operations;
 195         else if (S_ISDIR(inode->i_mode))
 196                 filp->f_op = &minix_dir_operations;
 197         return 0;
 198 }

/* [previous][next][first][last][top][bottom][index][help] */