Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/fs/minix/v1_inode.c 3 * 4 * Copyright 2018, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/kernel.h> 9 #include <fiwix/fs.h> 10 #include <fiwix/filesystems.h> 11 #include <fiwix/fs_minix.h> 12 #include <fiwix/fs_pipe.h> 13 #include <fiwix/statfs.h> 14 #include <fiwix/sleep.h> 15 #include <fiwix/stat.h> 16 #include <fiwix/sched.h> 17 #include <fiwix/buffer.h> 18 #include <fiwix/process.h> 19 #include <fiwix/errno.h> 20 #include <fiwix/stdio.h> 21 #include <fiwix/string.h> 22 23 #define BLOCKS_PER_IND_BLOCK(sb) (sb->s_blocksize / sizeof(__u16)) 24 #define MINIX_INODES_PER_BLOCK(sb) (sb->s_blocksize / sizeof(struct minix_inode)) 25 26 #define MINIX_NDIR_BLOCKS 7 27 #define MINIX_IND_BLOCK MINIX_NDIR_BLOCKS 28 #define MINIX_DIND_BLOCK (MINIX_NDIR_BLOCKS + 1) 29 30 static void free_zone(struct inode *i, int block, int offset) 31 { 32 int n; 33 struct buffer *buf; 34 __u16 *zone; 35 36 if(!(buf = bread(i->dev, block, i->sb->s_blocksize))) { 37 printk("WARNING: %s(): error reading block %d.\n", __FUNCTION__, block); 38 return; 39 } 40 zone = (__u16 *)buf->data; 41 for(n = offset; n < BLOCKS_PER_IND_BLOCK(i->sb); n++) { 42 if(zone[n]) { 43 minix_bfree(i->sb, zone[n]); 44 zone[n] = 0; 45 } 46 } 47 bwrite(buf); 48 } 49 50 int v1_minix_read_inode(struct inode *i) 51 { 52 __ino_t block; 53 short int offset; 54 struct minix_inode *ii; 55 struct buffer *buf; 56 int errno; 57 58 block = 1 + SUPERBLOCK + i->sb->u.minix.sb.s_imap_blocks + i->sb->u.minix.sb.s_zmap_blocks + (i->inode - 1) / MINIX_INODES_PER_BLOCK(i->sb); 59 60 if(!(buf = bread(i->dev, block, i->sb->s_blocksize))) { 61 return -EIO; 62 } 63 offset = (i->inode - 1) % MINIX_INODES_PER_BLOCK(i->sb); 64 ii = ((struct minix_inode *)buf->data) + offset; 65 66 i->i_mode = ii->i_mode; 67 i->i_uid = ii->i_uid; 68 i->i_size = ii->i_size; 69 i->i_atime = ii->i_time; 70 i->i_ctime = ii->i_time; 71 i->i_mtime = ii->i_time; 72 i->i_gid = ii->i_gid; 73 i->i_nlink = ii->i_nlinks; 74 memcpy_b(i->u.minix.u.i1_zone, ii->i_zone, sizeof(ii->i_zone)); 75 i->count = 1; 76 77 errno = 0; 78 switch(i->i_mode & S_IFMT) { 79 case S_IFCHR: 80 i->fsop = &def_chr_fsop; 81 i->rdev = ii->i_zone[0]; 82 break; 83 case S_IFBLK: 84 i->fsop = &def_blk_fsop; 85 i->rdev = ii->i_zone[0]; 86 break; 87 case S_IFIFO: 88 i->fsop = &pipefs_fsop; 89 /* it's a union so we need to clear pipefs_i */ 90 memset_b(&i->u.pipefs, NULL, sizeof(struct pipefs_inode)); 91 break; 92 case S_IFDIR: 93 i->fsop = &minix_dir_fsop; 94 break; 95 case S_IFREG: 96 i->fsop = &minix_file_fsop; 97 break; 98 case S_IFLNK: 99 i->fsop = &minix_symlink_fsop; 100 break; 101 case S_IFSOCK: 102 i->fsop = NULL; 103 break; 104 default: 105 printk("WARNING: %s(): invalid inode (%d) mode %o.\n", __FUNCTION__, i->inode, i->i_mode); 106 errno = -ENOENT; 107 break; 108 } 109 110 brelse(buf); 111 return errno; 112 } 113 114 int v1_minix_write_inode(struct inode *i) 115 { 116 __ino_t block; 117 short int offset; 118 struct minix_inode *ii; 119 struct buffer *buf; 120 121 block = 1 + SUPERBLOCK + i->sb->u.minix.sb.s_imap_blocks + i->sb->u.minix.sb.s_zmap_blocks + (i->inode - 1) / MINIX_INODES_PER_BLOCK(i->sb); 122 123 if(!(buf = bread(i->dev, block, i->sb->s_blocksize))) { 124 return -EIO; 125 } 126 offset = (i->inode - 1) % MINIX_INODES_PER_BLOCK(i->sb); 127 ii = ((struct minix_inode *)buf->data) + offset; 128 129 ii->i_mode = i->i_mode; 130 ii->i_uid = i->i_uid; 131 ii->i_size = i->i_size; 132 ii->i_time = i->i_mtime; 133 ii->i_gid = i->i_gid; 134 ii->i_nlinks = i->i_nlink; 135 if(S_ISCHR(i->i_mode) || S_ISBLK(i->i_mode)) { 136 ii->i_zone[0] = i->rdev; 137 } else { 138 memcpy_b(ii->i_zone, i->u.minix.u.i1_zone, sizeof(i->u.minix.u.i1_zone)); 139 } 140 i->dirty = 0; 141 bwrite(buf); 142 return 0; 143 } 144 145 int v1_minix_ialloc(struct inode *i, int mode) 146 { 147 __blk_t offset; 148 int inode, errno; 149 struct superblock *sb; 150 151 sb = i->sb; 152 superblock_lock(sb); 153 154 offset = 1 + SUPERBLOCK; 155 156 if(!(inode = minix_find_first_zero(sb, offset, sb->u.minix.sb.s_ninodes, offset + sb->u.minix.sb.s_imap_blocks))) { 157 superblock_unlock(sb); 158 return -ENOSPC; 159 } 160 161 errno = minix_change_bit(SET_BIT, sb, offset, inode); 162 163 if(errno) { 164 if(errno < 0) { 165 printk("WARNING: %s(): unable to set inode %d.\n", __FUNCTION__, inode); 166 superblock_unlock(sb); 167 return errno; 168 } else { 169 printk("WARNING: %s(): inode %d is already marked as used!\n", __FUNCTION__, inode); 170 } 171 } 172 173 i->inode = inode; 174 i->i_atime = CURRENT_TIME; 175 i->i_mtime = CURRENT_TIME; 176 i->i_ctime = CURRENT_TIME; 177 superblock_unlock(sb); 178 return 0; 179 } 180 181 void v1_minix_ifree(struct inode *i) 182 { 183 int errno; 184 struct superblock *sb; 185 186 minix_truncate(i, 0); 187 188 sb = i->sb; 189 superblock_lock(sb); 190 191 errno = minix_change_bit(CLEAR_BIT, i->sb, 1 + SUPERBLOCK, i->inode); 192 193 if(errno) { 194 if(errno < 0) { 195 printk("WARNING: %s(): unable to clear inode %d.\n", __FUNCTION__, i->inode); 196 } else { 197 printk("WARNING: %s(): inode %d is already marked as free!\n", __FUNCTION__, i->inode); 198 } 199 } 200 201 i->i_size = 0; 202 i->i_mtime = CURRENT_TIME; 203 i->i_ctime = CURRENT_TIME; 204 i->dirty = 1; 205 superblock_unlock(sb); 206 } 207 208 int v1_minix_bmap(struct inode *i, __off_t offset, int mode) 209 { 210 unsigned char level; 211 __u16 *indblock, *dindblock; 212 __blk_t block, iblock, dblock, newblock; 213 int blksize; 214 struct buffer *buf, *buf2, *buf3; 215 216 blksize = i->sb->s_blocksize; 217 block = offset / blksize; 218 level = 0; 219 220 if(block < MINIX_NDIR_BLOCKS) { 221 level = MINIX_NDIR_BLOCKS - 1; 222 } else { 223 if(block < (BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) { 224 level = MINIX_IND_BLOCK; 225 } else { 226 level = MINIX_DIND_BLOCK; 227 } 228 block -= MINIX_NDIR_BLOCKS; 229 } 230 231 if(level < MINIX_NDIR_BLOCKS) { 232 if(!i->u.minix.u.i1_zone[block] && mode == FOR_WRITING) { 233 if((newblock = minix_balloc(i->sb)) < 0) { 234 return -ENOSPC; 235 } 236 /* initialize the new block */ 237 if(!(buf = bread(i->dev, newblock, blksize))) { 238 minix_bfree(i->sb, newblock); 239 return -EIO; 240 } 241 memset_b(buf->data, 0, blksize); 242 bwrite(buf); 243 i->u.minix.u.i1_zone[block] = newblock; 244 } 245 return i->u.minix.u.i1_zone[block]; 246 } 247 248 if(!i->u.minix.u.i1_zone[level]) { 249 if(mode == FOR_WRITING) { 250 if((newblock = minix_balloc(i->sb)) < 0) { 251 return -ENOSPC; 252 } 253 /* initialize the new block */ 254 if(!(buf = bread(i->dev, newblock, blksize))) { 255 minix_bfree(i->sb, newblock); 256 return -EIO; 257 } 258 memset_b(buf->data, 0, blksize); 259 bwrite(buf); 260 i->u.minix.u.i1_zone[level] = newblock; 261 } else { 262 return 0; 263 } 264 } 265 if(!(buf = bread(i->dev, i->u.minix.u.i1_zone[level], blksize))) { 266 return -EIO; 267 } 268 indblock = (__u16 *)buf->data; 269 dblock = block - BLOCKS_PER_IND_BLOCK(i->sb); 270 271 if(level == MINIX_DIND_BLOCK) { 272 block = dblock / BLOCKS_PER_IND_BLOCK(i->sb); 273 } 274 275 if(!indblock[block]) { 276 if(mode == FOR_WRITING) { 277 if((newblock = minix_balloc(i->sb)) < 0) { 278 brelse(buf); 279 return -ENOSPC; 280 } 281 /* initialize the new block */ 282 if(!(buf2 = bread(i->dev, newblock, blksize))) { 283 minix_bfree(i->sb, newblock); 284 brelse(buf); 285 return -EIO; 286 } 287 memset_b(buf2->data, 0, blksize); 288 bwrite(buf2); 289 indblock[block] = newblock; 290 if(level == MINIX_IND_BLOCK) { 291 bwrite(buf); 292 return newblock; 293 } 294 buf->flags |= (BUFFER_DIRTY | BUFFER_VALID); 295 } else { 296 brelse(buf); 297 return 0; 298 } 299 } 300 if(level == MINIX_IND_BLOCK) { 301 newblock = indblock[block]; 302 brelse(buf); 303 return newblock; 304 } 305 306 iblock = block; 307 if(!(buf2 = bread(i->dev, indblock[iblock], blksize))) { 308 printk("%s(): returning -EIO\n", __FUNCTION__); 309 brelse(buf); 310 return -EIO; 311 } 312 dindblock = (__u16 *)buf2->data; 313 block = dindblock[dblock - (iblock * BLOCKS_PER_IND_BLOCK(i->sb))]; 314 if(!block && mode == FOR_WRITING) { 315 if((newblock = minix_balloc(i->sb)) < 0) { 316 brelse(buf); 317 brelse(buf2); 318 return -ENOSPC; 319 } 320 /* initialize the new block */ 321 if(!(buf3 = bread(i->dev, newblock, blksize))) { 322 minix_bfree(i->sb, newblock); 323 brelse(buf); 324 brelse(buf2); 325 return -EIO; 326 } 327 memset_b(buf3->data, 0, blksize); 328 bwrite(buf3); 329 dindblock[dblock - (iblock * BLOCKS_PER_IND_BLOCK(i->sb))] = newblock; 330 buf2->flags |= (BUFFER_DIRTY | BUFFER_VALID); 331 block = newblock; 332 } 333 brelse(buf); 334 brelse(buf2); 335 return block; 336 } 337 338 int v1_minix_truncate(struct inode *i, __off_t length) 339 { 340 int n; 341 __blk_t block, dblock; 342 __u16 *zone; 343 struct buffer *buf; 344 345 block = length / i->sb->s_blocksize; 346 347 if(!S_ISDIR(i->i_mode) && !S_ISREG(i->i_mode) && !S_ISLNK(i->i_mode)) { 348 return -EINVAL; 349 } 350 351 if(block < MINIX_NDIR_BLOCKS) { 352 for(n = block; n < MINIX_NDIR_BLOCKS; n++) { 353 if(i->u.minix.u.i1_zone[n]) { 354 minix_bfree(i->sb, i->u.minix.u.i1_zone[n]); 355 i->u.minix.u.i1_zone[n] = 0; 356 } 357 } 358 block = 0; 359 } 360 361 if(!block || block < (BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) { 362 if(block) { 363 block -= MINIX_NDIR_BLOCKS; 364 } 365 if(i->u.minix.u.i1_zone[MINIX_IND_BLOCK]) { 366 free_zone(i, i->u.minix.u.i1_zone[MINIX_IND_BLOCK], block); 367 if(!block) { 368 minix_bfree(i->sb, i->u.minix.u.i1_zone[MINIX_IND_BLOCK]); 369 i->u.minix.u.i1_zone[MINIX_IND_BLOCK] = 0; 370 } 371 } 372 block = 0; 373 } 374 375 if(block) { 376 block -= MINIX_NDIR_BLOCKS; 377 block -= BLOCKS_PER_IND_BLOCK(i->sb); 378 } 379 if(i->u.minix.u.i1_zone[MINIX_DIND_BLOCK]) { 380 if(!(buf = bread(i->dev, i->u.minix.u.i1_zone[MINIX_DIND_BLOCK], i->sb->s_blocksize))) { 381 printk("%s(): error reading block %d.\n", __FUNCTION__, i->u.minix.u.i1_zone[MINIX_DIND_BLOCK]); 382 } 383 zone = (__u16 *)buf->data; 384 dblock = block % BLOCKS_PER_IND_BLOCK(i->sb); 385 for(n = block / BLOCKS_PER_IND_BLOCK(i->sb); n < BLOCKS_PER_IND_BLOCK(i->sb); n++) { 386 if(zone[n]) { 387 free_zone(i, zone[n], dblock); 388 if(!dblock) { 389 minix_bfree(i->sb, zone[n]); 390 } 391 } 392 dblock = 0; 393 } 394 bwrite(buf); 395 if(!block) { 396 minix_bfree(i->sb, i->u.minix.u.i1_zone[MINIX_DIND_BLOCK]); 397 i->u.minix.u.i1_zone[MINIX_DIND_BLOCK] = 0; 398 } 399 } 400 401 i->i_mtime = CURRENT_TIME; 402 i->i_ctime = CURRENT_TIME; 403 i->i_size = length; 404 i->dirty = 1; 405 406 return 0; 407 }