ext2.c 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2014-2018 K. Lange
  5. */
  6. #include <kernel/system.h>
  7. #include <kernel/types.h>
  8. #include <kernel/fs.h>
  9. #include <kernel/ext2.h>
  10. #include <kernel/logging.h>
  11. #include <kernel/module.h>
  12. #include <kernel/args.h>
  13. #include <kernel/printf.h>
  14. #include <kernel/tokenize.h>
  15. #define EXT2_BGD_BLOCK 2
  16. #define E_SUCCESS 0
  17. #define E_BADBLOCK 1
  18. #define E_NOSPACE 2
  19. #define E_BADPARENT 3
  20. #undef _symlink
  21. #define _symlink(inode) ((char *)(inode)->block)
  22. /*
  23. * EXT2 filesystem object
  24. */
  25. typedef struct {
  26. ext2_superblock_t * superblock; /* Device superblock, contains important information */
  27. ext2_bgdescriptor_t * block_groups; /* Block Group Descriptor / Block groups */
  28. fs_node_t * root_node; /* Root FS node (attached to mountpoint) */
  29. fs_node_t * block_device; /* Block device node XXX unused */
  30. unsigned int block_size; /* Size of one block */
  31. unsigned int pointers_per_block; /* Number of pointers that fit in a block */
  32. unsigned int inodes_per_group; /* Number of inodes in a "group" */
  33. unsigned int block_group_count; /* Number of blocks groups */
  34. ext2_disk_cache_entry_t * disk_cache; /* Dynamically allocated array of cache entries */
  35. unsigned int cache_entries; /* Size of ->disk_cache */
  36. unsigned int cache_time; /* "timer" that increments with each cache read/write */
  37. spin_lock_t lock; /* Synchronization lock point */
  38. uint8_t bgd_block_span;
  39. uint8_t bgd_offset;
  40. unsigned int inode_size;
  41. uint8_t * cache_data;
  42. int flags;
  43. } ext2_fs_t;
  44. #define EXT2_FLAG_NOCACHE 0x0001
  45. /*
  46. * These macros were used in the original toaru ext2 driver.
  47. * They make referring to some of the core parts of the drive a bit easier.
  48. */
  49. #define BGDS (this->block_group_count)
  50. #define SB (this->superblock)
  51. #define BGD (this->block_groups)
  52. #define RN (this->root_node)
  53. #define DC (this->disk_cache)
  54. /*
  55. * These macros deal with the block group descriptor bitmap
  56. */
  57. #define BLOCKBIT(n) (bg_buffer[((n) >> 3)] & (1 << (((n) % 8))))
  58. #define BLOCKBYTE(n) (bg_buffer[((n) >> 3)])
  59. #define SETBIT(n) (1 << (((n) % 8)))
  60. static uint32_t node_from_file(ext2_fs_t * this, ext2_inodetable_t *inode, ext2_dir_t *direntry, fs_node_t *fnode);
  61. static uint32_t ext2_root(ext2_fs_t * this, ext2_inodetable_t *inode, fs_node_t *fnode);
  62. static ext2_inodetable_t * read_inode(ext2_fs_t * this, uint32_t inode);
  63. static void refresh_inode(ext2_fs_t * this, ext2_inodetable_t * inodet, uint32_t inode);
  64. static int write_inode(ext2_fs_t * this, ext2_inodetable_t *inode, uint32_t index);
  65. static fs_node_t * finddir_ext2(fs_node_t *node, char *name);
  66. static unsigned int allocate_block(ext2_fs_t * this);
  67. /**
  68. * ext2->get_cache_time Increment and return the current cache time
  69. *
  70. * @returns Current cache time
  71. */
  72. static unsigned int get_cache_time(ext2_fs_t * this) {
  73. return this->cache_time++;
  74. }
  75. /**
  76. * ext2->cache_flush_dirty Flush dirty cache entry to the disk.
  77. *
  78. * @param ent_no Cache entry to dump
  79. * @returns Error code or E_SUCCESS
  80. */
  81. static int cache_flush_dirty(ext2_fs_t * this, unsigned int ent_no) {
  82. write_fs(this->block_device, (DC[ent_no].block_no) * this->block_size, this->block_size, (uint8_t *)(DC[ent_no].block));
  83. DC[ent_no].dirty = 0;
  84. return E_SUCCESS;
  85. }
  86. /**
  87. * ext2->rewrite_superblock Rewrite the superblock.
  88. *
  89. * Superblocks are a bit different from other blocks, as they are always in the same place,
  90. * regardless of what the filesystem block size is. This doesn't work well with our setup,
  91. * so we need to special-case it.
  92. */
  93. static int rewrite_superblock(ext2_fs_t * this) {
  94. write_fs(this->block_device, 1024, sizeof(ext2_superblock_t), (uint8_t *)SB);
  95. return E_SUCCESS;
  96. }
  97. /**
  98. * ext2->read_block Read a block from the block device associated with this filesystem.
  99. *
  100. * The read block will be copied into the buffer pointed to by `buf`.
  101. *
  102. * @param block_no Number of block to read.
  103. * @param buf Where to put the data read.
  104. * @returns Error code or E_SUCCESS
  105. */
  106. static int read_block(ext2_fs_t * this, unsigned int block_no, uint8_t * buf) {
  107. /* 0 is an invalid block number. So is anything beyond the total block count, but we can't check that. */
  108. if (!block_no) {
  109. return E_BADBLOCK;
  110. }
  111. /* This operation requires the filesystem lock to be obtained */
  112. spin_lock(this->lock);
  113. /* We can make reads without a cache in place. */
  114. if (!DC) {
  115. /* In such cases, we read directly from the block device */
  116. read_fs(this->block_device, block_no * this->block_size, this->block_size, (uint8_t *)buf);
  117. /* We are done, release the lock */
  118. spin_unlock(this->lock);
  119. /* And return SUCCESS */
  120. return E_SUCCESS;
  121. }
  122. /*
  123. * Search the cache for this entry
  124. * We'll look for the oldest entry, too.
  125. */
  126. int oldest = -1;
  127. unsigned int oldest_age = UINT32_MAX;
  128. for (unsigned int i = 0; i < this->cache_entries; ++i) {
  129. if (DC[i].block_no == block_no) {
  130. /* We found it! Update usage times */
  131. DC[i].last_use = get_cache_time(this);
  132. /* Read the block */
  133. memcpy(buf, DC[i].block, this->block_size);
  134. /* Release the lock */
  135. spin_unlock(this->lock);
  136. /* Success! */
  137. return E_SUCCESS;
  138. }
  139. if (DC[i].last_use < oldest_age) {
  140. /* We found an older block, remember this. */
  141. oldest = i;
  142. oldest_age = DC[i].last_use;
  143. }
  144. }
  145. /*
  146. * At this point, we did not find this block in the cache.
  147. * We are going to replace the oldest entry with this new one.
  148. */
  149. /* We'll start by flushing the block if it was dirty. */
  150. if (DC[oldest].dirty) {
  151. cache_flush_dirty(this, oldest);
  152. }
  153. /* Then we'll read the new one */
  154. read_fs(this->block_device, block_no * this->block_size, this->block_size, (uint8_t *)DC[oldest].block);
  155. /* And copy the results to the output buffer */
  156. memcpy(buf, DC[oldest].block, this->block_size);
  157. /* And update the cache entry to point to the new block */
  158. DC[oldest].block_no = block_no;
  159. DC[oldest].last_use = get_cache_time(this);
  160. DC[oldest].dirty = 0;
  161. /* Release the lock */
  162. spin_unlock(this->lock);
  163. /* And return success */
  164. return E_SUCCESS;
  165. }
  166. /**
  167. * ext2->write_block Write a block to the block device.
  168. *
  169. * @param block_no Block to write
  170. * @param buf Data in the block
  171. * @returns Error code or E_SUCCESSS
  172. */
  173. static int write_block(ext2_fs_t * this, unsigned int block_no, uint8_t *buf) {
  174. if (!block_no) {
  175. debug_print(ERROR, "Attempted to write to block #0. Enable tracing and retry this operation.");
  176. debug_print(ERROR, "Your file system is most likely corrupted now.");
  177. return E_BADBLOCK;
  178. }
  179. /* This operation requires the filesystem lock */
  180. spin_lock(this->lock);
  181. if (!DC) {
  182. write_fs(this->block_device, block_no * this->block_size, this->block_size, buf);
  183. spin_unlock(this->lock);
  184. return E_SUCCESS;
  185. }
  186. /* Find the entry in the cache */
  187. int oldest = -1;
  188. unsigned int oldest_age = UINT32_MAX;
  189. for (unsigned int i = 0; i < this->cache_entries; ++i) {
  190. if (DC[i].block_no == block_no) {
  191. /* We found it. Update the cache entry */
  192. DC[i].last_use = get_cache_time(this);
  193. DC[i].dirty = 1;
  194. memcpy(DC[i].block, buf, this->block_size);
  195. spin_unlock(this->lock);
  196. return E_SUCCESS;
  197. }
  198. if (DC[i].last_use < oldest_age) {
  199. /* Keep track of the oldest entry */
  200. oldest = i;
  201. oldest_age = DC[i].last_use;
  202. }
  203. }
  204. /* We did not find this element in the cache, so make room. */
  205. if (DC[oldest].dirty) {
  206. /* Flush the oldest entry */
  207. cache_flush_dirty(this, oldest);
  208. }
  209. /* Update the entry */
  210. memcpy(DC[oldest].block, buf, this->block_size);
  211. DC[oldest].block_no = block_no;
  212. DC[oldest].last_use = get_cache_time(this);
  213. DC[oldest].dirty = 1;
  214. /* Release the lock */
  215. spin_unlock(this->lock);
  216. /* We're done. */
  217. return E_SUCCESS;
  218. }
  219. static unsigned int ext2_sync(ext2_fs_t * this) {
  220. if (!this->disk_cache) return 0;
  221. /* This operation requires the filesystem lock */
  222. spin_lock(this->lock);
  223. /* Flush each cache entry. */
  224. for (unsigned int i = 0; i < this->cache_entries; ++i) {
  225. if (DC[i].dirty) {
  226. cache_flush_dirty(this, i);
  227. }
  228. }
  229. /* Release the lock */
  230. spin_unlock(this->lock);
  231. return 0;
  232. }
  233. /**
  234. * ext2->set_block_number Set the "real" block number for a given "inode" block number.
  235. *
  236. * @param inode Inode to operate on
  237. * @param iblock Block offset within the inode
  238. * @param rblock Real block number
  239. * @returns Error code or E_SUCCESS
  240. */
  241. static unsigned int set_block_number(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int inode_no, unsigned int iblock, unsigned int rblock) {
  242. unsigned int p = this->pointers_per_block;
  243. /* We're going to do some crazy math in a bit... */
  244. unsigned int a, b, c, d, e, f, g;
  245. uint8_t * tmp;
  246. if (iblock < EXT2_DIRECT_BLOCKS) {
  247. inode->block[iblock] = rblock;
  248. return E_SUCCESS;
  249. } else if (iblock < EXT2_DIRECT_BLOCKS + p) {
  250. /* XXX what if inode->block[EXT2_DIRECT_BLOCKS] isn't set? */
  251. if (!inode->block[EXT2_DIRECT_BLOCKS]) {
  252. unsigned int block_no = allocate_block(this);
  253. if (!block_no) return E_NOSPACE;
  254. inode->block[EXT2_DIRECT_BLOCKS] = block_no;
  255. write_inode(this, inode, inode_no);
  256. }
  257. tmp = malloc(this->block_size);
  258. read_block(this, inode->block[EXT2_DIRECT_BLOCKS], (uint8_t *)tmp);
  259. ((uint32_t *)tmp)[iblock - EXT2_DIRECT_BLOCKS] = rblock;
  260. write_block(this, inode->block[EXT2_DIRECT_BLOCKS], (uint8_t *)tmp);
  261. free(tmp);
  262. return E_SUCCESS;
  263. } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p) {
  264. a = iblock - EXT2_DIRECT_BLOCKS;
  265. b = a - p;
  266. c = b / p;
  267. d = b - c * p;
  268. if (!inode->block[EXT2_DIRECT_BLOCKS+1]) {
  269. unsigned int block_no = allocate_block(this);
  270. if (!block_no) return E_NOSPACE;
  271. inode->block[EXT2_DIRECT_BLOCKS+1] = block_no;
  272. write_inode(this, inode, inode_no);
  273. }
  274. tmp = malloc(this->block_size);
  275. read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 1], (uint8_t *)tmp);
  276. if (!((uint32_t *)tmp)[c]) {
  277. unsigned int block_no = allocate_block(this);
  278. if (!block_no) goto no_space_free;
  279. ((uint32_t *)tmp)[c] = block_no;
  280. write_block(this, inode->block[EXT2_DIRECT_BLOCKS + 1], (uint8_t *)tmp);
  281. }
  282. uint32_t nblock = ((uint32_t *)tmp)[c];
  283. read_block(this, nblock, (uint8_t *)tmp);
  284. ((uint32_t *)tmp)[d] = rblock;
  285. write_block(this, nblock, (uint8_t *)tmp);
  286. free(tmp);
  287. return E_SUCCESS;
  288. } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p + p) {
  289. a = iblock - EXT2_DIRECT_BLOCKS;
  290. b = a - p;
  291. c = b - p * p;
  292. d = c / (p * p);
  293. e = c - d * p * p;
  294. f = e / p;
  295. g = e - f * p;
  296. if (!inode->block[EXT2_DIRECT_BLOCKS+2]) {
  297. unsigned int block_no = allocate_block(this);
  298. if (!block_no) return E_NOSPACE;
  299. inode->block[EXT2_DIRECT_BLOCKS+2] = block_no;
  300. write_inode(this, inode, inode_no);
  301. }
  302. tmp = malloc(this->block_size);
  303. read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 2], (uint8_t *)tmp);
  304. if (!((uint32_t *)tmp)[d]) {
  305. unsigned int block_no = allocate_block(this);
  306. if (!block_no) goto no_space_free;
  307. ((uint32_t *)tmp)[d] = block_no;
  308. write_block(this, inode->block[EXT2_DIRECT_BLOCKS + 2], (uint8_t *)tmp);
  309. }
  310. uint32_t nblock = ((uint32_t *)tmp)[d];
  311. read_block(this, nblock, (uint8_t *)tmp);
  312. if (!((uint32_t *)tmp)[f]) {
  313. unsigned int block_no = allocate_block(this);
  314. if (!block_no) goto no_space_free;
  315. ((uint32_t *)tmp)[f] = block_no;
  316. write_block(this, nblock, (uint8_t *)tmp);
  317. }
  318. nblock = ((uint32_t *)tmp)[f];
  319. read_block(this, nblock, (uint8_t *)tmp);
  320. ((uint32_t *)tmp)[g] = nblock;
  321. write_block(this, nblock, (uint8_t *)tmp);
  322. free(tmp);
  323. return E_SUCCESS;
  324. }
  325. debug_print(CRITICAL, "EXT2 driver tried to write to a block number that was too high (%d)", rblock);
  326. return E_BADBLOCK;
  327. no_space_free:
  328. free(tmp);
  329. return E_NOSPACE;
  330. }
  331. /**
  332. * ext2->get_block_number Given an inode block number, get the real block number.
  333. *
  334. * @param inode Inode to operate on
  335. * @param iblock Block offset within the inode
  336. * @returns Real block number
  337. */
  338. static unsigned int get_block_number(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int iblock) {
  339. unsigned int p = this->pointers_per_block;
  340. /* We're going to do some crazy math in a bit... */
  341. unsigned int a, b, c, d, e, f, g;
  342. uint8_t * tmp;
  343. if (iblock < EXT2_DIRECT_BLOCKS) {
  344. return inode->block[iblock];
  345. } else if (iblock < EXT2_DIRECT_BLOCKS + p) {
  346. /* XXX what if inode->block[EXT2_DIRECT_BLOCKS] isn't set? */
  347. tmp = malloc(this->block_size);
  348. read_block(this, inode->block[EXT2_DIRECT_BLOCKS], (uint8_t *)tmp);
  349. unsigned int out = ((uint32_t *)tmp)[iblock - EXT2_DIRECT_BLOCKS];
  350. free(tmp);
  351. return out;
  352. } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p) {
  353. a = iblock - EXT2_DIRECT_BLOCKS;
  354. b = a - p;
  355. c = b / p;
  356. d = b - c * p;
  357. tmp = malloc(this->block_size);
  358. read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 1], (uint8_t *)tmp);
  359. uint32_t nblock = ((uint32_t *)tmp)[c];
  360. read_block(this, nblock, (uint8_t *)tmp);
  361. unsigned int out = ((uint32_t *)tmp)[d];
  362. free(tmp);
  363. return out;
  364. } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p + p) {
  365. a = iblock - EXT2_DIRECT_BLOCKS;
  366. b = a - p;
  367. c = b - p * p;
  368. d = c / (p * p);
  369. e = c - d * p * p;
  370. f = e / p;
  371. g = e - f * p;
  372. tmp = malloc(this->block_size);
  373. read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 2], (uint8_t *)tmp);
  374. uint32_t nblock = ((uint32_t *)tmp)[d];
  375. read_block(this, nblock, (uint8_t *)tmp);
  376. nblock = ((uint32_t *)tmp)[f];
  377. read_block(this, nblock, (uint8_t *)tmp);
  378. unsigned int out = ((uint32_t *)tmp)[g];
  379. free(tmp);
  380. return out;
  381. }
  382. debug_print(CRITICAL, "EXT2 driver tried to read to a block number that was too high (%d)", iblock);
  383. return 0;
  384. }
  385. static int write_inode(ext2_fs_t * this, ext2_inodetable_t *inode, uint32_t index) {
  386. uint32_t group = index / this->inodes_per_group;
  387. if (group > BGDS) {
  388. return E_BADBLOCK;
  389. }
  390. uint32_t inode_table_block = BGD[group].inode_table;
  391. index -= group * this->inodes_per_group;
  392. uint32_t block_offset = ((index - 1) * this->inode_size) / this->block_size;
  393. uint32_t offset_in_block = (index - 1) - block_offset * (this->block_size / this->inode_size);
  394. ext2_inodetable_t *inodet = malloc(this->block_size);
  395. /* Read the current table block */
  396. read_block(this, inode_table_block + block_offset, (uint8_t *)inodet);
  397. memcpy((uint8_t *)((uint32_t)inodet + offset_in_block * this->inode_size), inode, this->inode_size);
  398. write_block(this, inode_table_block + block_offset, (uint8_t *)inodet);
  399. free(inodet);
  400. return E_SUCCESS;
  401. }
  402. static unsigned int allocate_block(ext2_fs_t * this) {
  403. unsigned int block_no = 0;
  404. unsigned int block_offset = 0;
  405. unsigned int group = 0;
  406. uint8_t * bg_buffer = malloc(this->block_size);
  407. for (unsigned int i = 0; i < BGDS; ++i) {
  408. if (BGD[i].free_blocks_count > 0) {
  409. read_block(this, BGD[i].block_bitmap, (uint8_t *)bg_buffer);
  410. while (BLOCKBIT(block_offset)) {
  411. ++block_offset;
  412. }
  413. block_no = block_offset + SB->blocks_per_group * i;
  414. group = i;
  415. break;
  416. }
  417. }
  418. if (!block_no) {
  419. debug_print(CRITICAL, "No available blocks, disk is out of space!");
  420. free(bg_buffer);
  421. return 0;
  422. }
  423. debug_print(WARNING, "allocating block #%d (group %d)", block_no, group);
  424. BLOCKBYTE(block_offset) |= SETBIT(block_offset);
  425. write_block(this, BGD[group].block_bitmap, (uint8_t *)bg_buffer);
  426. BGD[group].free_blocks_count--;
  427. for (int i = 0; i < this->bgd_block_span; ++i) {
  428. write_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i));
  429. }
  430. SB->free_blocks_count--;
  431. rewrite_superblock(this);
  432. memset(bg_buffer, 0x00, this->block_size);
  433. write_block(this, block_no, bg_buffer);
  434. free(bg_buffer);
  435. return block_no;
  436. }
  437. /**
  438. * ext2->allocate_inode_block Allocate a block in an inode.
  439. *
  440. * @param inode Inode to operate on
  441. * @param inode_no Number of the inode (this is not part of the struct)
  442. * @param block Block within inode to allocate
  443. * @returns Error code or E_SUCCESS
  444. */
  445. static int allocate_inode_block(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int inode_no, unsigned int block) {
  446. debug_print(NOTICE, "Allocating block #%d for inode #%d", block, inode_no);
  447. unsigned int block_no = allocate_block(this);
  448. if (!block_no) return E_NOSPACE;
  449. set_block_number(this, inode, inode_no, block, block_no);
  450. unsigned int t = (block + 1) * (this->block_size / 512);
  451. if (inode->blocks < t) {
  452. debug_print(NOTICE, "Setting inode->blocks to %d = (%d fs blocks)", t, t / (this->block_size / 512));
  453. inode->blocks = t;
  454. }
  455. write_inode(this, inode, inode_no);
  456. return E_SUCCESS;
  457. }
  458. /**
  459. * ext2->inode_read_block
  460. *
  461. * @param inode
  462. * @param no
  463. * @param block
  464. * @parma buf
  465. * @returns Real block number for reference.
  466. */
  467. static unsigned int inode_read_block(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int block, uint8_t * buf) {
  468. if (block >= inode->blocks / (this->block_size / 512)) {
  469. memset(buf, 0x00, this->block_size);
  470. debug_print(WARNING, "Tried to read an invalid block. Asked for %d (0-indexed), but inode only has %d!", block, inode->blocks / (this->block_size / 512));
  471. return 0;
  472. }
  473. unsigned int real_block = get_block_number(this, inode, block);
  474. read_block(this, real_block, buf);
  475. return real_block;
  476. }
  477. /**
  478. * ext2->inode_write_block
  479. */
  480. static unsigned int inode_write_block(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int inode_no, unsigned int block, uint8_t * buf) {
  481. if (block >= inode->blocks / (this->block_size / 512)) {
  482. debug_print(WARNING, "Attempting to write beyond the existing allocated blocks for this inode.");
  483. debug_print(WARNING, "Inode %d, Block %d", inode_no, block);
  484. }
  485. debug_print(WARNING, "clearing and allocating up to required blocks (block=%d, %d)", block, inode->blocks);
  486. char * empty = NULL;
  487. while (block >= inode->blocks / (this->block_size / 512)) {
  488. allocate_inode_block(this, inode, inode_no, inode->blocks / (this->block_size / 512));
  489. refresh_inode(this, inode, inode_no);
  490. }
  491. if (empty) free(empty);
  492. debug_print(WARNING, "... done");
  493. unsigned int real_block = get_block_number(this, inode, block);
  494. debug_print(WARNING, "Writing virtual block %d for inode %d maps to real block %d", block, inode_no, real_block);
  495. write_block(this, real_block, buf);
  496. return real_block;
  497. }
  498. /**
  499. * ext2->create_entry
  500. *
  501. * @returns Error code or E_SUCCESS
  502. */
  503. static int create_entry(fs_node_t * parent, char * name, uint32_t inode) {
  504. ext2_fs_t * this = (ext2_fs_t *)parent->device;
  505. ext2_inodetable_t * pinode = read_inode(this,parent->inode);
  506. if (((pinode->mode & EXT2_S_IFDIR) == 0) || (name == NULL)) {
  507. debug_print(WARNING, "Attempted to allocate an inode in a parent that was not a directory.");
  508. return E_BADPARENT;
  509. }
  510. debug_print(WARNING, "Creating a directory entry for %s pointing to inode %d.", name, inode);
  511. /* okay, how big is it... */
  512. debug_print(WARNING, "We need to append %d bytes to the direcotry.", sizeof(ext2_dir_t) + strlen(name));
  513. unsigned int rec_len = sizeof(ext2_dir_t) + strlen(name);
  514. rec_len += (rec_len % 4) ? (4 - (rec_len % 4)) : 0;
  515. debug_print(WARNING, "Our directory entry looks like this:");
  516. debug_print(WARNING, " inode = %d", inode);
  517. debug_print(WARNING, " rec_len = %d", rec_len);
  518. debug_print(WARNING, " name_len = %d", strlen(name));
  519. debug_print(WARNING, " file_type = %d", 0);
  520. debug_print(WARNING, " name = %s", name);
  521. debug_print(WARNING, "The inode size is marked as: %d", pinode->size);
  522. debug_print(WARNING, "Block size is %d", this->block_size);
  523. uint8_t * block = malloc(this->block_size);
  524. uint8_t block_nr = 0;
  525. uint32_t dir_offset = 0;
  526. uint32_t total_offset = 0;
  527. int modify_or_replace = 0;
  528. ext2_dir_t *previous;
  529. inode_read_block(this, pinode, block_nr, block);
  530. while (total_offset < pinode->size) {
  531. if (dir_offset >= this->block_size) {
  532. block_nr++;
  533. dir_offset -= this->block_size;
  534. inode_read_block(this, pinode, block_nr, block);
  535. }
  536. ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset);
  537. unsigned int sreclen = d_ent->name_len + sizeof(ext2_dir_t);
  538. sreclen += (sreclen % 4) ? (4 - (sreclen % 4)) : 0;
  539. {
  540. char f[d_ent->name_len+1];
  541. memcpy(f, d_ent->name, d_ent->name_len);
  542. f[d_ent->name_len] = 0;
  543. debug_print(WARNING, " * file: %s", f);
  544. }
  545. debug_print(WARNING, " rec_len: %d", d_ent->rec_len);
  546. debug_print(WARNING, " type: %d", d_ent->file_type);
  547. debug_print(WARNING, " namel: %d", d_ent->name_len);
  548. debug_print(WARNING, " inode: %d", d_ent->inode);
  549. if (d_ent->rec_len != sreclen && total_offset + d_ent->rec_len == pinode->size) {
  550. debug_print(WARNING, " - should be %d, but instead points to end of block", sreclen);
  551. debug_print(WARNING, " - we've hit the end, should change this pointer");
  552. dir_offset += sreclen;
  553. total_offset += sreclen;
  554. modify_or_replace = 1; /* Modify */
  555. previous = d_ent;
  556. break;
  557. }
  558. if (d_ent->inode == 0) {
  559. modify_or_replace = 2; /* Replace */
  560. }
  561. dir_offset += d_ent->rec_len;
  562. total_offset += d_ent->rec_len;
  563. }
  564. if (!modify_or_replace) {
  565. debug_print(WARNING, "That's odd, this shouldn't have happened, we made it all the way here without hitting our two end conditions?");
  566. }
  567. if (modify_or_replace == 1) {
  568. debug_print(WARNING, "The last node in the list is a real node, we need to modify it.");
  569. if (dir_offset + rec_len >= this->block_size) {
  570. debug_print(WARNING, "Need to allocate more space, bail!");
  571. free(block);
  572. return E_NOSPACE;
  573. } else {
  574. unsigned int sreclen = previous->name_len + sizeof(ext2_dir_t);
  575. sreclen += (sreclen % 4) ? (4 - (sreclen % 4)) : 0;
  576. previous->rec_len = sreclen;
  577. debug_print(WARNING, "Set previous node rec_len to %d", sreclen);
  578. }
  579. } else if (modify_or_replace == 2) {
  580. debug_print(WARNING, "The last node in the list is a fake node, we'll replace it.");
  581. }
  582. debug_print(WARNING, " total_offset = 0x%x", total_offset);
  583. debug_print(WARNING, " dir_offset = 0x%x", dir_offset);
  584. ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset);
  585. d_ent->inode = inode;
  586. d_ent->rec_len = this->block_size - dir_offset;
  587. d_ent->name_len = strlen(name);
  588. d_ent->file_type = 0; /* This is unused */
  589. memcpy(d_ent->name, name, strlen(name));
  590. inode_write_block(this, pinode, parent->inode, block_nr, block);
  591. free(block);
  592. free(pinode);
  593. return E_NOSPACE;
  594. }
  595. static unsigned int allocate_inode(ext2_fs_t * this) {
  596. uint32_t node_no = 0;
  597. uint32_t node_offset = 0;
  598. uint32_t group = 0;
  599. uint8_t * bg_buffer = malloc(this->block_size);
  600. for (unsigned int i = 0; i < BGDS; ++i) {
  601. if (BGD[i].free_inodes_count > 0) {
  602. debug_print(NOTICE, "Group %d has %d free inodes.", i, BGD[i].free_inodes_count);
  603. read_block(this, BGD[i].inode_bitmap, (uint8_t *)bg_buffer);
  604. while (BLOCKBIT(node_offset)) {
  605. node_offset++;
  606. }
  607. node_no = node_offset + i * this->inodes_per_group + 1;
  608. group = i;
  609. break;
  610. }
  611. }
  612. if (!node_no) {
  613. debug_print(ERROR, "Ran out of inodes!");
  614. return 0;
  615. }
  616. BLOCKBYTE(node_offset) |= SETBIT(node_offset);
  617. write_block(this, BGD[group].inode_bitmap, (uint8_t *)bg_buffer);
  618. free(bg_buffer);
  619. BGD[group].free_inodes_count--;
  620. for (int i = 0; i < this->bgd_block_span; ++i) {
  621. write_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i));
  622. }
  623. SB->free_inodes_count--;
  624. rewrite_superblock(this);
  625. return node_no;
  626. }
  627. static int mkdir_ext2(fs_node_t * parent, char * name, uint16_t permission) {
  628. if (!name) return -EINVAL;
  629. ext2_fs_t * this = parent->device;
  630. /* first off, check if it exists */
  631. fs_node_t * check = finddir_ext2(parent, name);
  632. if (check) {
  633. debug_print(WARNING, "A file by this name already exists: %s", name);
  634. free(check);
  635. return -EEXIST;
  636. }
  637. /* Allocate an inode for it */
  638. unsigned int inode_no = allocate_inode(this);
  639. ext2_inodetable_t * inode = read_inode(this,inode_no);
  640. /* Set the access and creation times to now */
  641. inode->atime = now();
  642. inode->ctime = inode->atime;
  643. inode->mtime = inode->atime;
  644. inode->dtime = 0; /* This inode was never deleted */
  645. /* Empty the file */
  646. memset(inode->block, 0x00, sizeof(inode->block));
  647. inode->blocks = 0;
  648. inode->size = 0; /* empty */
  649. /* Assign it to root */
  650. inode->uid = current_process->user; /* user */
  651. inode->gid = current_process->user;
  652. /* misc */
  653. inode->faddr = 0;
  654. inode->links_count = 2; /* There's the parent's pointer to us, and our pointer to us. */
  655. inode->flags = 0;
  656. inode->osd1 = 0;
  657. inode->generation = 0;
  658. inode->file_acl = 0;
  659. inode->dir_acl = 0;
  660. /* File mode */
  661. inode->mode = EXT2_S_IFDIR;
  662. inode->mode |= 0xFFF & permission;
  663. /* Write the osd blocks to 0 */
  664. memset(inode->osd2, 0x00, sizeof(inode->osd2));
  665. /* Write out inode changes */
  666. write_inode(this, inode, inode_no);
  667. /* Now append the entry to the parent */
  668. create_entry(parent, name, inode_no);
  669. inode->size = this->block_size;
  670. write_inode(this, inode, inode_no);
  671. uint8_t * tmp = malloc(this->block_size);
  672. ext2_dir_t * t = calloc(12,1);
  673. t->inode = inode_no;
  674. t->rec_len = 12;
  675. t->name_len = 1;
  676. t->name[0] = '.';
  677. memcpy(&tmp[0], t, 12);
  678. t->inode = parent->inode;
  679. t->name_len = 2;
  680. t->name[1] = '.';
  681. t->rec_len = this->block_size - 12;
  682. memcpy(&tmp[12], t, 12);
  683. free(t);
  684. inode_write_block(this, inode, inode_no, 0, tmp);
  685. free(inode);
  686. free(tmp);
  687. /* Update parent link count */
  688. ext2_inodetable_t * pinode = read_inode(this, parent->inode);
  689. pinode->links_count++;
  690. write_inode(this, pinode, parent->inode);
  691. free(pinode);
  692. /* Update directory count in block group descriptor */
  693. uint32_t group = inode_no / this->inodes_per_group;
  694. BGD[group].used_dirs_count++;
  695. for (int i = 0; i < this->bgd_block_span; ++i) {
  696. write_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i));
  697. }
  698. ext2_sync(this);
  699. return 0;
  700. }
  701. static int create_ext2(fs_node_t * parent, char * name, uint16_t permission) {
  702. if (!name) return -EINVAL;
  703. ext2_fs_t * this = parent->device;
  704. /* first off, check if it exists */
  705. fs_node_t * check = finddir_ext2(parent, name);
  706. if (check) {
  707. debug_print(WARNING, "A file by this name already exists: %s", name);
  708. free(check);
  709. return -EEXIST;
  710. }
  711. /* Allocate an inode for it */
  712. unsigned int inode_no = allocate_inode(this);
  713. ext2_inodetable_t * inode = read_inode(this,inode_no);
  714. /* Set the access and creation times to now */
  715. inode->atime = now();
  716. inode->ctime = inode->atime;
  717. inode->mtime = inode->atime;
  718. inode->dtime = 0; /* This inode was never deleted */
  719. /* Empty the file */
  720. memset(inode->block, 0x00, sizeof(inode->block));
  721. inode->blocks = 0;
  722. inode->size = 0; /* empty */
  723. /* Assign it to root */
  724. inode->uid = current_process->user; /* user */
  725. inode->gid = current_process->user;
  726. /* misc */
  727. inode->faddr = 0;
  728. inode->links_count = 1; /* The one we're about to create. */
  729. inode->flags = 0;
  730. inode->osd1 = 0;
  731. inode->generation = 0;
  732. inode->file_acl = 0;
  733. inode->dir_acl = 0;
  734. /* File mode */
  735. /* TODO: Use the mask from `permission` */
  736. inode->mode = EXT2_S_IFREG;
  737. inode->mode |= 0xFFF & permission;
  738. /* Write the osd blocks to 0 */
  739. memset(inode->osd2, 0x00, sizeof(inode->osd2));
  740. /* Write out inode changes */
  741. write_inode(this, inode, inode_no);
  742. /* Now append the entry to the parent */
  743. create_entry(parent, name, inode_no);
  744. free(inode);
  745. ext2_sync(this);
  746. return 0;
  747. }
  748. static int chmod_ext2(fs_node_t * node, int mode) {
  749. ext2_fs_t * this = node->device;
  750. ext2_inodetable_t * inode = read_inode(this,node->inode);
  751. inode->mode = (inode->mode & 0xFFFFF000) | mode;
  752. write_inode(this, inode, node->inode);
  753. ext2_sync(this);
  754. return 0;
  755. }
  756. /**
  757. * direntry_ext2
  758. */
  759. static ext2_dir_t * direntry_ext2(ext2_fs_t * this, ext2_inodetable_t * inode, uint32_t no, uint32_t index) {
  760. uint8_t *block = malloc(this->block_size);
  761. uint8_t block_nr = 0;
  762. inode_read_block(this, inode, block_nr, block);
  763. uint32_t dir_offset = 0;
  764. uint32_t total_offset = 0;
  765. uint32_t dir_index = 0;
  766. while (total_offset < inode->size && dir_index <= index) {
  767. ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset);
  768. if (d_ent->inode != 0 && dir_index == index) {
  769. ext2_dir_t *out = malloc(d_ent->rec_len);
  770. memcpy(out, d_ent, d_ent->rec_len);
  771. free(block);
  772. return out;
  773. }
  774. dir_offset += d_ent->rec_len;
  775. total_offset += d_ent->rec_len;
  776. if (d_ent->inode) {
  777. dir_index++;
  778. }
  779. if (dir_offset >= this->block_size) {
  780. block_nr++;
  781. dir_offset -= this->block_size;
  782. inode_read_block(this, inode, block_nr, block);
  783. }
  784. }
  785. free(block);
  786. return NULL;
  787. }
  788. /**
  789. * finddir_ext2
  790. */
  791. static fs_node_t * finddir_ext2(fs_node_t *node, char *name) {
  792. ext2_fs_t * this = (ext2_fs_t *)node->device;
  793. ext2_inodetable_t *inode = read_inode(this,node->inode);
  794. assert(inode->mode & EXT2_S_IFDIR);
  795. uint8_t * block = malloc(this->block_size);
  796. ext2_dir_t *direntry = NULL;
  797. uint8_t block_nr = 0;
  798. inode_read_block(this, inode, block_nr, block);
  799. uint32_t dir_offset = 0;
  800. uint32_t total_offset = 0;
  801. while (total_offset < inode->size) {
  802. if (dir_offset >= this->block_size) {
  803. block_nr++;
  804. dir_offset -= this->block_size;
  805. inode_read_block(this, inode, block_nr, block);
  806. }
  807. ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset);
  808. if (d_ent->inode == 0 || strlen(name) != d_ent->name_len) {
  809. dir_offset += d_ent->rec_len;
  810. total_offset += d_ent->rec_len;
  811. continue;
  812. }
  813. char *dname = malloc(sizeof(char) * (d_ent->name_len + 1));
  814. memcpy(dname, &(d_ent->name), d_ent->name_len);
  815. dname[d_ent->name_len] = '\0';
  816. if (!strcmp(dname, name)) {
  817. free(dname);
  818. direntry = malloc(d_ent->rec_len);
  819. memcpy(direntry, d_ent, d_ent->rec_len);
  820. break;
  821. }
  822. free(dname);
  823. dir_offset += d_ent->rec_len;
  824. total_offset += d_ent->rec_len;
  825. }
  826. free(inode);
  827. if (!direntry) {
  828. free(block);
  829. return NULL;
  830. }
  831. fs_node_t *outnode = malloc(sizeof(fs_node_t));
  832. memset(outnode, 0, sizeof(fs_node_t));
  833. inode = read_inode(this, direntry->inode);
  834. if (!node_from_file(this, inode, direntry, outnode)) {
  835. debug_print(CRITICAL, "Oh dear. Couldn't allocate the outnode?");
  836. }
  837. free(direntry);
  838. free(inode);
  839. free(block);
  840. return outnode;
  841. }
  842. static int unlink_ext2(fs_node_t * node, char * name) {
  843. /* XXX this is a very bad implementation */
  844. ext2_fs_t * this = (ext2_fs_t *)node->device;
  845. ext2_inodetable_t *inode = read_inode(this,node->inode);
  846. assert(inode->mode & EXT2_S_IFDIR);
  847. uint8_t * block = malloc(this->block_size);
  848. ext2_dir_t *direntry = NULL;
  849. uint8_t block_nr = 0;
  850. inode_read_block(this, inode, block_nr, block);
  851. uint32_t dir_offset = 0;
  852. uint32_t total_offset = 0;
  853. while (total_offset < inode->size) {
  854. if (dir_offset >= this->block_size) {
  855. block_nr++;
  856. dir_offset -= this->block_size;
  857. inode_read_block(this, inode, block_nr, block);
  858. }
  859. ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset);
  860. if (d_ent->inode == 0 || strlen(name) != d_ent->name_len) {
  861. dir_offset += d_ent->rec_len;
  862. total_offset += d_ent->rec_len;
  863. continue;
  864. }
  865. char *dname = malloc(sizeof(char) * (d_ent->name_len + 1));
  866. memcpy(dname, &(d_ent->name), d_ent->name_len);
  867. dname[d_ent->name_len] = '\0';
  868. if (!strcmp(dname, name)) {
  869. free(dname);
  870. direntry = d_ent;
  871. break;
  872. }
  873. free(dname);
  874. dir_offset += d_ent->rec_len;
  875. total_offset += d_ent->rec_len;
  876. }
  877. free(inode);
  878. if (!direntry) {
  879. free(block);
  880. return -ENOENT;
  881. }
  882. direntry->inode = 0;
  883. inode_write_block(this, inode, node->inode, block_nr, block);
  884. free(block);
  885. ext2_sync(this);
  886. return 0;
  887. }
  888. static void refresh_inode(ext2_fs_t * this, ext2_inodetable_t * inodet, uint32_t inode) {
  889. uint32_t group = inode / this->inodes_per_group;
  890. if (group > BGDS) {
  891. return;
  892. }
  893. uint32_t inode_table_block = BGD[group].inode_table;
  894. inode -= group * this->inodes_per_group; // adjust index within group
  895. uint32_t block_offset = ((inode - 1) * this->inode_size) / this->block_size;
  896. uint32_t offset_in_block = (inode - 1) - block_offset * (this->block_size / this->inode_size);
  897. uint8_t * buf = malloc(this->block_size);
  898. read_block(this, inode_table_block + block_offset, buf);
  899. ext2_inodetable_t *inodes = (ext2_inodetable_t *)buf;
  900. memcpy(inodet, (uint8_t *)((uint32_t)inodes + offset_in_block * this->inode_size), this->inode_size);
  901. free(buf);
  902. }
  903. /**
  904. * read_inode
  905. */
  906. static ext2_inodetable_t * read_inode(ext2_fs_t * this, uint32_t inode) {
  907. ext2_inodetable_t *inodet = malloc(this->inode_size);
  908. refresh_inode(this, inodet, inode);
  909. return inodet;
  910. }
  911. static uint32_t read_ext2(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
  912. ext2_fs_t * this = (ext2_fs_t *)node->device;
  913. ext2_inodetable_t * inode = read_inode(this, node->inode);
  914. uint32_t end;
  915. if (inode->size == 0) return 0;
  916. if (offset + size > inode->size) {
  917. end = inode->size;
  918. } else {
  919. end = offset + size;
  920. }
  921. uint32_t start_block = offset / this->block_size;
  922. uint32_t end_block = end / this->block_size;
  923. uint32_t end_size = end - end_block * this->block_size;
  924. uint32_t size_to_read = end - offset;
  925. uint8_t * buf = malloc(this->block_size);
  926. if (start_block == end_block) {
  927. inode_read_block(this, inode, start_block, buf);
  928. memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % this->block_size)), size_to_read);
  929. } else {
  930. uint32_t block_offset;
  931. uint32_t blocks_read = 0;
  932. for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) {
  933. if (block_offset == start_block) {
  934. inode_read_block(this, inode, block_offset, buf);
  935. memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % this->block_size)), this->block_size - (offset % this->block_size));
  936. } else {
  937. inode_read_block(this, inode, block_offset, buf);
  938. memcpy(buffer + this->block_size * blocks_read - (offset % this->block_size), buf, this->block_size);
  939. }
  940. }
  941. if (end_size) {
  942. inode_read_block(this, inode, end_block, buf);
  943. memcpy(buffer + this->block_size * blocks_read - (offset % this->block_size), buf, end_size);
  944. }
  945. }
  946. free(inode);
  947. free(buf);
  948. return size_to_read;
  949. }
  950. static uint32_t write_inode_buffer(ext2_fs_t * this, ext2_inodetable_t * inode, uint32_t inode_number, uint32_t offset, uint32_t size, uint8_t *buffer) {
  951. uint32_t end = offset + size;
  952. if (end > inode->size) {
  953. inode->size = end;
  954. write_inode(this, inode, inode_number);
  955. }
  956. uint32_t start_block = offset / this->block_size;
  957. uint32_t end_block = end / this->block_size;
  958. uint32_t end_size = end - end_block * this->block_size;
  959. uint32_t size_to_read = end - offset;
  960. uint8_t * buf = malloc(this->block_size);
  961. if (start_block == end_block) {
  962. inode_read_block(this, inode, start_block, buf);
  963. memcpy((uint8_t *)(((uint32_t)buf) + (offset % this->block_size)), buffer, size_to_read);
  964. inode_write_block(this, inode, inode_number, start_block, buf);
  965. } else {
  966. uint32_t block_offset;
  967. uint32_t blocks_read = 0;
  968. for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) {
  969. if (block_offset == start_block) {
  970. int b = inode_read_block(this, inode, block_offset, buf);
  971. memcpy((uint8_t *)(((uint32_t)buf) + (offset % this->block_size)), buffer, this->block_size - (offset % this->block_size));
  972. inode_write_block(this, inode, inode_number, block_offset, buf);
  973. if (!b) {
  974. refresh_inode(this, inode, inode_number);
  975. }
  976. } else {
  977. int b = inode_read_block(this, inode, block_offset, buf);
  978. memcpy(buf, buffer + this->block_size * blocks_read - (offset % this->block_size), this->block_size);
  979. inode_write_block(this, inode, inode_number, block_offset, buf);
  980. if (!b) {
  981. refresh_inode(this, inode, inode_number);
  982. }
  983. }
  984. }
  985. if (end_size) {
  986. inode_read_block(this, inode, end_block, buf);
  987. memcpy(buf, buffer + this->block_size * blocks_read - (offset % this->block_size), end_size);
  988. inode_write_block(this, inode, inode_number, end_block, buf);
  989. }
  990. }
  991. free(buf);
  992. return size_to_read;
  993. }
  994. static uint32_t write_ext2(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
  995. ext2_fs_t * this = (ext2_fs_t *)node->device;
  996. ext2_inodetable_t * inode = read_inode(this, node->inode);
  997. uint32_t rv = write_inode_buffer(this, inode, node->inode, offset, size, buffer);
  998. free(inode);
  999. return rv;
  1000. }
  1001. static void open_ext2(fs_node_t *node, unsigned int flags) {
  1002. ext2_fs_t * this = node->device;
  1003. if (flags & O_TRUNC) {
  1004. /* Uh, herp */
  1005. ext2_inodetable_t * inode = read_inode(this,node->inode);
  1006. inode->size = 0;
  1007. write_inode(this, inode, node->inode);
  1008. }
  1009. }
  1010. static void close_ext2(fs_node_t *node) {
  1011. /* Nothing to do here */
  1012. }
  1013. /**
  1014. * readdir_ext2
  1015. */
  1016. static struct dirent * readdir_ext2(fs_node_t *node, uint32_t index) {
  1017. ext2_fs_t * this = (ext2_fs_t *)node->device;
  1018. ext2_inodetable_t *inode = read_inode(this, node->inode);
  1019. assert(inode->mode & EXT2_S_IFDIR);
  1020. ext2_dir_t *direntry = direntry_ext2(this, inode, node->inode, index);
  1021. if (!direntry) {
  1022. free(inode);
  1023. return NULL;
  1024. }
  1025. struct dirent *dirent = malloc(sizeof(struct dirent));
  1026. memcpy(&dirent->name, &direntry->name, direntry->name_len);
  1027. dirent->name[direntry->name_len] = '\0';
  1028. dirent->ino = direntry->inode;
  1029. free(direntry);
  1030. free(inode);
  1031. return dirent;
  1032. }
  1033. static int symlink_ext2(fs_node_t * parent, char * target, char * name) {
  1034. if (!name) return -EINVAL;
  1035. ext2_fs_t * this = parent->device;
  1036. /* first off, check if it exists */
  1037. fs_node_t * check = finddir_ext2(parent, name);
  1038. if (check) {
  1039. debug_print(WARNING, "A file by this name already exists: %s", name);
  1040. free(check);
  1041. return -EEXIST; /* this should probably have a return value... */
  1042. }
  1043. /* Allocate an inode for it */
  1044. unsigned int inode_no = allocate_inode(this);
  1045. ext2_inodetable_t * inode = read_inode(this,inode_no);
  1046. /* Set the access and creation times to now */
  1047. inode->atime = now();
  1048. inode->ctime = inode->atime;
  1049. inode->mtime = inode->atime;
  1050. inode->dtime = 0; /* This inode was never deleted */
  1051. /* Empty the file */
  1052. memset(inode->block, 0x00, sizeof(inode->block));
  1053. inode->blocks = 0;
  1054. inode->size = 0; /* empty */
  1055. /* Assign it to current user */
  1056. inode->uid = current_process->user;
  1057. inode->gid = current_process->user;
  1058. /* misc */
  1059. inode->faddr = 0;
  1060. inode->links_count = 1; /* The one we're about to create. */
  1061. inode->flags = 0;
  1062. inode->osd1 = 0;
  1063. inode->generation = 0;
  1064. inode->file_acl = 0;
  1065. inode->dir_acl = 0;
  1066. inode->mode = EXT2_S_IFLNK;
  1067. /* I *think* this is what you're supposed to do with symlinks */
  1068. inode->mode |= 0777;
  1069. /* Write the osd blocks to 0 */
  1070. memset(inode->osd2, 0x00, sizeof(inode->osd2));
  1071. size_t target_len = strlen(target);
  1072. int embedded = target_len <= 60; // sizeof(_symlink(inode));
  1073. if (embedded) {
  1074. memcpy(_symlink(inode), target, target_len);
  1075. inode->size = target_len;
  1076. }
  1077. /* Write out inode changes */
  1078. write_inode(this, inode, inode_no);
  1079. /* Now append the entry to the parent */
  1080. create_entry(parent, name, inode_no);
  1081. /* If we didn't embed it in the inode just use write_inode_buffer to finish the job */
  1082. if (!embedded) {
  1083. write_inode_buffer(parent->device, inode, inode_no, 0, target_len, (uint8_t *)target);
  1084. }
  1085. free(inode);
  1086. ext2_sync(this);
  1087. return 0;
  1088. }
  1089. static int readlink_ext2(fs_node_t * node, char * buf, size_t size) {
  1090. ext2_fs_t * this = (ext2_fs_t *)node->device;
  1091. ext2_inodetable_t * inode = read_inode(this, node->inode);
  1092. size_t read_size = inode->size < size ? inode->size : size;
  1093. if (inode->size > 60) { //sizeof(_symlink(inode))) {
  1094. read_ext2(node, 0, read_size, (uint8_t *)buf);
  1095. } else {
  1096. memcpy(buf, _symlink(inode), read_size);
  1097. }
  1098. /* Believe it or not, we actually aren't supposed to include the nul in the length. */
  1099. if (read_size < size) {
  1100. buf[read_size] = '\0';
  1101. }
  1102. free(inode);
  1103. return read_size;
  1104. }
  1105. static uint32_t node_from_file(ext2_fs_t * this, ext2_inodetable_t *inode, ext2_dir_t *direntry, fs_node_t *fnode) {
  1106. if (!fnode) {
  1107. /* You didn't give me a node to write into, go **** yourself */
  1108. return 0;
  1109. }
  1110. /* Information from the direntry */
  1111. fnode->device = (void *)this;
  1112. fnode->inode = direntry->inode;
  1113. memcpy(&fnode->name, &direntry->name, direntry->name_len);
  1114. fnode->name[direntry->name_len] = '\0';
  1115. /* Information from the inode */
  1116. fnode->uid = inode->uid;
  1117. fnode->gid = inode->gid;
  1118. fnode->length = inode->size;
  1119. fnode->mask = inode->mode & 0xFFF;
  1120. fnode->nlink = inode->links_count;
  1121. /* File Flags */
  1122. fnode->flags = 0;
  1123. if ((inode->mode & EXT2_S_IFREG) == EXT2_S_IFREG) {
  1124. fnode->flags |= FS_FILE;
  1125. fnode->read = read_ext2;
  1126. fnode->write = write_ext2;
  1127. fnode->create = NULL;
  1128. fnode->mkdir = NULL;
  1129. fnode->readdir = NULL;
  1130. fnode->finddir = NULL;
  1131. fnode->symlink = NULL;
  1132. fnode->readlink = NULL;
  1133. }
  1134. if ((inode->mode & EXT2_S_IFDIR) == EXT2_S_IFDIR) {
  1135. fnode->flags |= FS_DIRECTORY;
  1136. fnode->create = create_ext2;
  1137. fnode->mkdir = mkdir_ext2;
  1138. fnode->readdir = readdir_ext2;
  1139. fnode->finddir = finddir_ext2;
  1140. fnode->unlink = unlink_ext2;
  1141. fnode->write = NULL;
  1142. fnode->symlink = symlink_ext2;
  1143. fnode->readlink = NULL;
  1144. }
  1145. if ((inode->mode & EXT2_S_IFBLK) == EXT2_S_IFBLK) {
  1146. fnode->flags |= FS_BLOCKDEVICE;
  1147. }
  1148. if ((inode->mode & EXT2_S_IFCHR) == EXT2_S_IFCHR) {
  1149. fnode->flags |= FS_CHARDEVICE;
  1150. }
  1151. if ((inode->mode & EXT2_S_IFIFO) == EXT2_S_IFIFO) {
  1152. fnode->flags |= FS_PIPE;
  1153. }
  1154. if ((inode->mode & EXT2_S_IFLNK) == EXT2_S_IFLNK) {
  1155. fnode->flags |= FS_SYMLINK;
  1156. fnode->read = NULL;
  1157. fnode->write = NULL;
  1158. fnode->create = NULL;
  1159. fnode->mkdir = NULL;
  1160. fnode->readdir = NULL;
  1161. fnode->finddir = NULL;
  1162. fnode->readlink = readlink_ext2;
  1163. }
  1164. fnode->atime = inode->atime;
  1165. fnode->mtime = inode->mtime;
  1166. fnode->ctime = inode->ctime;
  1167. debug_print(INFO, "file a/m/c times are %d/%d/%d", fnode->atime, fnode->mtime, fnode->ctime);
  1168. fnode->chmod = chmod_ext2;
  1169. fnode->open = open_ext2;
  1170. fnode->close = close_ext2;
  1171. fnode->ioctl = NULL;
  1172. return 1;
  1173. }
  1174. static uint32_t ext2_root(ext2_fs_t * this, ext2_inodetable_t *inode, fs_node_t *fnode) {
  1175. if (!fnode) {
  1176. return 0;
  1177. }
  1178. /* Information for root dir */
  1179. fnode->device = (void *)this;
  1180. fnode->inode = 2;
  1181. fnode->name[0] = '/';
  1182. fnode->name[1] = '\0';
  1183. /* Information from the inode */
  1184. fnode->uid = inode->uid;
  1185. fnode->gid = inode->gid;
  1186. fnode->length = inode->size;
  1187. fnode->mask = inode->mode & 0xFFF;
  1188. fnode->nlink = inode->links_count;
  1189. /* File Flags */
  1190. fnode->flags = 0;
  1191. if ((inode->mode & EXT2_S_IFREG) == EXT2_S_IFREG) {
  1192. debug_print(CRITICAL, "Root appears to be a regular file.");
  1193. debug_print(CRITICAL, "This is probably very, very wrong.");
  1194. return 0;
  1195. }
  1196. if ((inode->mode & EXT2_S_IFDIR) == EXT2_S_IFDIR) {
  1197. } else {
  1198. debug_print(CRITICAL, "Root doesn't appear to be a directory.");
  1199. debug_print(CRITICAL, "This is probably very, very wrong.");
  1200. debug_print(ERROR, "Other useful information:");
  1201. debug_print(ERROR, "%d", inode->uid);
  1202. debug_print(ERROR, "%d", inode->gid);
  1203. debug_print(ERROR, "%d", inode->size);
  1204. debug_print(ERROR, "%d", inode->mode);
  1205. debug_print(ERROR, "%d", inode->links_count);
  1206. return 0;
  1207. }
  1208. if ((inode->mode & EXT2_S_IFBLK) == EXT2_S_IFBLK) {
  1209. fnode->flags |= FS_BLOCKDEVICE;
  1210. }
  1211. if ((inode->mode & EXT2_S_IFCHR) == EXT2_S_IFCHR) {
  1212. fnode->flags |= FS_CHARDEVICE;
  1213. }
  1214. if ((inode->mode & EXT2_S_IFIFO) == EXT2_S_IFIFO) {
  1215. fnode->flags |= FS_PIPE;
  1216. }
  1217. if ((inode->mode & EXT2_S_IFLNK) == EXT2_S_IFLNK) {
  1218. fnode->flags |= FS_SYMLINK;
  1219. }
  1220. fnode->atime = inode->atime;
  1221. fnode->mtime = inode->mtime;
  1222. fnode->ctime = inode->ctime;
  1223. fnode->flags |= FS_DIRECTORY;
  1224. fnode->read = NULL;
  1225. fnode->write = NULL;
  1226. fnode->chmod = chmod_ext2;
  1227. fnode->open = open_ext2;
  1228. fnode->close = close_ext2;
  1229. fnode->readdir = readdir_ext2;
  1230. fnode->finddir = finddir_ext2;
  1231. fnode->ioctl = NULL;
  1232. fnode->create = create_ext2;
  1233. fnode->mkdir = mkdir_ext2;
  1234. fnode->unlink = unlink_ext2;
  1235. return 1;
  1236. }
  1237. static fs_node_t * mount_ext2(fs_node_t * block_device, int flags) {
  1238. debug_print(NOTICE, "Mounting ext2 file system...");
  1239. ext2_fs_t * this = malloc(sizeof(ext2_fs_t));
  1240. memset(this, 0x00, sizeof(ext2_fs_t));
  1241. this->flags = flags;
  1242. this->block_device = block_device;
  1243. this->block_size = 1024;
  1244. vfs_lock(this->block_device);
  1245. SB = malloc(this->block_size);
  1246. debug_print(INFO, "Reading superblock...");
  1247. read_block(this, 1, (uint8_t *)SB);
  1248. if (SB->magic != EXT2_SUPER_MAGIC) {
  1249. debug_print(ERROR, "... not an EXT2 filesystem? (magic didn't match, got 0x%x)", SB->magic);
  1250. return NULL;
  1251. }
  1252. this->inode_size = SB->inode_size;
  1253. if (SB->inode_size == 0) {
  1254. this->inode_size = 128;
  1255. }
  1256. this->block_size = 1024 << SB->log_block_size;
  1257. this->cache_entries = 10240;
  1258. if (this->block_size > 2048) {
  1259. this->cache_entries /= 4;
  1260. }
  1261. debug_print(INFO, "bs=%d, cache entries=%d", this->block_size, this->cache_entries);
  1262. this->pointers_per_block = this->block_size / 4;
  1263. debug_print(INFO, "Log block size = %d -> %d", SB->log_block_size, this->block_size);
  1264. BGDS = SB->blocks_count / SB->blocks_per_group;
  1265. if (SB->blocks_per_group * BGDS < SB->blocks_count) {
  1266. BGDS += 1;
  1267. }
  1268. this->inodes_per_group = SB->inodes_count / BGDS;
  1269. if (!(this->flags & EXT2_FLAG_NOCACHE)) {
  1270. debug_print(INFO, "Allocating cache...");
  1271. DC = malloc(sizeof(ext2_disk_cache_entry_t) * this->cache_entries);
  1272. this->cache_data = calloc(this->block_size, this->cache_entries);
  1273. for (uint32_t i = 0; i < this->cache_entries; ++i) {
  1274. DC[i].block_no = 0;
  1275. DC[i].dirty = 0;
  1276. DC[i].last_use = 0;
  1277. DC[i].block = this->cache_data + i * this->block_size;
  1278. if (i % 128 == 0) {
  1279. debug_print(INFO, "Allocated cache block #%d", i+1);
  1280. }
  1281. }
  1282. debug_print(INFO, "Allocated cache.");
  1283. } else {
  1284. DC = NULL;
  1285. debug_print(NOTICE, "ext2 cache is disabled (nocache)");
  1286. }
  1287. // load the block group descriptors
  1288. this->bgd_block_span = sizeof(ext2_bgdescriptor_t) * BGDS / this->block_size + 1;
  1289. BGD = malloc(this->block_size * this->bgd_block_span);
  1290. debug_print(INFO, "bgd_block_span = %d", this->bgd_block_span);
  1291. this->bgd_offset = 2;
  1292. if (this->block_size > 1024) {
  1293. this->bgd_offset = 1;
  1294. }
  1295. for (int i = 0; i < this->bgd_block_span; ++i) {
  1296. read_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i));
  1297. }
  1298. #ifdef DEBUG_BLOCK_DESCRIPTORS
  1299. char * bg_buffer = malloc(this->block_size * sizeof(char));
  1300. for (uint32_t i = 0; i < BGDS; ++i) {
  1301. debug_print(INFO, "Block Group Descriptor #%d @ %d", i, this->bgd_offset + i * SB->blocks_per_group);
  1302. debug_print(INFO, "\tBlock Bitmap @ %d", BGD[i].block_bitmap); {
  1303. debug_print(INFO, "\t\tExamining block bitmap at %d", BGD[i].block_bitmap);
  1304. read_block(this, BGD[i].block_bitmap, (uint8_t *)bg_buffer);
  1305. uint32_t j = 0;
  1306. while (BLOCKBIT(j)) {
  1307. ++j;
  1308. }
  1309. debug_print(INFO, "\t\tFirst free block in group is %d", j + BGD[i].block_bitmap - 2);
  1310. }
  1311. debug_print(INFO, "\tInode Bitmap @ %d", BGD[i].inode_bitmap); {
  1312. debug_print(INFO, "\t\tExamining inode bitmap at %d", BGD[i].inode_bitmap);
  1313. read_block(this, BGD[i].inode_bitmap, (uint8_t *)bg_buffer);
  1314. uint32_t j = 0;
  1315. while (BLOCKBIT(j)) {
  1316. ++j;
  1317. }
  1318. debug_print(INFO, "\t\tFirst free inode in group is %d", j + this->inodes_per_group * i + 1);
  1319. }
  1320. debug_print(INFO, "\tInode Table @ %d", BGD[i].inode_table);
  1321. debug_print(INFO, "\tFree Blocks = %d", BGD[i].free_blocks_count);
  1322. debug_print(INFO, "\tFree Inodes = %d", BGD[i].free_inodes_count);
  1323. }
  1324. free(bg_buffer);
  1325. #endif
  1326. ext2_inodetable_t *root_inode = read_inode(this, 2);
  1327. RN = (fs_node_t *)malloc(sizeof(fs_node_t));
  1328. if (!ext2_root(this, root_inode, RN)) {
  1329. return NULL;
  1330. }
  1331. debug_print(NOTICE, "Mounted EXT2 disk, root VFS node is at 0x%x", RN);
  1332. return RN;
  1333. }
  1334. fs_node_t * ext2_fs_mount(char * device, char * mount_path) {
  1335. char * arg = strdup(device);
  1336. char * argv[10];
  1337. int argc = tokenize(arg, ",", argv);
  1338. fs_node_t * dev = kopen(argv[0], 0);
  1339. if (!dev) {
  1340. debug_print(ERROR, "failed to open %s", device);
  1341. return NULL;
  1342. }
  1343. int flags = 0;
  1344. for (int i = 1; i < argc; ++i) {
  1345. if (!strcmp(argv[i],"nocache")) {
  1346. flags |= EXT2_FLAG_NOCACHE;
  1347. } else {
  1348. debug_print(WARNING, "Unrecognized option to ext2 driver: %s", argv[i]);
  1349. }
  1350. }
  1351. fs_node_t * fs = mount_ext2(dev, flags);
  1352. free(arg);
  1353. return fs;
  1354. }
  1355. int ext2_initialize(void) {
  1356. vfs_register("ext2", ext2_fs_mount);
  1357. return 0;
  1358. }
  1359. int ext2_finalize(void) {
  1360. return 0;
  1361. }
  1362. MODULE_DEF(ext2, ext2_initialize, ext2_finalize);