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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * file.c
  3.  *
  4.  * PURPOSE
  5.  *  File handling routines for the OSTA-UDF(tm) filesystem.
  6.  *
  7.  * CONTACTS
  8.  *  E-mail regarding any portion of the Linux UDF file system should be
  9.  *  directed to the development team mailing list (run by majordomo):
  10.  *    linux_udf@hpesjro.fc.hp.com
  11.  *
  12.  * COPYRIGHT
  13.  *  This file is distributed under the terms of the GNU General Public
  14.  *  License (GPL). Copies of the GPL can be obtained from:
  15.  *    ftp://prep.ai.mit.edu/pub/gnu/GPL
  16.  *  Each contributing author retains all rights to their own work.
  17.  *
  18.  *  (C) 1998-1999 Dave Boynton
  19.  *  (C) 1998-2001 Ben Fennema
  20.  *  (C) 1999-2000 Stelias Computing Inc
  21.  *
  22.  * HISTORY
  23.  *
  24.  *  10/02/98 dgb  Attempt to integrate into udf.o
  25.  *  10/07/98      Switched to using generic_readpage, etc., like isofs
  26.  *                And it works!
  27.  *  12/06/98 blf  Added udf_file_read. uses generic_file_read for all cases but
  28.  *                ICBTAG_FLAG_AD_IN_ICB.
  29.  *  04/06/99      64 bit file handling on 32 bit systems taken from ext2 file.c
  30.  *  05/12/99      Preliminary file write support
  31.  */
  32. #include "udfdecl.h"
  33. #include <linux/fs.h>
  34. #include <linux/udf_fs.h>
  35. #include <asm/uaccess.h>
  36. #include <linux/kernel.h>
  37. #include <linux/string.h> /* memset */
  38. #include <linux/errno.h>
  39. #include <linux/locks.h>
  40. #include <linux/smp_lock.h>
  41. #include "udf_i.h"
  42. #include "udf_sb.h"
  43. static int udf_adinicb_readpage(struct file *file, struct page * page)
  44. {
  45. struct inode *inode = page->mapping->host;
  46. struct buffer_head *bh;
  47. int block;
  48. char *kaddr;
  49. int err = 0;
  50. if (!PageLocked(page))
  51. PAGE_BUG(page);
  52. kaddr = kmap(page);
  53. memset(kaddr, 0, PAGE_CACHE_SIZE);
  54. block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
  55. bh = sb_bread(inode->i_sb, block);
  56. if (!bh)
  57. {
  58. SetPageError(page);
  59. err = -EIO;
  60. goto out;
  61. }
  62. memcpy(kaddr, bh->b_data + udf_ext0_offset(inode), inode->i_size);
  63. brelse(bh);
  64. flush_dcache_page(page);
  65. SetPageUptodate(page);
  66. out:
  67. kunmap(page);
  68. UnlockPage(page);
  69. return err;
  70. }
  71. static int udf_adinicb_writepage(struct page *page)
  72. {
  73. struct inode *inode = page->mapping->host;
  74. struct buffer_head *bh;
  75. int block;
  76. char *kaddr;
  77. int err = 0;
  78. if (!PageLocked(page))
  79. PAGE_BUG(page);
  80. kaddr = kmap(page);
  81. block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
  82. bh = sb_bread(inode->i_sb, block);
  83. if (!bh)
  84. {
  85. SetPageError(page);
  86. err = -EIO;
  87. goto out;
  88. }
  89. memcpy(bh->b_data + udf_ext0_offset(inode), kaddr, inode->i_size);
  90. mark_buffer_dirty(bh);
  91. brelse(bh);
  92. SetPageUptodate(page);
  93. out:
  94. kunmap(page);
  95. UnlockPage(page);
  96. return err;
  97. }
  98. static int udf_adinicb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
  99. {
  100. kmap(page);
  101. return 0;
  102. }
  103. static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
  104. {
  105. struct inode *inode = page->mapping->host;
  106. struct buffer_head *bh;
  107. int block;
  108. char *kaddr = page_address(page);
  109. int err = 0;
  110. block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
  111. bh = sb_bread(inode->i_sb, block);
  112. if (!bh)
  113. {
  114. SetPageError(page);
  115. err = -EIO;
  116. goto out;
  117. }
  118. memcpy(bh->b_data + udf_file_entry_alloc_offset(inode) + offset,
  119. kaddr + offset, to - offset);
  120. mark_buffer_dirty(bh);
  121. brelse(bh);
  122. SetPageUptodate(page);
  123. out:
  124. kunmap(page);
  125. /* only one page here */
  126. if (to > inode->i_size)
  127. inode->i_size = to;
  128. return err;
  129. }
  130. struct address_space_operations udf_adinicb_aops = {
  131. readpage: udf_adinicb_readpage,
  132. writepage: udf_adinicb_writepage,
  133. sync_page: block_sync_page,
  134. prepare_write: udf_adinicb_prepare_write,
  135. commit_write: udf_adinicb_commit_write,
  136. };
  137. static ssize_t udf_file_write(struct file * file, const char * buf,
  138. size_t count, loff_t *ppos)
  139. {
  140. ssize_t retval;
  141. struct inode *inode = file->f_dentry->d_inode;
  142. int err, pos;
  143. if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
  144. {
  145. if (file->f_flags & O_APPEND)
  146. pos = inode->i_size;
  147. else
  148. pos = *ppos;
  149. if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
  150. pos + count))
  151. {
  152. udf_expand_file_adinicb(inode, pos + count, &err);
  153. if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
  154. {
  155. udf_debug("udf_expand_adinicb: err=%dn", err);
  156. return err;
  157. }
  158. }
  159. else
  160. {
  161. if (pos + count > inode->i_size)
  162. UDF_I_LENALLOC(inode) = pos + count;
  163. else
  164. UDF_I_LENALLOC(inode) = inode->i_size;
  165. }
  166. }
  167. retval = generic_file_write(file, buf, count, ppos);
  168. if (retval > 0)
  169. {
  170. UDF_I_UCTIME(inode) = UDF_I_UMTIME(inode) = CURRENT_UTIME;
  171. mark_inode_dirty(inode);
  172. }
  173. return retval;
  174. }
  175. /*
  176.  * udf_ioctl
  177.  *
  178.  * PURPOSE
  179.  * Issue an ioctl.
  180.  *
  181.  * DESCRIPTION
  182.  * Optional - sys_ioctl() will return -ENOTTY if this routine is not
  183.  * available, and the ioctl cannot be handled without filesystem help.
  184.  *
  185.  * sys_ioctl() handles these ioctls that apply only to regular files:
  186.  * FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD
  187.  * These ioctls are also handled by sys_ioctl():
  188.  * FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC
  189.  * All other ioctls are passed to the filesystem.
  190.  *
  191.  * Refer to sys_ioctl() in fs/ioctl.c
  192.  * sys_ioctl() -> .
  193.  *
  194.  * PRE-CONDITIONS
  195.  * inode Pointer to inode that ioctl was issued on.
  196.  * filp Pointer to file that ioctl was issued on.
  197.  * cmd The ioctl command.
  198.  * arg The ioctl argument [can be interpreted as a
  199.  * user-space pointer if desired].
  200.  *
  201.  * POST-CONDITIONS
  202.  * <return> Success (>=0) or an error code (<=0) that
  203.  * sys_ioctl() will return.
  204.  *
  205.  * HISTORY
  206.  * July 1, 1997 - Andrew E. Mileski
  207.  * Written, tested, and released.
  208.  */
  209. int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
  210. unsigned long arg)
  211. {
  212. int result = -EINVAL;
  213. struct buffer_head *bh = NULL;
  214. long_ad eaicb;
  215. uint8_t *ea = NULL;
  216. if ( permission(inode, MAY_READ) != 0 )
  217. {
  218. udf_debug("no permission to access inode %lun",
  219. inode->i_ino);
  220. return -EPERM;
  221. }
  222. if ( !arg )
  223. {
  224. udf_debug("invalid argument to udf_ioctln");
  225. return -EINVAL;
  226. }
  227. /* first, do ioctls that don't need to udf_read */
  228. switch (cmd)
  229. {
  230. case UDF_GETVOLIDENT:
  231. return copy_to_user((char *)arg,
  232. UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0;
  233. case UDF_RELOCATE_BLOCKS:
  234. {
  235. long old, new;
  236. if (!capable(CAP_SYS_ADMIN)) return -EACCES;
  237. if (get_user(old, (long *)arg)) return -EFAULT;
  238. if ((result = udf_relocate_blocks(inode->i_sb,
  239. old, &new)) == 0)
  240. result = put_user(new, (long *)arg);
  241. return result;
  242. }
  243. }
  244. /* ok, we need to read the inode */
  245. bh = udf_tread(inode->i_sb,
  246. udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0));
  247. if (!bh)
  248. {
  249. udf_debug("bread failed (inode=%ld)n", inode->i_ino);
  250. return -EIO;
  251. }
  252. if (UDF_I_EXTENDED_FE(inode) == 0)
  253. {
  254. struct fileEntry *fe;
  255. fe = (struct fileEntry *)bh->b_data;
  256. eaicb = lela_to_cpu(fe->extendedAttrICB);
  257. if (UDF_I_LENEATTR(inode))
  258. ea = fe->extendedAttr;
  259. }
  260. else
  261. {
  262. struct extendedFileEntry *efe;
  263. efe = (struct extendedFileEntry *)bh->b_data;
  264. eaicb = lela_to_cpu(efe->extendedAttrICB);
  265. if (UDF_I_LENEATTR(inode))
  266. ea = efe->extendedAttr;
  267. }
  268. switch (cmd) 
  269. {
  270. case UDF_GETEASIZE:
  271. result = put_user(UDF_I_LENEATTR(inode), (int *)arg);
  272. break;
  273. case UDF_GETEABLOCK:
  274. result = copy_to_user((char *)arg, ea,
  275. UDF_I_LENEATTR(inode)) ? -EFAULT : 0;
  276. break;
  277. }
  278. udf_release_data(bh);
  279. return result;
  280. }
  281. /*
  282.  * udf_release_file
  283.  *
  284.  * PURPOSE
  285.  *  Called when all references to the file are closed
  286.  *
  287.  * DESCRIPTION
  288.  *  Discard prealloced blocks
  289.  *
  290.  * HISTORY
  291.  *
  292.  */
  293. static int udf_release_file(struct inode * inode, struct file * filp)
  294. {
  295. if (filp->f_mode & FMODE_WRITE)
  296. {
  297. lock_kernel();
  298. udf_discard_prealloc(inode);
  299. unlock_kernel();
  300. }
  301. return 0;
  302. }
  303. /*
  304.  * udf_open_file
  305.  *
  306.  * PURPOSE
  307.  *  Called when an inode is about to be open.
  308.  *
  309.  * DESCRIPTION
  310.  *  Use this to disallow opening RW large files on 32 bit systems.
  311.  *  On 64 bit systems we force on O_LARGEFILE in sys_open.
  312.  *
  313.  * HISTORY
  314.  *
  315.  */
  316. static int udf_open_file(struct inode * inode, struct file * filp)
  317. {
  318. if ((inode->i_size & 0xFFFFFFFF80000000ULL) && !(filp->f_flags & O_LARGEFILE))
  319. return -EFBIG;
  320. return 0;
  321. }
  322. struct file_operations udf_file_operations = {
  323. read: generic_file_read,
  324. ioctl: udf_ioctl,
  325. open: udf_open_file,
  326. mmap: generic_file_mmap,
  327. write: udf_file_write,
  328. release: udf_release_file,
  329. fsync: udf_fsync_file,
  330. };
  331. struct inode_operations udf_file_inode_operations = {
  332. truncate: udf_truncate,
  333. };