Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
file.c
Go to the documentation of this file.
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 
9 #include <asm/uaccess.h>
10 
11 #include <linux/time.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/fcntl.h>
15 #include <linux/stat.h>
16 #include <linux/mm.h>
17 #include <linux/vmalloc.h>
18 #include <linux/sched.h>
19 
20 #include "ncp_fs.h"
21 
22 static int ncp_fsync(struct file *file, loff_t start, loff_t end, int datasync)
23 {
24  return filemap_write_and_wait_range(file->f_mapping, start, end);
25 }
26 
27 /*
28  * Open a file with the specified read/write mode.
29  */
30 int ncp_make_open(struct inode *inode, int right)
31 {
32  int error;
33  int access;
34 
35  error = -EINVAL;
36  if (!inode) {
37  printk(KERN_ERR "ncp_make_open: got NULL inode\n");
38  goto out;
39  }
40 
41  DPRINTK("ncp_make_open: opened=%d, volume # %u, dir entry # %u\n",
42  atomic_read(&NCP_FINFO(inode)->opened),
43  NCP_FINFO(inode)->volNumber,
44  NCP_FINFO(inode)->dirEntNum);
45  error = -EACCES;
46  mutex_lock(&NCP_FINFO(inode)->open_mutex);
47  if (!atomic_read(&NCP_FINFO(inode)->opened)) {
48  struct ncp_entry_info finfo;
49  int result;
50 
51  /* tries max. rights */
52  finfo.access = O_RDWR;
54  inode, NULL, OC_MODE_OPEN,
55  0, AR_READ | AR_WRITE, &finfo);
56  if (!result)
57  goto update;
58  /* RDWR did not succeeded, try readonly or writeonly as requested */
59  switch (right) {
60  case O_RDONLY:
61  finfo.access = O_RDONLY;
63  inode, NULL, OC_MODE_OPEN,
64  0, AR_READ, &finfo);
65  break;
66  case O_WRONLY:
67  finfo.access = O_WRONLY;
69  inode, NULL, OC_MODE_OPEN,
70  0, AR_WRITE, &finfo);
71  break;
72  }
73  if (result) {
74  PPRINTK("ncp_make_open: failed, result=%d\n", result);
75  goto out_unlock;
76  }
77  /*
78  * Update the inode information.
79  */
80  update:
81  ncp_update_inode(inode, &finfo);
82  atomic_set(&NCP_FINFO(inode)->opened, 1);
83  }
84 
85  access = NCP_FINFO(inode)->access;
86  PPRINTK("ncp_make_open: file open, access=%x\n", access);
87  if (access == right || access == O_RDWR) {
88  atomic_inc(&NCP_FINFO(inode)->opened);
89  error = 0;
90  }
91 
92 out_unlock:
93  mutex_unlock(&NCP_FINFO(inode)->open_mutex);
94 out:
95  return error;
96 }
97 
98 static ssize_t
99 ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
100 {
101  struct dentry *dentry = file->f_path.dentry;
102  struct inode *inode = dentry->d_inode;
103  size_t already_read = 0;
104  off_t pos;
105  size_t bufsize;
106  int error;
107  void* freepage;
108  size_t freelen;
109 
110  DPRINTK("ncp_file_read: enter %s/%s\n",
111  dentry->d_parent->d_name.name, dentry->d_name.name);
112 
113  pos = *ppos;
114 
115  if ((ssize_t) count < 0) {
116  return -EINVAL;
117  }
118  if (!count)
119  return 0;
120  if (pos > inode->i_sb->s_maxbytes)
121  return 0;
122  if (pos + count > inode->i_sb->s_maxbytes) {
123  count = inode->i_sb->s_maxbytes - pos;
124  }
125 
126  error = ncp_make_open(inode, O_RDONLY);
127  if (error) {
128  DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%d\n", error);
129  return error;
130  }
131 
132  bufsize = NCP_SERVER(inode)->buffer_size;
133 
134  error = -EIO;
135  freelen = ncp_read_bounce_size(bufsize);
136  freepage = vmalloc(freelen);
137  if (!freepage)
138  goto outrel;
139  error = 0;
140  /* First read in as much as possible for each bufsize. */
141  while (already_read < count) {
142  int read_this_time;
143  size_t to_read = min_t(unsigned int,
144  bufsize - (pos % bufsize),
145  count - already_read);
146 
147  error = ncp_read_bounce(NCP_SERVER(inode),
148  NCP_FINFO(inode)->file_handle,
149  pos, to_read, buf, &read_this_time,
150  freepage, freelen);
151  if (error) {
152  error = -EIO; /* NW errno -> Linux errno */
153  break;
154  }
155  pos += read_this_time;
156  buf += read_this_time;
157  already_read += read_this_time;
158 
159  if (read_this_time != to_read) {
160  break;
161  }
162  }
163  vfree(freepage);
164 
165  *ppos = pos;
166 
167  file_accessed(file);
168 
169  DPRINTK("ncp_file_read: exit %s/%s\n",
170  dentry->d_parent->d_name.name, dentry->d_name.name);
171 outrel:
172  ncp_inode_close(inode);
173  return already_read ? already_read : error;
174 }
175 
176 static ssize_t
177 ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
178 {
179  struct dentry *dentry = file->f_path.dentry;
180  struct inode *inode = dentry->d_inode;
181  size_t already_written = 0;
182  off_t pos;
183  size_t bufsize;
184  int errno;
185  void* bouncebuffer;
186 
187  DPRINTK("ncp_file_write: enter %s/%s\n",
188  dentry->d_parent->d_name.name, dentry->d_name.name);
189  if ((ssize_t) count < 0)
190  return -EINVAL;
191  pos = *ppos;
192  if (file->f_flags & O_APPEND) {
193  pos = i_size_read(inode);
194  }
195 
196  if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
197  if (pos >= MAX_NON_LFS) {
198  return -EFBIG;
199  }
200  if (count > MAX_NON_LFS - (u32)pos) {
201  count = MAX_NON_LFS - (u32)pos;
202  }
203  }
204  if (pos >= inode->i_sb->s_maxbytes) {
205  if (count || pos > inode->i_sb->s_maxbytes) {
206  return -EFBIG;
207  }
208  }
209  if (pos + count > inode->i_sb->s_maxbytes) {
210  count = inode->i_sb->s_maxbytes - pos;
211  }
212 
213  if (!count)
214  return 0;
215  errno = ncp_make_open(inode, O_WRONLY);
216  if (errno) {
217  DPRINTK(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno);
218  return errno;
219  }
220  bufsize = NCP_SERVER(inode)->buffer_size;
221 
222  already_written = 0;
223 
224  errno = file_update_time(file);
225  if (errno)
226  goto outrel;
227 
228  bouncebuffer = vmalloc(bufsize);
229  if (!bouncebuffer) {
230  errno = -EIO; /* -ENOMEM */
231  goto outrel;
232  }
233  while (already_written < count) {
234  int written_this_time;
235  size_t to_write = min_t(unsigned int,
236  bufsize - (pos % bufsize),
237  count - already_written);
238 
239  if (copy_from_user(bouncebuffer, buf, to_write)) {
240  errno = -EFAULT;
241  break;
242  }
243  if (ncp_write_kernel(NCP_SERVER(inode),
244  NCP_FINFO(inode)->file_handle,
245  pos, to_write, bouncebuffer, &written_this_time) != 0) {
246  errno = -EIO;
247  break;
248  }
249  pos += written_this_time;
250  buf += written_this_time;
251  already_written += written_this_time;
252 
253  if (written_this_time != to_write) {
254  break;
255  }
256  }
257  vfree(bouncebuffer);
258 
259  *ppos = pos;
260 
261  if (pos > i_size_read(inode)) {
262  mutex_lock(&inode->i_mutex);
263  if (pos > i_size_read(inode))
264  i_size_write(inode, pos);
265  mutex_unlock(&inode->i_mutex);
266  }
267  DPRINTK("ncp_file_write: exit %s/%s\n",
268  dentry->d_parent->d_name.name, dentry->d_name.name);
269 outrel:
270  ncp_inode_close(inode);
271  return already_written ? already_written : errno;
272 }
273 
274 static int ncp_release(struct inode *inode, struct file *file) {
275  if (ncp_make_closed(inode)) {
276  DPRINTK("ncp_release: failed to close\n");
277  }
278  return 0;
279 }
280 
282 {
283  .llseek = generic_file_llseek,
284  .read = ncp_file_read,
285  .write = ncp_file_write,
286  .unlocked_ioctl = ncp_ioctl,
287 #ifdef CONFIG_COMPAT
288  .compat_ioctl = ncp_compat_ioctl,
289 #endif
290  .mmap = ncp_mmap,
291  .release = ncp_release,
292  .fsync = ncp_fsync,
293 };
294 
296 {
297  .setattr = ncp_notify_change,
298 };