file.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:7k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  file.c
  3.  *
  4.  *  Copyright (C) 1995, 1996 by Volker Lendecke
  5.  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
  6.  *
  7.  */
  8. #include <asm/uaccess.h>
  9. #include <asm/system.h>
  10. #include <linux/sched.h>
  11. #include <linux/kernel.h>
  12. #include <linux/errno.h>
  13. #include <linux/fcntl.h>
  14. #include <linux/stat.h>
  15. #include <linux/mm.h>
  16. #include <linux/locks.h>
  17. #include <linux/slab.h>
  18. #include <linux/vmalloc.h>
  19. #include <linux/ncp_fs.h>
  20. #include "ncplib_kernel.h"
  21. static int ncp_fsync(struct file *file, struct dentry *dentry, int datasync)
  22. {
  23. return 0;
  24. }
  25. /*
  26.  * Open a file with the specified read/write mode.
  27.  */
  28. int ncp_make_open(struct inode *inode, int right)
  29. {
  30. int error;
  31. int access;
  32. error = -EINVAL;
  33. if (!inode) {
  34. printk(KERN_ERR "ncp_make_open: got NULL inoden");
  35. goto out;
  36. }
  37. DPRINTK("ncp_make_open: opened=%d, volume # %u, dir entry # %un",
  38. atomic_read(&NCP_FINFO(inode)->opened), 
  39. NCP_FINFO(inode)->volNumber, 
  40. NCP_FINFO(inode)->dirEntNum);
  41. error = -EACCES;
  42. down(&NCP_FINFO(inode)->open_sem);
  43. if (!atomic_read(&NCP_FINFO(inode)->opened)) {
  44. struct ncp_entry_info finfo;
  45. int result;
  46. finfo.i.dirEntNum = NCP_FINFO(inode)->dirEntNum;
  47. finfo.i.volNumber = NCP_FINFO(inode)->volNumber;
  48. /* tries max. rights */
  49. finfo.access = O_RDWR;
  50. result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
  51. NULL, NULL, OC_MODE_OPEN,
  52. 0, AR_READ | AR_WRITE, &finfo);
  53. if (!result)
  54. goto update;
  55. /* RDWR did not succeeded, try readonly or writeonly as requested */
  56. switch (right) {
  57. case O_RDONLY:
  58. finfo.access = O_RDONLY;
  59. result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
  60. NULL, NULL, OC_MODE_OPEN,
  61. 0, AR_READ, &finfo);
  62. break;
  63. case O_WRONLY:
  64. finfo.access = O_WRONLY;
  65. result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
  66. NULL, NULL, OC_MODE_OPEN,
  67. 0, AR_WRITE, &finfo);
  68. break;
  69. }
  70. if (result) {
  71. PPRINTK("ncp_make_open: failed, result=%dn", result);
  72. goto out_unlock;
  73. }
  74. /*
  75.  * Update the inode information.
  76.  */
  77. update:
  78. ncp_update_inode(inode, &finfo);
  79. atomic_set(&NCP_FINFO(inode)->opened, 1);
  80. }
  81. access = NCP_FINFO(inode)->access;
  82. PPRINTK("ncp_make_open: file open, access=%xn", access);
  83. if (access == right || access == O_RDWR) {
  84. atomic_inc(&NCP_FINFO(inode)->opened);
  85. error = 0;
  86. }
  87. out_unlock:
  88. up(&NCP_FINFO(inode)->open_sem);
  89. out:
  90. return error;
  91. }
  92. static ssize_t
  93. ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
  94. {
  95. struct dentry *dentry = file->f_dentry;
  96. struct inode *inode = dentry->d_inode;
  97. size_t already_read = 0;
  98. off_t pos;
  99. size_t bufsize;
  100. int error;
  101. void* freepage;
  102. size_t freelen;
  103. DPRINTK("ncp_file_read: enter %s/%sn",
  104. dentry->d_parent->d_name.name, dentry->d_name.name);
  105. error = -EIO;
  106. if (!ncp_conn_valid(NCP_SERVER(inode)))
  107. goto out;
  108. error = -EINVAL;
  109. if (!S_ISREG(inode->i_mode)) {
  110. DPRINTK("ncp_file_read: read from non-file, mode %07on",
  111. inode->i_mode);
  112. goto out;
  113. }
  114. pos = *ppos;
  115. /* leave it out on server ...
  116. if (pos + count > inode->i_size) {
  117. count = inode->i_size - pos;
  118. }
  119. */
  120. error = 0;
  121. if (!count) /* size_t is never < 0 */
  122. goto out;
  123. error = ncp_make_open(inode, O_RDONLY);
  124. if (error) {
  125. DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%dn", error);
  126. goto out;
  127. }
  128. bufsize = NCP_SERVER(inode)->buffer_size;
  129. error = -EIO;
  130. freelen = ncp_read_bounce_size(bufsize);
  131. freepage = vmalloc(freelen);
  132. if (!freepage)
  133. goto outrel;
  134. error = 0;
  135. /* First read in as much as possible for each bufsize. */
  136. while (already_read < count) {
  137. int read_this_time;
  138. size_t to_read = min_t(unsigned int,
  139.      bufsize - (pos % bufsize),
  140.      count - already_read);
  141. error = ncp_read_bounce(NCP_SERVER(inode),
  142.   NCP_FINFO(inode)->file_handle,
  143. pos, to_read, buf, &read_this_time, 
  144. freepage, freelen);
  145. if (error) {
  146. error = -EIO; /* NW errno -> Linux errno */
  147. break;
  148. }
  149. pos += read_this_time;
  150. buf += read_this_time;
  151. already_read += read_this_time;
  152. if (read_this_time != to_read) {
  153. break;
  154. }
  155. }
  156. vfree(freepage);
  157. *ppos = pos;
  158. if (!IS_RDONLY(inode)) {
  159. inode->i_atime = CURRENT_TIME;
  160. }
  161. DPRINTK("ncp_file_read: exit %s/%sn",
  162. dentry->d_parent->d_name.name, dentry->d_name.name);
  163. outrel:
  164. ncp_inode_close(inode);
  165. out:
  166. return already_read ? already_read : error;
  167. }
  168. static ssize_t
  169. ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
  170. {
  171. struct dentry *dentry = file->f_dentry;
  172. struct inode *inode = dentry->d_inode;
  173. size_t already_written = 0;
  174. off_t pos;
  175. size_t bufsize;
  176. int errno;
  177. void* bouncebuffer;
  178. DPRINTK("ncp_file_write: enter %s/%sn",
  179. dentry->d_parent->d_name.name, dentry->d_name.name);
  180. errno = -EIO;
  181. if (!ncp_conn_valid(NCP_SERVER(inode)))
  182. goto out;
  183. if (!S_ISREG(inode->i_mode)) {
  184. DPRINTK("ncp_file_write: write to non-file, mode %07on",
  185. inode->i_mode);
  186. return -EINVAL;
  187. }
  188. errno = 0;
  189. if (!count)
  190. goto out;
  191. errno = ncp_make_open(inode, O_WRONLY);
  192. if (errno) {
  193. DPRINTK(KERN_ERR "ncp_file_write: open failed, error=%dn", errno);
  194. return errno;
  195. }
  196. pos = *ppos;
  197. if (file->f_flags & O_APPEND) {
  198. pos = inode->i_size;
  199. }
  200. bufsize = NCP_SERVER(inode)->buffer_size;
  201. already_written = 0;
  202. bouncebuffer = vmalloc(bufsize);
  203. if (!bouncebuffer) {
  204. errno = -EIO; /* -ENOMEM */
  205. goto outrel;
  206. }
  207. while (already_written < count) {
  208. int written_this_time;
  209. size_t to_write = min_t(unsigned int,
  210.       bufsize - (pos % bufsize),
  211.       count - already_written);
  212. if (copy_from_user(bouncebuffer, buf, to_write)) {
  213. errno = -EFAULT;
  214. break;
  215. }
  216. if (ncp_write_kernel(NCP_SERVER(inode), 
  217.     NCP_FINFO(inode)->file_handle,
  218.     pos, to_write, bouncebuffer, &written_this_time) != 0) {
  219. errno = -EIO;
  220. break;
  221. }
  222. pos += written_this_time;
  223. buf += written_this_time;
  224. already_written += written_this_time;
  225. if (written_this_time != to_write) {
  226. break;
  227. }
  228. }
  229. vfree(bouncebuffer);
  230. inode->i_mtime = inode->i_atime = CURRENT_TIME;
  231. *ppos = pos;
  232. if (pos > inode->i_size) {
  233. inode->i_size = pos;
  234. }
  235. DPRINTK("ncp_file_write: exit %s/%sn",
  236. dentry->d_parent->d_name.name, dentry->d_name.name);
  237. outrel:
  238. ncp_inode_close(inode);
  239. out:
  240. return already_written ? already_written : errno;
  241. }
  242. static int ncp_release(struct inode *inode, struct file *file) {
  243. if (ncp_make_closed(inode)) {
  244. DPRINTK("ncp_release: failed to closen");
  245. }
  246. return 0;
  247. }
  248. struct file_operations ncp_file_operations =
  249. {
  250. llseek: generic_file_llseek,
  251. read: ncp_file_read,
  252. write: ncp_file_write,
  253. ioctl: ncp_ioctl,
  254. mmap: ncp_mmap,
  255. release: ncp_release,
  256. fsync: ncp_fsync,
  257. };
  258. struct inode_operations ncp_file_inode_operations =
  259. {
  260. setattr: ncp_notify_change,
  261. };