root/fs/affs/inode.c

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

DEFINITIONS

This source file includes following definitions.
  1. affs_put_super
  2. affs_parent_ino
  3. parse_options
  4. get_device_size
  5. affs_read_super
  6. affs_statfs
  7. affs_read_inode
  8. leak_check_malloc
  9. leak_check_free_s
  10. leak_check_bread
  11. leak_check_brelse

   1 /*
   2  *  linux/fs/affs/inode.c
   3  *
   4  *  (C) 1994  Geert Uytterhoeven - Modified for MultiUserFileSystem
   5  *
   6  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
   7  *
   8  *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
   9  *
  10  *  (C) 1991  Linus Torvalds - minix filesystem
  11  */
  12 
  13 #include <linux/stat.h>
  14 #include <linux/sched.h>
  15 #include <linux/affs_fs.h>
  16 #include <linux/kernel.h>
  17 #include <linux/mm.h>
  18 #include <linux/string.h>
  19 #include <linux/locks.h>
  20 
  21 #include <asm/system.h>
  22 #include <asm/segment.h>
  23 #include <linux/errno.h>
  24 
  25 #include <linux/genhd.h>
  26 
  27 #include "amigaffs.h"
  28 
  29 extern int check_cdrom_media_change(int, int);
  30 
  31 #ifdef LEAK_CHECK
  32 static int check_malloc = 0;
  33 static int check_bread = 0;
  34 #endif
  35 
  36 void affs_put_super(struct super_block *sb)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38         lock_super(sb);
  39 
  40 #ifdef LEAK_CHECK
  41         printk("Outstanding mallocs:%d, outstanding buffers: %d\n",
  42                check_malloc, check_bread);
  43 #endif
  44         sb->s_dev = 0;
  45         unlock_super(sb);
  46         return;
  47 }
  48 
  49 static struct super_operations affs_sops = {
  50         affs_read_inode,
  51         NULL,                   /* notify_change */
  52         NULL,                   /* write_inode */
  53         NULL,                   /* put_inode */
  54         affs_put_super,
  55         NULL,                   /* write_super */
  56         affs_statfs,
  57         NULL                    /* remount */
  58 };
  59 
  60 int affs_parent_ino(struct inode *dir)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62         int root_ino = (dir->i_sb->u.affs_sb.s_root_block
  63                         - dir->i_sb->u.affs_sb.s_partition_offset);
  64 
  65         if (!S_ISDIR (dir->i_mode)) {
  66                 printk ("affs_parent_ino: argument is not a directory\n");
  67                 return root_ino;
  68         }
  69         if (dir->i_ino == root_ino)
  70                 return root_ino;
  71         return dir->u.affs_i.i_parent;
  72 }
  73 
  74 static int parse_options(char *options, struct affs_options *optp)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76         char *this_opt,*value,*end;
  77         int n;
  78 
  79         optp->offset = 0;
  80         optp->size = 0;
  81         optp->root = 0;
  82         optp->conv_links = 0;
  83 
  84         if (!options)
  85                 return 1;
  86         for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,",")) {
  87                 if ((value = strchr(this_opt,'='))) *value++ = 0;
  88 
  89                 if (!strcmp(this_opt,"offset") && value) {
  90                         n = simple_strtoul (value, &end, 10);
  91                         if (end == value || *end != 0)
  92                                 return 0;
  93                         optp->offset = n;
  94                 }
  95                 else if (!strcmp(this_opt,"size") && value) {
  96                         n = simple_strtoul (value, &end, 10);
  97                         if (end == value || *end != 0 || n <= 0)
  98                                 return 0;
  99                         optp->size = n;
 100                 }
 101                 else if (!strcmp(this_opt,"root") && value) {
 102                         n = simple_strtoul (value, &end, 10);
 103                         if (end == value || *end != 0 || n <= 0)
 104                                 return 0;
 105                         optp->root = n;
 106                 }
 107                 else if (!strcmp(this_opt,"conv_symlinks")) {
 108                         optp->conv_links = 1;
 109                 }
 110                 else return 0;
 111         }
 112         return 1;
 113 }
 114 
 115 /* Is this The Right Way?  Should I be locking something? */
 116 
 117 static int get_device_size (dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 118 {
 119         struct gendisk *gd_p;
 120         int dev_size = 0;
 121 
 122         for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) {
 123                 if (gd_p->major != MAJOR(dev))
 124                         continue;
 125                 dev_size = gd_p->part[MINOR(dev)].nr_sects;
 126                 break;
 127         }
 128         return dev_size;
 129 }
 130 
 131 struct super_block *affs_read_super(struct super_block *s,void *data,
     /* [previous][next][first][last][top][bottom][index][help] */
 132                                     int silent)
 133 {
 134         struct buffer_head *bh;
 135         int dev = s->s_dev;
 136         int root_block;
 137         int ptype, stype;
 138         void *root_data;
 139         struct affs_options *optp;
 140 
 141         optp = &s->u.affs_sb.s_options;
 142 
 143         if (!parse_options((char *) data, optp)) {
 144                 s->s_dev = 0;
 145                 printk ("AFFS: bad mount options\n");
 146                 return NULL;
 147         }
 148 
 149         lock_super(s);
 150 
 151         root_block = 0;
 152         if (optp->size) {
 153                 s->u.affs_sb.s_partition_size = optp->size;
 154         }
 155         else {
 156                 int size = get_device_size (dev);
 157                 if (size == 0) {
 158                         s->s_dev = 0;
 159                         unlock_super(s);
 160                         printk ("affs_read_super: could not"
 161                                 "determine device size\n");
 162                 }
 163                 s->u.affs_sb.s_partition_size = size;
 164         }
 165 
 166         s->u.affs_sb.s_partition_offset = optp->offset;
 167         root_block = optp->root;
 168 
 169         if (!root_block)
 170                 root_block = (s->u.affs_sb.s_partition_offset
 171                               + s->u.affs_sb.s_partition_size / 2
 172                               + (s->u.affs_sb.s_partition_size & 1));
 173         s->u.affs_sb.s_root_block = root_block;
 174 
 175         s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE;
 176 
 177 #if 0
 178         printk ("affs_read_super: dev=0x%04x offset=%d "
 179                 "size=%d root=%d blocksize=%d\n",
 180                 dev,
 181                 s->u.affs_sb.s_partition_offset,
 182                 s->u.affs_sb.s_partition_size,
 183                 s->u.affs_sb.s_root_block,
 184                 s->u.affs_sb.s_block_size);
 185 #endif
 186 
 187         bh = affs_sread (dev, root_block, &root_data);
 188         if (!bh) {
 189                 s->s_dev = 0;
 190                 unlock_super(s);
 191                 printk ("AFFS: unable to read superblock\n");
 192                 return NULL;
 193         }
 194 
 195         if (affs_checksum_block (AFFS_BLOCK_SIZE, root_data, &ptype, &stype)
 196             || ptype != T_SHORT || stype != ST_ROOT) {
 197                 printk ("AFFS: invalid root block %d on device 0x%04x\n",
 198                         root_block, dev);
 199                 goto out;
 200         }
 201 
 202 #if 1
 203 {
 204         char *name;
 205         int len;
 206         char buf[33];
 207         len = affs_get_file_name (AFFS_BLOCK_SIZE, root_data, &name);
 208         memcpy (buf,name,len);
 209         buf[len] = 0;
 210 #if 0
 211         printk ("affs_read_super: volume name \"%s\"\n", buf);
 212 #endif
 213 }
 214 #endif
 215 
 216         s->s_magic = AFFS_SUPER_MAGIC;
 217 
 218         s->s_flags = MS_RDONLY | MS_NODEV | MS_NOSUID;
 219 
 220         brelse(bh);
 221 
 222         /* set up enough so that it can read an inode */
 223         s->s_dev = dev;
 224         s->s_op = &affs_sops;
 225         s->s_blocksize = AFFS_BUFFER_SIZE;
 226         s->s_mounted = iget (s, root_block - s->u.affs_sb.s_partition_offset);
 227 
 228         unlock_super(s);
 229 
 230         if (!(s->s_mounted)) {
 231                 s->s_dev = 0;
 232                 printk("AFFS: get root inode failed\n");
 233                 return NULL;
 234         }
 235 
 236         return s;
 237 
 238  out: /* Kick out for various error conditions */
 239         brelse (bh);
 240         s->s_dev = 0;
 241         unlock_super(s);
 242         return NULL;
 243 }
 244 
 245 void affs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247 #ifdef DEBUG
 248         printk ("AFFS: affs_statfs called\n");
 249 #endif
 250         put_fs_long(AFFS_SUPER_MAGIC, &buf->f_type);
 251         put_fs_long(sb->u.affs_sb.s_block_size, &buf->f_bsize);
 252         put_fs_long(sb->u.affs_sb.s_partition_size, &buf->f_blocks);
 253         put_fs_long(0, &buf->f_bfree);
 254         put_fs_long(0, &buf->f_bavail);
 255         put_fs_long(0, &buf->f_files);
 256         put_fs_long(0, &buf->f_ffree);
 257         /* Don't know what value to put in buf->f_fsid */
 258 }
 259 
 260 static int prot_table[9][2] = {
 261         {PROT_OTR_EXECUTE, PROT_OTR_EXECUTE},   /* other: 1 = allowed */
 262         {PROT_OTR_WRITE, PROT_OTR_WRITE},
 263         {PROT_OTR_READ, PROT_OTR_READ},
 264         {PROT_GRP_EXECUTE, PROT_GRP_EXECUTE},   /* group: 1 = allowed */
 265         {PROT_GRP_WRITE, PROT_GRP_WRITE},
 266         {PROT_GRP_READ, PROT_GRP_READ},
 267         {PROT_EXECUTE, 0},                      /* owner: 0 = allowed */
 268         {PROT_WRITE, 0},
 269         {PROT_READ, 0}
 270 };
 271 
 272 void affs_read_inode(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 273 {
 274         struct buffer_head *bh;
 275         int block;
 276         void *fh_data;
 277         struct file_front *file_front;
 278         struct file_end *file_end;
 279         int i;
 280         struct hardlink_end *link_end;
 281         int link;       
 282 
 283 #ifdef DEBUG
 284         printk ("AFFS: entering affs_read_inode\n");
 285 #endif
 286 
 287         inode->i_nlink = 1; /* at least */
 288         do {
 289                 link = 0;
 290                 block = inode->i_ino;
 291                 if (!(bh=affs_pread (inode, block, &fh_data))) {
 292                         printk("AFFS: unable to read i-node block %d\n", block);
 293                         return;
 294                 }
 295 
 296                 file_front = (struct file_front *) fh_data;
 297                 file_end = GET_END_PTR (struct file_end, fh_data, /* coincidendly the same as  dir_end */
 298                                         AFFS_I2BSIZE (inode));
 299 
 300                 /* don't use bitmap data for mode, uid & gid of the rootblock */
 301                 if (block == inode->i_sb->u.affs_sb.s_root_block) {
 302                         inode->u.affs_i.i_protect = 0;
 303                         inode->u.affs_i.i_parent = block;
 304 
 305                         inode->i_mode = S_IRWXUGO | S_IFDIR | S_ISVTX ;  /* drwxrwxrwt */
 306                         inode->i_nlink = 2; /* at least ..... */
 307 
 308                         inode->i_size = 0;  /* some differrent idea ? */
 309 
 310                         inode->i_uid = 0;
 311                         inode->i_gid = 0;
 312                 }
 313                 else { 
 314 
 315                         inode->u.affs_i.i_protect = file_end->protect;
 316                         inode->u.affs_i.i_parent = swap_long (file_end->parent);
 317 
 318                         inode->i_mode = 0;
 319                         for (i = 0; i < 9; i++)
 320                                 if ((prot_table[i][0] & inode->u.affs_i.i_protect) == prot_table[i][1])
 321                                         inode->i_mode |= 1<<i;
 322                         switch(swap_long(file_end->secondary_type)) {
 323                                 case ST_USERDIR:
 324                                         inode->i_mode |= ((inode->i_mode & 0444)>>2) | S_IFDIR;
 325 
 326                                         inode->i_nlink++; /* There are always at least 2.  It is
 327                                                                hard to figure out what is correct*/
 328                                         inode->i_size = 0;
 329                                 break;
 330                                 case ST_SOFTLINK:
 331                                         inode->i_mode |= S_IFLNK;
 332                                         inode->i_size  = 0;
 333                                 break;
 334                                 case ST_LINKFILE:   /* doing things very easy (not really correct) */
 335                                 case ST_LINKDIR:    /* code is _very_ inefficient (see below) */
 336 
 337                                   /* Where is struct link_end defined?
 338                                      ... I don't know what is going on
 339                                      here, someone else should
 340                                      probably spend some time on this */
 341                                         link_end = (struct hardlink_end *)file_end;
 342                                         inode->i_ino = link_end->original;
 343                                         inode->i_nlink += 2; /* It's hard to say whats correct */
 344                                         brelse(bh);
 345                                         link = 1;
 346                                 break;
 347                                 default:
 348                                         printk("affs: unknown secondary type %ld; assuming file\n",
 349                                                 file_end->secondary_type);
 350                                 case ST_FILE:
 351                                         inode->i_mode |= S_IFREG;
 352                                         inode->i_size = swap_long (file_end->byte_size);
 353                                 break;
 354                                 }
 355                         if (file_end->uid == 0xffff)
 356                                 inode->i_uid = 0;       /* root uid */
 357                         else if (file_end->uid == 0x0000) {
 358                                 umode_t mode;
 359                                 inode->i_uid = -1;      /* unknown uid */
 360 
 361                                 /*
 362                                  * change the mode of the inode to duplicate the
 363                                  * perms of the user in the group and other fields;
 364                                  * the assumption is that this isn't a MultiUser
 365                                  * filesystem/file, so the permissions should be
 366                                  * the same for all users
 367                                  */
 368                                 mode = (inode->i_mode >> 6) & 7;
 369                                 inode->i_mode |= (mode << 3) | (mode);
 370                         } else
 371                                 inode->i_uid = file_end->uid;
 372                         if (file_end->gid == 0xffff)
 373                                 inode->i_gid = 0;       /* root gid */
 374                         else if (file_end->gid == 0x0000)
 375                                 inode->i_gid = -1;      /* unknown gid */
 376                         else
 377                                 inode->i_gid = file_end->gid;
 378                 }
 379         }
 380         while (link);
 381 
 382 #ifdef DEBUG
 383         printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size);
 384 #endif
 385         inode->i_mtime = inode->i_atime = inode->i_ctime
 386                 = (swap_long (file_end->created.ds_Days) * (24 * 60 * 60)
 387                    + swap_long (file_end->created.ds_Minute) * 60
 388                    + swap_long (file_end->created.ds_Tick) / 50
 389                    + ((8 * 365 + 2) * 24 * 60 * 60));
 390 
 391         brelse(bh);
 392 
 393         inode->i_op = NULL;
 394         if (S_ISREG(inode->i_mode))
 395                 inode->i_op = &affs_file_inode_operations;
 396         else if (S_ISDIR(inode->i_mode))
 397                 inode->i_op = &affs_dir_inode_operations;
 398         else if (S_ISLNK(inode->i_mode))
 399                 inode->i_op = &affs_symlink_inode_operations;
 400 }
 401 
 402 
 403 #ifdef LEAK_CHECK
 404 #undef malloc
 405 #undef free_s
 406 #undef bread
 407 #undef brelse
 408 
 409 void * leak_check_malloc(unsigned int size){
     /* [previous][next][first][last][top][bottom][index][help] */
 410   void * tmp;
 411   check_malloc++;
 412   tmp = kmalloc(size, GFP_ATOMIC);
 413   return tmp;
 414 }
 415 
 416 void leak_check_free_s(void * obj, int size){
     /* [previous][next][first][last][top][bottom][index][help] */
 417   check_malloc--;
 418   return kfree_s(obj, size);
 419 }
 420 
 421 struct buffer_head * leak_check_bread(int dev, int block, int size){
     /* [previous][next][first][last][top][bottom][index][help] */
 422   check_bread++;
 423   return bread(dev, block, size);
 424 }
 425 
 426 void leak_check_brelse(struct buffer_head * bh){
     /* [previous][next][first][last][top][bottom][index][help] */
 427   check_bread--;
 428   return brelse(bh);
 429 }
 430 
 431 #endif

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