3
0

openfs.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * openfs.c --- open an ext2 filesystem
  4. *
  5. * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
  6. *
  7. * %Begin-Header%
  8. * This file may be redistributed under the terms of the GNU Public
  9. * License.
  10. * %End-Header%
  11. */
  12. #include <stdio.h>
  13. #include <string.h>
  14. #if HAVE_UNISTD_H
  15. #include <unistd.h>
  16. #endif
  17. #include <fcntl.h>
  18. #include <time.h>
  19. #if HAVE_SYS_STAT_H
  20. #include <sys/stat.h>
  21. #endif
  22. #if HAVE_SYS_TYPES_H
  23. #include <sys/types.h>
  24. #endif
  25. #include "ext2_fs.h"
  26. #include "ext2fs.h"
  27. #include "e2image.h"
  28. blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
  29. {
  30. int bg;
  31. int has_super = 0;
  32. int ret_blk;
  33. if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
  34. (i < fs->super->s_first_meta_bg))
  35. return (group_block + i + 1);
  36. bg = (fs->blocksize / sizeof (struct ext2_group_desc)) * i;
  37. if (ext2fs_bg_has_super(fs, bg))
  38. has_super = 1;
  39. ret_blk = (fs->super->s_first_data_block + has_super +
  40. (bg * fs->super->s_blocks_per_group));
  41. /*
  42. * If group_block is not the normal value, we're trying to use
  43. * the backup group descriptors and superblock --- so use the
  44. * alternate location of the second block group in the
  45. * metablock group. Ideally we should be testing each bg
  46. * descriptor block individually for correctness, but we don't
  47. * have the infrastructure in place to do that.
  48. */
  49. if (group_block != fs->super->s_first_data_block &&
  50. ((ret_blk + fs->super->s_blocks_per_group) <
  51. fs->super->s_blocks_count))
  52. ret_blk += fs->super->s_blocks_per_group;
  53. return ret_blk;
  54. }
  55. errcode_t ext2fs_open(const char *name, int flags, int superblock,
  56. unsigned int block_size, io_manager manager,
  57. ext2_filsys *ret_fs)
  58. {
  59. return ext2fs_open2(name, 0, flags, superblock, block_size,
  60. manager, ret_fs);
  61. }
  62. /*
  63. * Note: if superblock is non-zero, block-size must also be non-zero.
  64. * Superblock and block_size can be zero to use the default size.
  65. *
  66. * Valid flags for ext2fs_open()
  67. *
  68. * EXT2_FLAG_RW - Open the filesystem for read/write.
  69. * EXT2_FLAG_FORCE - Open the filesystem even if some of the
  70. * features aren't supported.
  71. * EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
  72. */
  73. errcode_t ext2fs_open2(const char *name, const char *io_options,
  74. int flags, int superblock,
  75. unsigned int block_size, io_manager manager,
  76. ext2_filsys *ret_fs)
  77. {
  78. ext2_filsys fs;
  79. errcode_t retval;
  80. unsigned long i;
  81. int groups_per_block, blocks_per_group;
  82. blk_t group_block, blk;
  83. char *dest, *cp;
  84. #if BB_BIG_ENDIAN
  85. int j;
  86. struct ext2_group_desc *gdp;
  87. #endif
  88. EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
  89. retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
  90. if (retval)
  91. return retval;
  92. memset(fs, 0, sizeof(struct struct_ext2_filsys));
  93. fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
  94. fs->flags = flags;
  95. fs->umask = 022;
  96. retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
  97. if (retval)
  98. goto cleanup;
  99. strcpy(fs->device_name, name);
  100. cp = strchr(fs->device_name, '?');
  101. if (!io_options && cp) {
  102. *cp++ = 0;
  103. io_options = cp;
  104. }
  105. retval = manager->open(fs->device_name,
  106. (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0,
  107. &fs->io);
  108. if (retval)
  109. goto cleanup;
  110. if (io_options &&
  111. (retval = io_channel_set_options(fs->io, io_options)))
  112. goto cleanup;
  113. fs->image_io = fs->io;
  114. fs->io->app_data = fs;
  115. retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
  116. if (retval)
  117. goto cleanup;
  118. if (flags & EXT2_FLAG_IMAGE_FILE) {
  119. retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
  120. &fs->image_header);
  121. if (retval)
  122. goto cleanup;
  123. retval = io_channel_read_blk(fs->io, 0,
  124. -(int)sizeof(struct ext2_image_hdr),
  125. fs->image_header);
  126. if (retval)
  127. goto cleanup;
  128. if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE)
  129. return EXT2_ET_MAGIC_E2IMAGE;
  130. superblock = 1;
  131. block_size = fs->image_header->fs_blocksize;
  132. }
  133. /*
  134. * If the user specifies a specific block # for the
  135. * superblock, then he/she must also specify the block size!
  136. * Otherwise, read the master superblock located at offset
  137. * SUPERBLOCK_OFFSET from the start of the partition.
  138. *
  139. * Note: we only save a backup copy of the superblock if we
  140. * are reading the superblock from the primary superblock location.
  141. */
  142. if (superblock) {
  143. if (!block_size) {
  144. retval = EXT2_ET_INVALID_ARGUMENT;
  145. goto cleanup;
  146. }
  147. io_channel_set_blksize(fs->io, block_size);
  148. group_block = superblock;
  149. fs->orig_super = 0;
  150. } else {
  151. io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
  152. superblock = 1;
  153. group_block = 0;
  154. retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
  155. if (retval)
  156. goto cleanup;
  157. }
  158. retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
  159. fs->super);
  160. if (retval)
  161. goto cleanup;
  162. if (fs->orig_super)
  163. memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
  164. #if BB_BIG_ENDIAN
  165. if ((fs->super->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ||
  166. (fs->flags & EXT2_FLAG_SWAP_BYTES)) {
  167. fs->flags |= EXT2_FLAG_SWAP_BYTES;
  168. ext2fs_swap_super(fs->super);
  169. }
  170. #endif
  171. if (fs->super->s_magic != EXT2_SUPER_MAGIC) {
  172. retval = EXT2_ET_BAD_MAGIC;
  173. goto cleanup;
  174. }
  175. if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
  176. retval = EXT2_ET_REV_TOO_HIGH;
  177. goto cleanup;
  178. }
  179. /*
  180. * Check for feature set incompatibility
  181. */
  182. if (!(flags & EXT2_FLAG_FORCE)) {
  183. if (fs->super->s_feature_incompat &
  184. ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
  185. retval = EXT2_ET_UNSUPP_FEATURE;
  186. goto cleanup;
  187. }
  188. if ((flags & EXT2_FLAG_RW) &&
  189. (fs->super->s_feature_ro_compat &
  190. ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
  191. retval = EXT2_ET_RO_UNSUPP_FEATURE;
  192. goto cleanup;
  193. }
  194. if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
  195. (fs->super->s_feature_incompat &
  196. EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
  197. retval = EXT2_ET_UNSUPP_FEATURE;
  198. goto cleanup;
  199. }
  200. }
  201. fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
  202. if (fs->blocksize == 0) {
  203. retval = EXT2_ET_CORRUPT_SUPERBLOCK;
  204. goto cleanup;
  205. }
  206. fs->fragsize = EXT2_FRAG_SIZE(fs->super);
  207. fs->inode_blocks_per_group = ((fs->super->s_inodes_per_group *
  208. EXT2_INODE_SIZE(fs->super) +
  209. EXT2_BLOCK_SIZE(fs->super) - 1) /
  210. EXT2_BLOCK_SIZE(fs->super));
  211. if (block_size) {
  212. if (block_size != fs->blocksize) {
  213. retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
  214. goto cleanup;
  215. }
  216. }
  217. /*
  218. * Set the blocksize to the filesystem's blocksize.
  219. */
  220. io_channel_set_blksize(fs->io, fs->blocksize);
  221. /*
  222. * If this is an external journal device, don't try to read
  223. * the group descriptors, because they're not there.
  224. */
  225. if (fs->super->s_feature_incompat &
  226. EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
  227. fs->group_desc_count = 0;
  228. *ret_fs = fs;
  229. return 0;
  230. }
  231. /*
  232. * Read group descriptors
  233. */
  234. blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
  235. if (blocks_per_group == 0 ||
  236. blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
  237. fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super)) {
  238. retval = EXT2_ET_CORRUPT_SUPERBLOCK;
  239. goto cleanup;
  240. }
  241. fs->group_desc_count = (fs->super->s_blocks_count -
  242. fs->super->s_first_data_block +
  243. blocks_per_group - 1) / blocks_per_group;
  244. fs->desc_blocks = (fs->group_desc_count +
  245. EXT2_DESC_PER_BLOCK(fs->super) - 1)
  246. / EXT2_DESC_PER_BLOCK(fs->super);
  247. retval = ext2fs_get_mem(fs->desc_blocks * fs->blocksize,
  248. &fs->group_desc);
  249. if (retval)
  250. goto cleanup;
  251. if (!group_block)
  252. group_block = fs->super->s_first_data_block;
  253. dest = (char *) fs->group_desc;
  254. groups_per_block = fs->blocksize / sizeof(struct ext2_group_desc);
  255. for (i = 0; i < fs->desc_blocks; i++) {
  256. blk = ext2fs_descriptor_block_loc(fs, group_block, i);
  257. retval = io_channel_read_blk(fs->io, blk, 1, dest);
  258. if (retval)
  259. goto cleanup;
  260. #if BB_BIG_ENDIAN
  261. if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
  262. gdp = (struct ext2_group_desc *) dest;
  263. for (j=0; j < groups_per_block; j++)
  264. ext2fs_swap_group_desc(gdp++);
  265. }
  266. #endif
  267. dest += fs->blocksize;
  268. }
  269. *ret_fs = fs;
  270. return 0;
  271. cleanup:
  272. ext2fs_free(fs);
  273. return retval;
  274. }
  275. /*
  276. * Set/get the filesystem data I/O channel.
  277. *
  278. * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true.
  279. */
  280. errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io)
  281. {
  282. if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
  283. return EXT2_ET_NOT_IMAGE_FILE;
  284. if (old_io) {
  285. *old_io = (fs->image_io == fs->io) ? 0 : fs->io;
  286. }
  287. return 0;
  288. }
  289. errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io)
  290. {
  291. if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
  292. return EXT2_ET_NOT_IMAGE_FILE;
  293. fs->io = new_io ? new_io : fs->image_io;
  294. return 0;
  295. }
  296. errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io)
  297. {
  298. if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
  299. return EXT2_ET_NOT_IMAGE_FILE;
  300. fs->io = fs->image_io = new_io;
  301. fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW |
  302. EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
  303. fs->flags &= ~EXT2_FLAG_IMAGE_FILE;
  304. return 0;
  305. }