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