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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/read_write.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  *  Minor pieces Copyright (C) 2002 Red Hat Inc, All Rights Reserved
  6.  *
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  */
  21. #include <linux/slab.h> 
  22. #include <linux/stat.h>
  23. #include <linux/fcntl.h>
  24. #include <linux/file.h>
  25. #include <linux/uio.h>
  26. #include <linux/smp_lock.h>
  27. #include <linux/dnotify.h>
  28. #include <asm/uaccess.h>
  29. struct file_operations generic_ro_fops = {
  30. llseek: generic_file_llseek,
  31. read: generic_file_read,
  32. mmap: generic_file_mmap,
  33. };
  34. ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
  35. {
  36. return -EISDIR;
  37. }
  38. loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
  39. {
  40. long long retval;
  41. switch (origin) {
  42. case 2:
  43. offset += file->f_dentry->d_inode->i_size;
  44. break;
  45. case 1:
  46. offset += file->f_pos;
  47. }
  48. retval = -EINVAL;
  49. if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
  50. if (offset != file->f_pos) {
  51. file->f_pos = offset;
  52. file->f_reada = 0;
  53. file->f_version = ++event;
  54. }
  55. retval = offset;
  56. }
  57. return retval;
  58. }
  59. loff_t no_llseek(struct file *file, loff_t offset, int origin)
  60. {
  61. return -ESPIPE;
  62. }
  63. loff_t default_llseek(struct file *file, loff_t offset, int origin)
  64. {
  65. long long retval;
  66. switch (origin) {
  67. case 2:
  68. offset += file->f_dentry->d_inode->i_size;
  69. break;
  70. case 1:
  71. offset += file->f_pos;
  72. }
  73. retval = -EINVAL;
  74. if (offset >= 0) {
  75. if (offset != file->f_pos) {
  76. file->f_pos = offset;
  77. file->f_reada = 0;
  78. file->f_version = ++event;
  79. }
  80. retval = offset;
  81. }
  82. return retval;
  83. }
  84. static inline loff_t llseek(struct file *file, loff_t offset, int origin)
  85. {
  86. loff_t (*fn)(struct file *, loff_t, int);
  87. loff_t retval;
  88. fn = default_llseek;
  89. if (file->f_op && file->f_op->llseek)
  90. fn = file->f_op->llseek;
  91. lock_kernel();
  92. retval = fn(file, offset, origin);
  93. unlock_kernel();
  94. return retval;
  95. }
  96. asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
  97. {
  98. off_t retval;
  99. struct file * file;
  100. retval = -EBADF;
  101. file = fget(fd);
  102. if (!file)
  103. goto bad;
  104. retval = -EINVAL;
  105. if (origin <= 2) {
  106. loff_t res = llseek(file, offset, origin);
  107. retval = res;
  108. if (res != (loff_t)retval)
  109. retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
  110. }
  111. fput(file);
  112. bad:
  113. return retval;
  114. }
  115. #if !defined(__alpha__)
  116. asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
  117.    unsigned long offset_low, loff_t * result,
  118.    unsigned int origin)
  119. {
  120. int retval;
  121. struct file * file;
  122. loff_t offset;
  123. retval = -EBADF;
  124. file = fget(fd);
  125. if (!file)
  126. goto bad;
  127. retval = -EINVAL;
  128. if (origin > 2)
  129. goto out_putf;
  130. offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
  131. origin);
  132. retval = (int)offset;
  133. if (offset >= 0) {
  134. retval = -EFAULT;
  135. if (!copy_to_user(result, &offset, sizeof(offset)))
  136. retval = 0;
  137. }
  138. out_putf:
  139. fput(file);
  140. bad:
  141. return retval;
  142. }
  143. #endif
  144. asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
  145. {
  146. ssize_t ret;
  147. struct file * file;
  148. ret = -EBADF;
  149. file = fget(fd);
  150. if (file) {
  151. if (file->f_mode & FMODE_READ) {
  152. ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
  153. file, file->f_pos, count);
  154. if (!ret) {
  155. ssize_t (*read)(struct file *, char *, size_t, loff_t *);
  156. ret = -EINVAL;
  157. if (file->f_op && (read = file->f_op->read) != NULL)
  158. ret = read(file, buf, count, &file->f_pos);
  159. }
  160. }
  161. if (ret > 0)
  162. dnotify_parent(file->f_dentry, DN_ACCESS);
  163. fput(file);
  164. }
  165. return ret;
  166. }
  167. asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
  168. {
  169. ssize_t ret;
  170. struct file * file;
  171. ret = -EBADF;
  172. file = fget(fd);
  173. if (file) {
  174. if (file->f_mode & FMODE_WRITE) {
  175. struct inode *inode = file->f_dentry->d_inode;
  176. ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
  177. file->f_pos, count);
  178. if (!ret) {
  179. ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
  180. ret = -EINVAL;
  181. if (file->f_op && (write = file->f_op->write) != NULL)
  182. ret = write(file, buf, count, &file->f_pos);
  183. }
  184. }
  185. if (ret > 0)
  186. dnotify_parent(file->f_dentry, DN_MODIFY);
  187. fput(file);
  188. }
  189. return ret;
  190. }
  191. static ssize_t do_readv_writev(int type, struct file *file,
  192.        const struct iovec * vector,
  193.        unsigned long count)
  194. {
  195. typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
  196. typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
  197. ssize_t tot_len;
  198. struct iovec iovstack[UIO_FASTIOV];
  199. struct iovec *iov=iovstack;
  200. ssize_t ret, i;
  201. io_fn_t fn;
  202. iov_fn_t fnv;
  203. struct inode *inode;
  204. /*
  205.  * First get the "struct iovec" from user memory and
  206.  * verify all the pointers
  207.  */
  208. ret = 0;
  209. if (!count)
  210. goto out_nofree;
  211. ret = -EINVAL;
  212. if (count > UIO_MAXIOV)
  213. goto out_nofree;
  214. if (!file->f_op)
  215. goto out_nofree;
  216. if (count > UIO_FASTIOV) {
  217. ret = -ENOMEM;
  218. iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
  219. if (!iov)
  220. goto out_nofree;
  221. }
  222. ret = -EFAULT;
  223. if (copy_from_user(iov, vector, count*sizeof(*vector)))
  224. goto out;
  225. /*
  226.  * Single unix specification:
  227.  * We should -EINVAL if an element length is not >= 0 and fitting an ssize_t
  228.  * The total length is fitting an ssize_t
  229.  *
  230.  * Be careful here because iov_len is a size_t not an ssize_t
  231.  */
  232.  
  233. tot_len = 0;
  234. ret = -EINVAL;
  235. for (i = 0 ; i < count ; i++) {
  236. ssize_t tmp = tot_len;
  237. ssize_t len = (ssize_t) iov[i].iov_len;
  238. if (len < 0) /* size_t not fitting an ssize_t .. */
  239. goto out;
  240. tot_len += len;
  241. if (tot_len < tmp) /* maths overflow on the ssize_t */
  242. goto out;
  243. }
  244. inode = file->f_dentry->d_inode;
  245. /* VERIFY_WRITE actually means a read, as we write to user space */
  246. ret = locks_verify_area((type == VERIFY_WRITE
  247.  ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
  248. inode, file, file->f_pos, tot_len);
  249. if (ret) goto out;
  250. fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
  251. if (fnv) {
  252. ret = fnv(file, iov, count, &file->f_pos);
  253. goto out;
  254. }
  255. /* VERIFY_WRITE actually means a read, as we write to user space */
  256. fn = (type == VERIFY_WRITE ? file->f_op->read :
  257.       (io_fn_t) file->f_op->write);
  258. ret = 0;
  259. vector = iov;
  260. while (count > 0) {
  261. void * base;
  262. size_t len;
  263. ssize_t nr;
  264. base = vector->iov_base;
  265. len = vector->iov_len;
  266. vector++;
  267. count--;
  268. nr = fn(file, base, len, &file->f_pos);
  269. if (nr < 0) {
  270. if (!ret) ret = nr;
  271. break;
  272. }
  273. ret += nr;
  274. if (nr != len)
  275. break;
  276. }
  277. out:
  278. if (iov != iovstack)
  279. kfree(iov);
  280. out_nofree:
  281. /* VERIFY_WRITE actually means a read, as we write to user space */
  282. if ((ret + (type == VERIFY_WRITE)) > 0)
  283. dnotify_parent(file->f_dentry,
  284. (type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
  285. return ret;
  286. }
  287. asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
  288.      unsigned long count)
  289. {
  290. struct file * file;
  291. ssize_t ret;
  292. ret = -EBADF;
  293. file = fget(fd);
  294. if (!file)
  295. goto bad_file;
  296. if (file->f_op && (file->f_mode & FMODE_READ) &&
  297.     (file->f_op->readv || file->f_op->read))
  298. ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
  299. fput(file);
  300. bad_file:
  301. return ret;
  302. }
  303. asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
  304.       unsigned long count)
  305. {
  306. struct file * file;
  307. ssize_t ret;
  308. ret = -EBADF;
  309. file = fget(fd);
  310. if (!file)
  311. goto bad_file;
  312. if (file->f_op && (file->f_mode & FMODE_WRITE) &&
  313.     (file->f_op->writev || file->f_op->write))
  314. ret = do_readv_writev(VERIFY_READ, file, vector, count);
  315. fput(file);
  316. bad_file:
  317. return ret;
  318. }
  319. /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
  320.    lseek back to original location.  They fail just like lseek does on
  321.    non-seekable files.  */
  322. asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
  323.      size_t count, loff_t pos)
  324. {
  325. ssize_t ret;
  326. struct file * file;
  327. ssize_t (*read)(struct file *, char *, size_t, loff_t *);
  328. ret = -EBADF;
  329. file = fget(fd);
  330. if (!file)
  331. goto bad_file;
  332. if (!(file->f_mode & FMODE_READ))
  333. goto out;
  334. ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
  335. file, pos, count);
  336. if (ret)
  337. goto out;
  338. ret = -EINVAL;
  339. if (!file->f_op || !(read = file->f_op->read))
  340. goto out;
  341. if (pos < 0)
  342. goto out;
  343. ret = read(file, buf, count, &pos);
  344. if (ret > 0)
  345. dnotify_parent(file->f_dentry, DN_ACCESS);
  346. out:
  347. fput(file);
  348. bad_file:
  349. return ret;
  350. }
  351. asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
  352.       size_t count, loff_t pos)
  353. {
  354. ssize_t ret;
  355. struct file * file;
  356. ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
  357. ret = -EBADF;
  358. file = fget(fd);
  359. if (!file)
  360. goto bad_file;
  361. if (!(file->f_mode & FMODE_WRITE))
  362. goto out;
  363. ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
  364. file, pos, count);
  365. if (ret)
  366. goto out;
  367. ret = -EINVAL;
  368. if (!file->f_op || !(write = file->f_op->write))
  369. goto out;
  370. if (pos < 0)
  371. goto out;
  372. ret = write(file, buf, count, &pos);
  373. if (ret > 0)
  374. dnotify_parent(file->f_dentry, DN_MODIFY);
  375. out:
  376. fput(file);
  377. bad_file:
  378. return ret;
  379. }