Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/fs/iso9660/inode.c 3 * 4 * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/kernel.h> 9 #include <fiwix/types.h> 10 #include <fiwix/errno.h> 11 #include <fiwix/fs.h> 12 #include <fiwix/filesystems.h> 13 #include <fiwix/fs_iso9660.h> 14 #include <fiwix/fs_pipe.h> 15 #include <fiwix/buffer.h> 16 #include <fiwix/stat.h> 17 #include <fiwix/mm.h> 18 #include <fiwix/sched.h> 19 #include <fiwix/stdio.h> 20 #include <fiwix/string.h> 21 22 static int read_pathtable(struct inode *i) 23 { 24 int n, offset, pt_len, pt_blk; 25 struct iso9660_sb_info *sbi; 26 struct iso9660_pathtable_record *ptr; 27 struct buffer *buf; 28 29 sbi = (struct iso9660_sb_info *)&i->sb->u.iso9660; 30 pt_len = isonum_733(sbi->sb->path_table_size); 31 pt_blk = isonum_731(sbi->sb->type_l_path_table); 32 33 if(pt_len > PAGE_SIZE) { 34 printk("WARNING: %s(): path table record size (%d) > 4096, not supported yet.\n", __FUNCTION__, pt_len); 35 return -EINVAL; 36 } 37 38 if(!(sbi->pathtable_raw = (void *)kmalloc())) { 39 return -ENOMEM; 40 } 41 offset = 0; 42 while(offset < pt_len) { 43 if(!(buf = bread(i->dev, pt_blk++, BLKSIZE_2K))) { 44 kfree((unsigned int)sbi->pathtable_raw); 45 return -EIO; 46 } 47 memcpy_b(sbi->pathtable_raw + offset, (void *)buf->data, MIN(pt_len - offset, BLKSIZE_2K)); 48 offset += MIN(pt_len - offset, BLKSIZE_2K); 49 brelse(buf); 50 } 51 52 /* allocate and count the number of records in the Path Table */ 53 offset = n = 0; 54 if(!(sbi->pathtable = (struct iso9660_pathtable_record **)kmalloc())) { 55 kfree((unsigned int)sbi->pathtable_raw); 56 return -ENOMEM; 57 } 58 sbi->pathtable[n] = NULL; 59 while(offset < pt_len) { 60 ptr = (struct iso9660_pathtable_record *)(sbi->pathtable_raw + offset); 61 sbi->pathtable[++n] = ptr; 62 offset += sizeof(struct iso9660_pathtable_record) + isonum_711(ptr->length) + (isonum_711(ptr->length) & 1); 63 } 64 sbi->paths = n; 65 66 return 0; 67 } 68 69 static int get_parent_dir_size(struct superblock *sb, __blk_t extent) 70 { 71 int n; 72 struct iso9660_pathtable_record *ptr; 73 __blk_t parent; 74 75 for(n = 0; n < sb->u.iso9660.paths; n++) { 76 ptr = (struct iso9660_pathtable_record *)sb->u.iso9660.pathtable[n]; 77 if(isonum_731(ptr->extent) == extent) { 78 79 parent = isonum_723(ptr->parent); 80 ptr = (struct iso9660_pathtable_record *)sb->u.iso9660.pathtable[parent]; 81 parent = isonum_731(ptr->extent); 82 return parent; 83 } 84 } 85 printk("WARNING: %s(): unable to locate extent '%d' in path table.\n", __FUNCTION__, extent); 86 return 0; 87 } 88 89 int iso9660_read_inode(struct inode *i) 90 { 91 int errno; 92 __u32 blksize; 93 struct superblock *sb; 94 struct iso9660_directory_record *d; 95 struct buffer *buf; 96 __blk_t dblock; 97 __off_t doffset; 98 99 sb = (struct superblock *)i->sb; 100 if(!sb->u.iso9660.pathtable) { 101 if((errno = read_pathtable(i))) { 102 return errno; 103 } 104 } 105 106 dblock = (i->inode & ~ISO9660_INODE_MASK) >> ISO9660_INODE_BITS; 107 doffset = i->inode & ISO9660_INODE_MASK; 108 blksize = i->sb->s_blocksize; 109 110 /* FIXME: it only looks in one directory block */ 111 if(!(buf = bread(i->dev, dblock, blksize))) { 112 return -EIO; 113 } 114 115 if(doffset >= blksize) { 116 printk("WARNING: %s(): inode %d (dblock=%d, doffset=%d) not found in directory entry.\n", __FUNCTION__, i->inode, dblock, doffset); 117 brelse(buf); 118 return -EIO; 119 } 120 d = (struct iso9660_directory_record *)(buf->data + doffset); 121 122 i->i_mode = S_IFREG; 123 if((char)d->flags[0] & ISO9660_FILE_ISDIR) { 124 i->i_mode = S_IFDIR; 125 } 126 if(!((char)d->flags[0] & ISO9660_FILE_HASOWNER)) { 127 i->i_mode |= S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; 128 } 129 i->i_uid = 0; 130 i->i_size = isonum_733(d->size); 131 i->i_atime = isodate(d->date); 132 i->i_ctime = isodate(d->date); 133 i->i_mtime = isodate(d->date); 134 i->i_gid = 0; 135 i->i_nlink = 1; 136 i->count = 1; 137 138 i->u.iso9660.i_extent = isonum_733(d->extent); 139 check_rrip_inode(d, i); 140 brelse(buf); 141 142 switch(i->i_mode & S_IFMT) { 143 case S_IFCHR: 144 i->fsop = &def_chr_fsop; 145 break; 146 case S_IFBLK: 147 i->fsop = &def_blk_fsop; 148 break; 149 case S_IFIFO: 150 i->fsop = &pipefs_fsop; 151 /* it's a union so we need to clear pipefs_inode */ 152 memset_b(&i->u.pipefs, NULL, sizeof(struct pipefs_inode)); 153 break; 154 case S_IFDIR: 155 i->fsop = &iso9660_dir_fsop; 156 i->i_nlink++; 157 break; 158 case S_IFREG: 159 i->fsop = &iso9660_file_fsop; 160 break; 161 case S_IFLNK: 162 i->fsop = &iso9660_symlink_fsop; 163 break; 164 case S_IFSOCK: 165 i->fsop = NULL; 166 break; 167 default: 168 PANIC("invalid inode (%d) mode %08o.\n", i->inode, i->i_mode); 169 } 170 return 0; 171 } 172 173 int iso9660_bmap(struct inode *i, __off_t offset, int mode) 174 { 175 __blk_t block; 176 177 block = i->u.iso9660.i_extent + (offset / i->sb->s_blocksize); 178 return block; 179 }