ext2.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /* Copyright (C) 2013 by John Cronin <jncronin@tysos.org>
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. * The above copyright notice and this permission notice shall be included in
  10. * all copies or substantial portions of the Software.
  11. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. * THE SOFTWARE.
  18. */
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <stdint.h>
  22. #include <string.h>
  23. #include <dirent.h>
  24. #include "vfs.h"
  25. #include "fs.h"
  26. #include "errno.h"
  27. #ifdef DEBUG2
  28. #define EXT2_DEBUG
  29. #endif
  30. struct ext2_bgd
  31. {
  32. uint32_t block_bitmap_block_address;
  33. uint32_t inode_bitmap_block_address;
  34. uint32_t inode_table_start_block;
  35. uint16_t unallocated_block_count;
  36. uint16_t unallocated_inode_count;
  37. uint16_t directory_count;
  38. uint8_t reserved[14];
  39. } __attribute__ ((packed));
  40. struct ext2_fs {
  41. struct fs b;
  42. uint32_t total_inodes;
  43. uint32_t total_blocks;
  44. uint32_t inode_size;
  45. uint32_t inodes_per_group;
  46. uint32_t blocks_per_group;
  47. uint32_t total_groups;
  48. int major_version;
  49. int minor_version;
  50. uint32_t pointers_per_indirect_block;
  51. uint32_t pointers_per_indirect_block_2;
  52. uint32_t pointers_per_indirect_block_3;
  53. int type_flags_used;
  54. // cache the block group descriptor table
  55. struct ext2_bgd *bgdt;
  56. };
  57. struct ext2_inode {
  58. uint16_t type_permissions;
  59. uint16_t user_id;
  60. uint32_t size;
  61. uint32_t last_access_time;
  62. uint32_t creation_time;
  63. uint32_t last_modification_time;
  64. uint32_t deletion_time;
  65. uint16_t group_id;
  66. uint16_t hard_link_count;
  67. uint32_t sector_count;
  68. uint32_t flags;
  69. uint32_t os_specific_1;
  70. uint32_t db0;
  71. uint32_t db1;
  72. uint32_t db2;
  73. uint32_t db3;
  74. uint32_t db4;
  75. uint32_t db5;
  76. uint32_t db6;
  77. uint32_t db7;
  78. uint32_t db8;
  79. uint32_t db9;
  80. uint32_t db10;
  81. uint32_t db11;
  82. uint32_t sibp;
  83. uint32_t dibp;
  84. uint32_t tibp;
  85. uint32_t generation_number;
  86. uint32_t extended_attribute_block;
  87. uint32_t size_upper_bits;
  88. uint32_t fragment_block_address;
  89. uint32_t os_opecific[3];
  90. } __attribute__ ((packed));
  91. static struct dirent *ext2_read_directory(struct fs *fs, char **name);
  92. static struct dirent *ext2_read_dir(struct ext2_fs *fs, struct dirent *d);
  93. static FILE *ext2_fopen(struct fs *fs, struct dirent *path, const char *mode);
  94. static size_t ext2_fread(struct fs *fs, void *ptr, size_t byte_size, FILE *stream);
  95. static struct ext2_inode *ext2_read_inode(struct ext2_fs *fs,
  96. uint32_t inode_idx);
  97. static char ext2_name[] = "ext2";
  98. static uint32_t get_sector_num(struct ext2_fs *fs, uint32_t block_no)
  99. {
  100. return block_no * fs->b.block_size / fs->b.parent->block_size;
  101. }
  102. static uint8_t *read_block(struct ext2_fs *fs, uint32_t block_no)
  103. {
  104. uint8_t *ret = (uint8_t *)malloc(fs->b.block_size);
  105. int br_ret = block_read(fs->b.parent, ret, fs->b.block_size,
  106. get_sector_num(fs, block_no));
  107. if(br_ret < 0)
  108. {
  109. printf("EXT2: block_read returned %i\n");
  110. return (void*)0;
  111. }
  112. return ret;
  113. }
  114. static uint32_t get_block_no_from_inode(struct ext2_fs *fs, struct ext2_inode *i, uint32_t index, int add_blocks)
  115. {
  116. // If the block index is < 12 use the direct block pointers
  117. if(index < 12)
  118. return ((uint32_t *)&i->db0)[index];
  119. else
  120. {
  121. // If the block index is < (12 + pointers_per_indirect_block),
  122. // use the singly-indirect block pointer
  123. index -= 12;
  124. if(index < fs->pointers_per_indirect_block)
  125. {
  126. // Load the singly indirect block
  127. uint8_t *sib = read_block(fs, i->sibp);
  128. if(!sib)
  129. return 0;
  130. uint32_t ret = ((uint32_t *)sib)[index];
  131. free(sib);
  132. return ret;
  133. }
  134. else
  135. {
  136. index -= fs->pointers_per_indirect_block;
  137. // If the index is < pointers_per_indirect_block ^ 2,
  138. // use the doubly-indirect block pointer
  139. if(index < (fs->pointers_per_indirect_block_2))
  140. {
  141. uint32_t dib_index = index / fs->pointers_per_indirect_block;
  142. uint32_t sib_index = index % fs->pointers_per_indirect_block;
  143. // Load the doubly indirect block
  144. uint8_t *dib = read_block(fs, i->dibp);
  145. if(!dib)
  146. return 0;
  147. uint32_t sib_block = ((uint32_t *)dib)[dib_index];
  148. free(dib);
  149. // Load the appropriate singly indirect block
  150. uint8_t *sib = read_block(fs, sib_block);
  151. if(!sib)
  152. return 0;
  153. uint32_t ret = ((uint32_t *)sib)[sib_index];
  154. free(sib);
  155. return ret;
  156. }
  157. else
  158. {
  159. index -= fs->pointers_per_indirect_block_2;
  160. // Else use a triply indirect block or fail
  161. if(index < fs->pointers_per_indirect_block_3)
  162. {
  163. uint32_t tib_index = index /
  164. fs->pointers_per_indirect_block_2;
  165. uint32_t tib_rem = index %
  166. fs->pointers_per_indirect_block_2;
  167. uint32_t dib_index = tib_rem /
  168. fs->pointers_per_indirect_block;
  169. uint32_t sib_index = tib_rem %
  170. fs->pointers_per_indirect_block;
  171. // Load the triply indirect block
  172. uint8_t *tib = read_block(fs, i->tibp);
  173. if(!tib)
  174. return 0;
  175. uint32_t dib_block = ((uint32_t *)tib)[tib_index];
  176. free(tib);
  177. // Load the appropriate doubly indirect block
  178. uint8_t *dib = read_block(fs, dib_block);
  179. if(!dib)
  180. return 0;
  181. uint32_t sib_block = ((uint32_t *)dib)[dib_index];
  182. free(dib);
  183. // Load the appropriate singly indirect block
  184. uint8_t *sib = read_block(fs, sib_block);
  185. if(!sib)
  186. return 0;
  187. uint32_t ret = ((uint32_t *)sib)[sib_index];
  188. free(sib);
  189. return ret;
  190. }
  191. else
  192. {
  193. if(add_blocks)
  194. {
  195. printf("EXT2: request to extend file not currently supported\n");
  196. return 0;
  197. }
  198. printf("EXT2: invalid block number\n");
  199. return 0;
  200. }
  201. }
  202. }
  203. }
  204. }
  205. static FILE *ext2_fopen(struct fs *fs, struct dirent *path, const char *mode)
  206. {
  207. if(fs != path->fs)
  208. {
  209. errno = EFAULT;
  210. return (FILE *)0;
  211. }
  212. if(strcmp(mode, "r"))
  213. {
  214. errno = EROFS;
  215. return (FILE *)0;
  216. }
  217. struct ext2_fs *ext2 = (struct ext2_fs *)fs;
  218. struct vfs_file *ret = (struct vfs_file *)malloc(sizeof(struct vfs_file));
  219. memset(ret, 0, sizeof(struct vfs_file));
  220. ret->fs = fs;
  221. ret->pos = 0;
  222. ret->opaque = path->opaque;
  223. // We have to load the inode to get the length
  224. struct ext2_inode *inode = ext2_read_inode(ext2,
  225. (uint32_t)path->opaque);
  226. ret->len = (long)inode->size; // no support for large files
  227. free(inode);
  228. return ret;
  229. }
  230. static uint32_t ext2_get_next_bdev_block_num(uint32_t f_block_idx, FILE *s, void *opaque, int add_blocks)
  231. {
  232. return get_block_no_from_inode((struct ext2_fs *)s->fs, (struct ext2_inode *)opaque,
  233. f_block_idx, add_blocks);
  234. }
  235. static size_t ext2_fread(struct fs *fs, void *ptr, size_t byte_size, FILE *stream)
  236. {
  237. if(stream->fs != fs)
  238. return -1;
  239. if(stream->opaque == (void *)0)
  240. return -1;
  241. struct ext2_inode *inode = ext2_read_inode((struct ext2_fs *)fs,
  242. (uint32_t)stream->opaque);
  243. return fs_fread(ext2_get_next_bdev_block_num, fs, ptr, byte_size, stream, (void *)inode);
  244. }
  245. static int ext2_fclose(struct fs *fs, FILE *fp)
  246. {
  247. (void)fs;
  248. (void)fp;
  249. return 0;
  250. }
  251. static struct ext2_inode *ext2_read_inode(struct ext2_fs *fs,
  252. uint32_t inode_idx)
  253. {
  254. // Inode addresses start at 1
  255. inode_idx--;
  256. // First find which block group the inode is in
  257. uint32_t block_idx = inode_idx / fs->inodes_per_group;
  258. uint32_t block_offset = inode_idx % fs->inodes_per_group;
  259. struct ext2_bgd *b = &fs->bgdt[block_idx];
  260. // Now find which block in its inode table its in
  261. uint32_t inodes_per_block = fs->b.block_size / fs->inode_size;
  262. block_idx = block_offset / inodes_per_block;
  263. block_offset = block_offset % inodes_per_block;
  264. // Now read the appropriate block and extract the inode
  265. uint8_t *itable = read_block(fs, b->inode_table_start_block + block_idx);
  266. if(itable == (void*)0)
  267. return (void*)0;
  268. struct ext2_inode *inode =
  269. (struct ext2_inode *)malloc(sizeof(struct ext2_inode));
  270. memcpy(inode, &itable[block_offset * fs->inode_size],
  271. sizeof(struct ext2_inode));
  272. free(itable);
  273. return inode;
  274. }
  275. int ext2_init(struct block_device *parent, struct fs **fs)
  276. {
  277. // Interpret an EXT2 file system
  278. #ifdef EXT2_DEBUG
  279. printf("EXT2: looking for a filesytem on %s\n", parent->device_name);
  280. #endif
  281. // Read superblock
  282. uint8_t *sb = (uint8_t *)malloc(1024);
  283. int r = block_read(parent, sb, 1024, 1024 / parent->block_size);
  284. if(r < 0)
  285. {
  286. printf("EXT2: error %i reading block 0\n", r);
  287. return r;
  288. }
  289. if(r != 1024)
  290. {
  291. printf("EXT2: error reading superblock (only %i bytes read)\n", r);
  292. return -1;
  293. }
  294. // Confirm its ext2
  295. if(*(uint16_t *)&sb[56] != 0xef53)
  296. {
  297. printf("EXT2: not a valid ext2 filesystem on %s\n", parent->device_name);
  298. return -1;
  299. }
  300. struct ext2_fs *ret = (struct ext2_fs *)malloc(sizeof(struct ext2_fs));
  301. memset(ret, 0, sizeof(struct ext2_fs));
  302. ret->b.fopen = ext2_fopen;
  303. ret->b.fread = ext2_fread;
  304. ret->b.fclose = ext2_fclose;
  305. ret->b.read_directory = ext2_read_directory;
  306. ret->b.parent = parent;
  307. ret->b.fs_name = ext2_name;
  308. ret->total_inodes = *(uint32_t *)&sb[0];
  309. ret->total_blocks = *(uint32_t *)&sb[4];
  310. ret->inodes_per_group = *(uint32_t *)&sb[40];
  311. ret->blocks_per_group = *(uint32_t *)&sb[32];
  312. ret->b.block_size = 1024 << *(uint32_t *)&sb[24];
  313. ret->minor_version = *(int16_t *)&sb[62];
  314. ret->major_version = *(int32_t *)&sb[76];
  315. if(ret->major_version >= 1)
  316. {
  317. // Read extended superblock
  318. ret->inode_size = *(uint16_t *)&sb[88];
  319. uint32_t required_flags = *(uint32_t *)&sb[96];
  320. if(required_flags & 0x2)
  321. ret->type_flags_used = 1;
  322. }
  323. else
  324. ret->inode_size = 128;
  325. // Calculate the number of block groups by two different methods and ensure they tally
  326. uint32_t i_calc_val = ret->total_inodes / ret->inodes_per_group;
  327. uint32_t i_calc_rem = ret->total_inodes % ret->inodes_per_group;
  328. if(i_calc_rem)
  329. i_calc_val++;
  330. uint32_t b_calc_val = ret->total_blocks / ret->blocks_per_group;
  331. uint32_t b_calc_rem = ret->total_blocks % ret->blocks_per_group;
  332. if(b_calc_rem)
  333. b_calc_val++;
  334. if(i_calc_val != b_calc_val)
  335. {
  336. printf("EXT2: total group calculation by block method (%i) and inode "
  337. "method (%i) differs\n", b_calc_val, i_calc_val);
  338. return -1;
  339. }
  340. ret->total_groups = i_calc_val;
  341. ret->pointers_per_indirect_block = ret->b.block_size / 4;
  342. ret->pointers_per_indirect_block_2 = ret->pointers_per_indirect_block *
  343. ret->pointers_per_indirect_block;
  344. ret->pointers_per_indirect_block_3 = ret->pointers_per_indirect_block_2 *
  345. ret->pointers_per_indirect_block;
  346. // Read the block group descriptor table
  347. ret->bgdt = (struct ext2_bgd *)malloc(ret->total_groups * sizeof(struct ext2_bgd));
  348. int bgdt_block = 1;
  349. if(ret->b.block_size == 1024)
  350. bgdt_block = 2;
  351. uint32_t bgdt_size = ret->total_groups * sizeof(struct ext2_bgd);
  352. // round up to a multiple of block_size
  353. if(bgdt_size % ret->b.block_size)
  354. bgdt_size = (bgdt_size / ret->b.block_size + 1) * ret->b.block_size;
  355. block_read(parent, (uint8_t *)ret->bgdt, bgdt_size,
  356. get_sector_num(ret, bgdt_block));
  357. *fs = (struct fs *)ret;
  358. free(sb);
  359. printf("EXT2: found an ext2 filesystem on %s\n", ret->b.parent->device_name);
  360. return 0;
  361. }
  362. struct dirent *ext2_read_directory(struct fs *fs, char **name)
  363. {
  364. struct dirent *cur_dir = ext2_read_dir((struct ext2_fs *)fs, (void*)0);
  365. while(*name)
  366. {
  367. // Search the directory entries for one of the requested name
  368. int found = 0;
  369. while(cur_dir)
  370. {
  371. if(!strcmp(*name, cur_dir->name))
  372. {
  373. if(!cur_dir->is_dir)
  374. {
  375. errno = ENOTDIR;
  376. return (void *)0;
  377. }
  378. found = 1;
  379. cur_dir = ext2_read_dir((struct ext2_fs *)fs, cur_dir);
  380. name++;
  381. break;
  382. }
  383. cur_dir = cur_dir->next;
  384. }
  385. if(!found)
  386. {
  387. #ifdef EXT2_DEBUG
  388. printf("EXT2: path part %s not found\n", *name);
  389. #endif
  390. errno = ENOENT;
  391. return (void*)0;
  392. }
  393. }
  394. return cur_dir;
  395. }
  396. struct dirent *ext2_read_dir(struct ext2_fs *fs, struct dirent *d)
  397. {
  398. struct ext2_fs *ext2 = (struct ext2_fs *)fs;
  399. uint32_t inode_idx = 2; // root
  400. if(d != (void*)0)
  401. inode_idx = (uint32_t)d->opaque;
  402. struct dirent *ret = (void *)0;
  403. struct dirent *prev = (void *)0;
  404. // Load the inode of the directory
  405. struct ext2_inode *inode = ext2_read_inode(ext2, inode_idx);
  406. // Iterate through loading the blocks
  407. uint32_t total_blocks = inode->size / ext2->b.block_size;
  408. uint32_t block_rem = inode->size % ext2->b.block_size;
  409. if(block_rem)
  410. total_blocks++;
  411. uint32_t cur_block_idx = 0;
  412. while(cur_block_idx < total_blocks)
  413. {
  414. uint32_t block_no = get_block_no_from_inode(ext2, inode,
  415. cur_block_idx, 0);
  416. uint8_t *block = read_block(ext2, block_no);
  417. uint32_t total_block_size = ext2->b.block_size;
  418. // If inode->size is not a complete multiple of
  419. // ext2->block_size then only read part of the last block
  420. if((cur_block_idx == (total_blocks - 1)) && block_rem)
  421. total_block_size = block_rem;
  422. uint32_t ptr = 0;
  423. while(ptr < total_block_size)
  424. {
  425. uint32_t de_inode_idx = *(uint32_t *)&block[ptr];
  426. uint16_t de_entry_size = *(uint16_t *)&block[ptr + 4];
  427. uint16_t de_name_length = *(uint16_t *)&block[ptr + 6];
  428. uint8_t de_type_flags = *(uint8_t *)&block[ptr + 7];
  429. // Does the entry exist?
  430. if(!de_inode_idx)
  431. {
  432. ptr += de_entry_size;
  433. continue;
  434. }
  435. // Read it
  436. struct dirent *de = (struct dirent *)malloc(sizeof(struct dirent));
  437. memset(de, 0, sizeof(struct dirent));
  438. if(ret == (void *)0)
  439. ret = de;
  440. if(prev != (void *)0)
  441. prev->next = de;
  442. prev = de;
  443. // Determine the length of the name part
  444. uint32_t name_length = de_name_length;
  445. if(ext2->type_flags_used)
  446. name_length &= 0xff;
  447. // Store the name
  448. de->name = (char *)malloc(name_length + 1);
  449. memset(de->name, 0, name_length + 1);
  450. memcpy(de->name, &block[ptr + 8], name_length);
  451. // Don't return special files
  452. if(!strcmp(de->name, ".") || !strcmp(de->name, "..") ||
  453. !strcmp(de->name, "lost+found"))
  454. {
  455. free(de);
  456. ptr += de_entry_size;
  457. continue;
  458. }
  459. // Determine if its a directory
  460. if(ext2->type_flags_used)
  461. {
  462. if(de_type_flags == 2)
  463. de->is_dir = 1;
  464. }
  465. else
  466. {
  467. // If directory type flags are not supported
  468. // we have to load the inode and do it that
  469. // way
  470. struct ext2_inode *de_inode =
  471. ext2_read_inode(ext2, de_inode_idx);
  472. if(de_inode->type_permissions & 0x2000)
  473. de->is_dir = 1;
  474. free(de_inode);
  475. }
  476. de->fs = &fs->b;
  477. de->next = (void *)0;
  478. de->opaque = (void*)de_inode_idx;
  479. ptr += de_entry_size;
  480. }
  481. free(block);
  482. cur_block_idx++;
  483. }
  484. free(inode);
  485. return ret;
  486. }