if (offset > file[0]) { flag error }The next 13 words are pointers to the first thirteen blocks of the file:
if (bn < 13) { get_block(buf, file[bn+1]); return buf[bo]; }The 14th word is a pointer to a block of cached block pointers. It contains pairs of file block numbers and disk pointers. So if a block number is thirteen or greater, before we try to find it elsewhere, we check the cache:
get_block(buf,file[14]); ip = (int *) buf; for (i = 0; i < ibs; i += 2) { if (ip[i] == bn) { get_block(buf, ip[i+1]); return buf[bo]; } }Finally, the last block is a pointer to a triple indirect block, as described in section 11.2.3 of the book (indexed allocation). That block contains pointers to blocks (level 1). The blocks pointed to by level 1 pointers contain pointers to blocks (level 2). And the The blocks pointed to by level 2 pointers contain pointers to blocks (level 3). These pointers point to file blocks.
bn -= 13; ib1n = bn / ibs; ib1o = bn % ibs; ib2n = ib1n / ibs; ib2o = ib1n % ibs; get_block(buf, file[15]); get_block(buf, buf[ib2n]); get_block(buf, buf[ib2o]); get_block(buf, buf[ib1o]); return buf[bo];So, for example, to get block 13, you have get the block in file[15] to get the first level 1 pointer. Use that to get the level 1 block, and the first level 2 pointer. Use that to get the level 2 block, and the first level 3 pointer. Use that to get the level 3 block, and the pointer to file block 13.Now, motivationally, this structure works well for small files, but holds arbitrarily big files too. If we cache recently-used blocks (or perhaps cache based on lookahead) in our disk-reading routines, then we can use the cache block to improve performance when getting blocks greater than number 12.
Part 2
The first 13 pointers are responsible for 128 bytes each, and the last pointer is responsible for 32*32*32*128 = 2^22 bytes (roughly 4 megabytes). The whole expression is:
(13 * 128) + (32 * 32 * 32 * 128) = 4,195,968 bytes
Grading
Only one student got the fact that file[14] was meant to be a cache -- well done!