inode.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/adfs/inode.c
  3.  *
  4.  *  Copyright (C) 1997-1999 Russell King
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License version 2 as
  8.  * published by the Free Software Foundation.
  9.  */
  10. #include <linux/version.h>
  11. #include <linux/errno.h>
  12. #include <linux/fs.h>
  13. #include <linux/adfs_fs.h>
  14. #include <linux/sched.h>
  15. #include <linux/stat.h>
  16. #include <linux/string.h>
  17. #include <linux/locks.h>
  18. #include <linux/mm.h>
  19. #include <linux/smp_lock.h>
  20. #include <linux/module.h>
  21. #include "adfs.h"
  22. /*
  23.  * Lookup/Create a block at offset 'block' into 'inode'.  We currently do
  24.  * not support creation of new blocks, so we return -EIO for this case.
  25.  */
  26. int
  27. adfs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create)
  28. {
  29. if (block < 0)
  30. goto abort_negative;
  31. if (!create) {
  32. if (block >= inode->i_blocks)
  33. goto abort_toobig;
  34. block = __adfs_block_map(inode->i_sb, inode->i_ino, block);
  35. if (block) {
  36. bh->b_dev = inode->i_dev;
  37. bh->b_blocknr = block;
  38. bh->b_state |= (1UL << BH_Mapped);
  39. }
  40. return 0;
  41. }
  42. /* don't support allocation of blocks yet */
  43. return -EIO;
  44. abort_negative:
  45. adfs_error(inode->i_sb, "block %d < 0", block);
  46. return -EIO;
  47. abort_toobig:
  48. return 0;
  49. }
  50. static int adfs_writepage(struct page *page)
  51. {
  52. return block_write_full_page(page, adfs_get_block);
  53. }
  54. static int adfs_readpage(struct file *file, struct page *page)
  55. {
  56. return block_read_full_page(page, adfs_get_block);
  57. }
  58. static int adfs_prepare_write(struct file *file, struct page *page, unsigned int from, unsigned int to)
  59. {
  60. return cont_prepare_write(page, from, to, adfs_get_block,
  61. &page->mapping->host->u.adfs_i.mmu_private);
  62. }
  63. static int _adfs_bmap(struct address_space *mapping, long block)
  64. {
  65. return generic_block_bmap(mapping, block, adfs_get_block);
  66. }
  67. static struct address_space_operations adfs_aops = {
  68. readpage: adfs_readpage,
  69. writepage: adfs_writepage,
  70. sync_page: block_sync_page,
  71. prepare_write: adfs_prepare_write,
  72. commit_write: generic_commit_write,
  73. bmap: _adfs_bmap
  74. };
  75. static inline unsigned int
  76. adfs_filetype(struct inode *inode)
  77. {
  78. unsigned int type;
  79. if (inode->u.adfs_i.stamped)
  80. type = (inode->u.adfs_i.loadaddr >> 8) & 0xfff;
  81. else
  82. type = (unsigned int) -1;
  83. return type;
  84. }
  85. /*
  86.  * Convert ADFS attributes and filetype to Linux permission.
  87.  */
  88. static umode_t
  89. adfs_atts2mode(struct super_block *sb, struct inode *inode)
  90. {
  91. unsigned int filetype, attr = inode->u.adfs_i.attr;
  92. umode_t mode, rmask;
  93. if (attr & ADFS_NDA_DIRECTORY) {
  94. mode = S_IRUGO & sb->u.adfs_sb.s_owner_mask;
  95. return S_IFDIR | S_IXUGO | mode;
  96. }
  97. filetype = adfs_filetype(inode);
  98. switch (filetype) {
  99. case 0xfc0: /* LinkFS */
  100. return S_IFLNK|S_IRWXUGO;
  101. case 0xfe6: /* UnixExec */
  102. rmask = S_IRUGO | S_IXUGO;
  103. break;
  104. default:
  105. rmask = S_IRUGO;
  106. }
  107. mode = S_IFREG;
  108. if (attr & ADFS_NDA_OWNER_READ)
  109. mode |= rmask & sb->u.adfs_sb.s_owner_mask;
  110. if (attr & ADFS_NDA_OWNER_WRITE)
  111. mode |= S_IWUGO & sb->u.adfs_sb.s_owner_mask;
  112. if (attr & ADFS_NDA_PUBLIC_READ)
  113. mode |= rmask & sb->u.adfs_sb.s_other_mask;
  114. if (attr & ADFS_NDA_PUBLIC_WRITE)
  115. mode |= S_IWUGO & sb->u.adfs_sb.s_other_mask;
  116. return mode;
  117. }
  118. /*
  119.  * Convert Linux permission to ADFS attribute.  We try to do the reverse
  120.  * of atts2mode, but there is not a 1:1 translation.
  121.  */
  122. static int
  123. adfs_mode2atts(struct super_block *sb, struct inode *inode)
  124. {
  125. umode_t mode;
  126. int attr;
  127. /* FIXME: should we be able to alter a link? */
  128. if (S_ISLNK(inode->i_mode))
  129. return inode->u.adfs_i.attr;
  130. if (S_ISDIR(inode->i_mode))
  131. attr = ADFS_NDA_DIRECTORY;
  132. else
  133. attr = 0;
  134. mode = inode->i_mode & sb->u.adfs_sb.s_owner_mask;
  135. if (mode & S_IRUGO)
  136. attr |= ADFS_NDA_OWNER_READ;
  137. if (mode & S_IWUGO)
  138. attr |= ADFS_NDA_OWNER_WRITE;
  139. mode = inode->i_mode & sb->u.adfs_sb.s_other_mask;
  140. mode &= ~sb->u.adfs_sb.s_owner_mask;
  141. if (mode & S_IRUGO)
  142. attr |= ADFS_NDA_PUBLIC_READ;
  143. if (mode & S_IWUGO)
  144. attr |= ADFS_NDA_PUBLIC_WRITE;
  145. return attr;
  146. }
  147. /*
  148.  * Convert an ADFS time to Unix time.  ADFS has a 40-bit centi-second time
  149.  * referenced to 1 Jan 1900 (til 2248)
  150.  */
  151. static unsigned int
  152. adfs_adfs2unix_time(struct inode *inode)
  153. {
  154. unsigned int high, low;
  155. if (inode->u.adfs_i.stamped == 0)
  156. return CURRENT_TIME;
  157. high = inode->u.adfs_i.loadaddr << 24;
  158. low  = inode->u.adfs_i.execaddr;
  159. high |= low >> 8;
  160. low  &= 255;
  161. /* Files dated pre  01 Jan 1970 00:00:00. */
  162. if (high < 0x336e996a)
  163. return 0;
  164. /* Files dated post 18 Jan 2038 03:14:05. */
  165. if (high >= 0x656e9969)
  166. return 0x7ffffffd;
  167. /* discard 2208988800 (0x336e996a00) seconds of time */
  168. high -= 0x336e996a;
  169. /* convert 40-bit centi-seconds to 32-bit seconds */
  170. return (((high % 100) << 8) + low) / 100 + (high / 100 << 8);
  171. }
  172. /*
  173.  * Convert an Unix time to ADFS time.  We only do this if the entry has a
  174.  * time/date stamp already.
  175.  */
  176. static void
  177. adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
  178. {
  179. unsigned int high, low;
  180. if (inode->u.adfs_i.stamped) {
  181. /* convert 32-bit seconds to 40-bit centi-seconds */
  182. low  = (secs & 255) * 100;
  183. high = (secs / 256) * 100 + (low >> 8) + 0x336e996a;
  184. inode->u.adfs_i.loadaddr = (high >> 24) |
  185. (inode->u.adfs_i.loadaddr & ~0xff);
  186. inode->u.adfs_i.execaddr = (low & 255) | (high << 8);
  187. }
  188. }
  189. /*
  190.  * Fill in the inode information from the object information.
  191.  *
  192.  * Note that this is an inode-less filesystem, so we can't use the inode
  193.  * number to reference the metadata on the media.  Instead, we use the
  194.  * inode number to hold the object ID, which in turn will tell us where
  195.  * the data is held.  We also save the parent object ID, and with these
  196.  * two, we can locate the metadata.
  197.  *
  198.  * This does mean that we rely on an objects parent remaining the same at
  199.  * all times - we cannot cope with a cross-directory rename (yet).
  200.  */
  201. struct inode *
  202. adfs_iget(struct super_block *sb, struct object_info *obj)
  203. {
  204. struct inode *inode;
  205. inode = new_inode(sb);
  206. if (!inode)
  207. goto out;
  208. inode->i_version = ++event;
  209. inode->i_uid  = sb->u.adfs_sb.s_uid;
  210. inode->i_gid  = sb->u.adfs_sb.s_gid;
  211. inode->i_ino  = obj->file_id;
  212. inode->i_size  = obj->size;
  213. inode->i_nlink  = 2;
  214. inode->i_blksize = PAGE_SIZE;
  215. inode->i_blocks  = (inode->i_size + sb->s_blocksize - 1) >>
  216.     sb->s_blocksize_bits;
  217. /*
  218.  * we need to save the parent directory ID so that
  219.  * write_inode can update the directory information
  220.  * for this file.  This will need special handling
  221.  * for cross-directory renames.
  222.  */
  223. inode->u.adfs_i.parent_id = obj->parent_id;
  224. inode->u.adfs_i.loadaddr  = obj->loadaddr;
  225. inode->u.adfs_i.execaddr  = obj->execaddr;
  226. inode->u.adfs_i.attr      = obj->attr;
  227. inode->u.adfs_i.stamped   = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
  228. inode->i_mode  = adfs_atts2mode(sb, inode);
  229. inode->i_mtime  =
  230. inode->i_atime  =
  231. inode->i_ctime  = adfs_adfs2unix_time(inode);
  232. if (S_ISDIR(inode->i_mode)) {
  233. inode->i_op = &adfs_dir_inode_operations;
  234. inode->i_fop = &adfs_dir_operations;
  235. } else if (S_ISREG(inode->i_mode)) {
  236. inode->i_op = &adfs_file_inode_operations;
  237. inode->i_fop = &adfs_file_operations;
  238. inode->i_mapping->a_ops = &adfs_aops;
  239. inode->u.adfs_i.mmu_private = inode->i_size;
  240. }
  241. insert_inode_hash(inode);
  242. out:
  243. return inode;
  244. }
  245. /*
  246.  * Validate and convert a changed access mode/time to their ADFS equivalents.
  247.  * adfs_write_inode will actually write the information back to the directory
  248.  * later.
  249.  */
  250. int
  251. adfs_notify_change(struct dentry *dentry, struct iattr *attr)
  252. {
  253. struct inode *inode = dentry->d_inode;
  254. struct super_block *sb = inode->i_sb;
  255. unsigned int ia_valid = attr->ia_valid;
  256. int error;
  257. error = inode_change_ok(inode, attr);
  258. /*
  259.  * we can't change the UID or GID of any file -
  260.  * we have a global UID/GID in the superblock
  261.  */
  262. if ((ia_valid & ATTR_UID && attr->ia_uid != sb->u.adfs_sb.s_uid) ||
  263.     (ia_valid & ATTR_GID && attr->ia_gid != sb->u.adfs_sb.s_gid))
  264. error = -EPERM;
  265. if (error)
  266. goto out;
  267. if (ia_valid & ATTR_SIZE)
  268. error = vmtruncate(inode, attr->ia_size);
  269. if (error)
  270. goto out;
  271. if (ia_valid & ATTR_MTIME) {
  272. inode->i_mtime = attr->ia_mtime;
  273. adfs_unix2adfs_time(inode, attr->ia_mtime);
  274. }
  275. /*
  276.  * FIXME: should we make these == to i_mtime since we don't
  277.  * have the ability to represent them in our filesystem?
  278.  */
  279. if (ia_valid & ATTR_ATIME)
  280. inode->i_atime = attr->ia_atime;
  281. if (ia_valid & ATTR_CTIME)
  282. inode->i_ctime = attr->ia_ctime;
  283. if (ia_valid & ATTR_MODE) {
  284. inode->u.adfs_i.attr = adfs_mode2atts(sb, inode);
  285. inode->i_mode = adfs_atts2mode(sb, inode);
  286. }
  287. /*
  288.  * FIXME: should we be marking this inode dirty even if
  289.  * we don't have any metadata to write back?
  290.  */
  291. if (ia_valid & (ATTR_SIZE | ATTR_MTIME | ATTR_MODE))
  292. mark_inode_dirty(inode);
  293. out:
  294. return error;
  295. }
  296. /*
  297.  * write an existing inode back to the directory, and therefore the disk.
  298.  * The adfs-specific inode data has already been updated by
  299.  * adfs_notify_change()
  300.  */
  301. void adfs_write_inode(struct inode *inode, int unused)
  302. {
  303. struct super_block *sb = inode->i_sb;
  304. struct object_info obj;
  305. lock_kernel();
  306. obj.file_id = inode->i_ino;
  307. obj.name_len = 0;
  308. obj.parent_id = inode->u.adfs_i.parent_id;
  309. obj.loadaddr = inode->u.adfs_i.loadaddr;
  310. obj.execaddr = inode->u.adfs_i.execaddr;
  311. obj.attr = inode->u.adfs_i.attr;
  312. obj.size = inode->i_size;
  313. adfs_dir_update(sb, &obj);
  314. unlock_kernel();
  315. }
  316. MODULE_LICENSE("GPL");