Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/fs/iso9660/super.c 3 * 4 * Copyright 2018, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/types.h> 9 #include <fiwix/errno.h> 10 #include <fiwix/fs.h> 11 #include <fiwix/filesystems.h> 12 #include <fiwix/fs_iso9660.h> 13 #include <fiwix/buffer.h> 14 #include <fiwix/time.h> 15 #include <fiwix/sched.h> 16 #include <fiwix/mm.h> 17 #include <fiwix/stdio.h> 18 #include <fiwix/string.h> 19 20 struct fs_operations iso9660_fsop = { 21 FSOP_REQUIRES_DEV, 22 NULL, 23 24 NULL, /* open */ 25 NULL, /* close */ 26 NULL, /* read */ 27 NULL, /* write */ 28 NULL, /* ioctl */ 29 NULL, /* lseek */ 30 NULL, /* readdir */ 31 NULL, /* mmap */ 32 NULL, /* select */ 33 34 NULL, /* readlink */ 35 NULL, /* followlink */ 36 NULL, /* bmap */ 37 NULL, /* lookup */ 38 NULL, /* rmdir */ 39 NULL, /* link */ 40 NULL, /* unlink */ 41 NULL, /* symlink */ 42 NULL, /* mkdir */ 43 NULL, /* mknod */ 44 NULL, /* truncate */ 45 NULL, /* create */ 46 NULL, /* rename */ 47 48 NULL, /* read_block */ 49 NULL, /* write_block */ 50 51 iso9660_read_inode, 52 NULL, /* write_inode */ 53 NULL, /* ialloc */ 54 NULL, /* ifree */ 55 iso9660_statfs, 56 iso9660_read_superblock, 57 NULL, /* remount_fs */ 58 NULL, /* write_superblock */ 59 iso9660_release_superblock 60 }; 61 62 int isonum_711(char *str) 63 { 64 unsigned char *le; 65 66 le = (unsigned char *)str; 67 return le[0]; 68 } 69 70 /* return a 16bit little-endian number */ 71 int isonum_723(char *str) 72 { 73 unsigned char *le; 74 75 le = (unsigned char *)str; 76 return le[0] | (le[1] << 8); 77 } 78 79 /* return a 32bit little-endian number */ 80 int isonum_731(char *str) 81 { 82 unsigned char *le; 83 84 le = (unsigned char *)str; 85 return le[0] | (le[1] << 8) | (le[2] << 16) | (le[3] << 24); 86 } 87 88 /* return a 32bit little-endian number */ 89 int isonum_733(char *p) 90 { 91 return isonum_731(p); 92 } 93 94 /* return a date and time format */ 95 unsigned long int isodate(char *p) 96 { 97 struct mt mt; 98 99 if(!p[0]) { 100 return 0; 101 } 102 103 mt.mt_sec = p[5]; 104 mt.mt_min = p[4]; 105 mt.mt_hour = p[3]; 106 mt.mt_day = p[2]; 107 mt.mt_month = p[1]; 108 mt.mt_year = p[0]; 109 mt.mt_year += 1900; 110 mt.mt_min += p[6] * 15; 111 112 return mktime(&mt); 113 } 114 115 /* return a clean filename */ 116 int iso9660_cleanfilename(char *filename, int len) 117 { 118 int n; 119 char *p; 120 121 p = filename; 122 if(len > 2) { 123 for(n = 0; n < len; n++) { 124 if((len - n) == 2) { 125 if(p[n] == ';' && p[n + 1] == '1') { 126 filename[n] = NULL; 127 if(p[n - 1] == '.') { 128 filename[n - 1] = NULL; 129 } 130 return 0; 131 } 132 } 133 } 134 } 135 return 1; 136 } 137 138 void iso9660_statfs(struct superblock *sb, struct statfs *statfsbuf) 139 { 140 statfsbuf->f_type = ISO9660_SUPER_MAGIC; 141 statfsbuf->f_bsize = sb->s_blocksize; 142 statfsbuf->f_blocks = isonum_733(sb->u.iso9660.sb->volume_space_size); 143 statfsbuf->f_bfree = 0; 144 statfsbuf->f_bavail = 0; 145 statfsbuf->f_files = 0; /* FIXME */ 146 statfsbuf->f_ffree = 0; 147 /* statfsbuf->f_fsid = ? */ 148 statfsbuf->f_namelen = NAME_MAX; 149 } 150 151 int iso9660_read_superblock(__dev_t dev, struct superblock *sb) 152 { 153 struct buffer *buf; 154 struct iso9660_super_block *iso9660sb; 155 struct iso9660_super_block *pvd; 156 struct iso9660_directory_record *dr; 157 __ino_t root_inode; 158 int n; 159 160 superblock_lock(sb); 161 pvd = NULL; 162 163 for(n = 0; n < ISO9660_MAX_VD; n++) { 164 if(!(buf = bread(dev, ISO9660_SUPERBLOCK + n, BLKSIZE_2K))) { 165 superblock_unlock(sb); 166 return -EIO; 167 } 168 169 iso9660sb = (struct iso9660_super_block *)buf->data; 170 if(strncmp(iso9660sb->id, ISO9660_STANDARD_ID, sizeof(iso9660sb->id)) || (isonum_711(iso9660sb->type) == ISO9660_VD_END)) { 171 break; 172 } 173 if(isonum_711(iso9660sb->type) == ISO9660_VD_PRIMARY) { 174 pvd = (struct iso9660_super_block *)buf->data; 175 break; 176 } 177 brelse(buf); 178 } 179 if(!pvd) { 180 printk("WARNING: %s(): invalid filesystem type or bad superblock on device %d,%d.\n", __FUNCTION__, MAJOR(dev), MINOR(dev)); 181 superblock_unlock(sb); 182 brelse(buf); 183 return -EINVAL; 184 } 185 186 dr = (struct iso9660_directory_record *)pvd->root_directory_record; 187 root_inode = isonum_711(dr->extent); 188 189 sb->dev = dev; 190 sb->fsop = &iso9660_fsop; 191 sb->flags = MS_RDONLY; 192 sb->s_blocksize = isonum_723(pvd->logical_block_size); 193 sb->u.iso9660.rrip = 0; 194 if(!(sb->u.iso9660.sb = (void *)kmalloc())) { 195 superblock_unlock(sb); 196 brelse(buf); 197 return -ENOMEM; 198 } 199 memcpy_b(sb->u.iso9660.sb, pvd, sizeof(struct iso9660_super_block)); 200 brelse(buf); 201 202 root_inode = (root_inode << ISO9660_INODE_BITS) + (0 & ISO9660_INODE_MASK); 203 if(!(sb->root = iget(sb, root_inode))) { 204 printk("WARNING: %s(): unable to get root inode.\n", __FUNCTION__); 205 superblock_unlock(sb); 206 return -EINVAL; 207 } 208 sb->u.iso9660.s_root_inode = root_inode; 209 210 superblock_unlock(sb); 211 return 0; 212 } 213 214 void iso9660_release_superblock(struct superblock *sb) 215 { 216 kfree((unsigned int)sb->u.iso9660.sb); 217 kfree((unsigned int)sb->u.iso9660.pathtable); 218 kfree((unsigned int)sb->u.iso9660.pathtable_raw); 219 } 220 221 int iso9660_init(void) 222 { 223 return register_filesystem("iso9660", &iso9660_fsop); 224 }