* better
[mascara-docs.git] / i386 / linux-2.3.21 / fs / ncpfs / file.c
blobe39578d75ec7b1238160d90c1ec89cb18beb1abd
1 /*
2 * file.c
4 * Copyright (C) 1995, 1996 by Volker Lendecke
5 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7 */
9 #include <asm/uaccess.h>
10 #include <asm/system.h>
12 #include <linux/sched.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/locks.h>
19 #include <linux/malloc.h>
21 #include <linux/ncp_fs.h>
22 #include "ncplib_kernel.h"
24 static inline unsigned int min(unsigned int a, unsigned int b)
26 return a < b ? a : b;
29 static int ncp_fsync(struct file *file, struct dentry *dentry)
31 return 0;
35 * Open a file with the specified read/write mode.
37 int ncp_make_open(struct inode *inode, int right)
39 int error, result;
40 int access;
41 struct ncp_entry_info finfo;
43 error = -EINVAL;
44 if (!inode) {
45 printk(KERN_ERR "ncp_make_open: got NULL inode\n");
46 goto out;
49 DPRINTK(KERN_DEBUG "ncp_make_open: opened=%d, volume # %u, dir entry # %u\n",
50 NCP_FINFO(inode)->opened,
51 NCP_FINFO(inode)->volNumber,
52 NCP_FINFO(inode)->dirEntNum);
53 error = -EACCES;
54 lock_super(inode->i_sb);
55 if (!NCP_FINFO(inode)->opened) {
56 finfo.i.dirEntNum = NCP_FINFO(inode)->dirEntNum;
57 finfo.i.volNumber = NCP_FINFO(inode)->volNumber;
58 /* tries max. rights */
59 finfo.access = O_RDWR;
60 result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
61 NULL, NULL, OC_MODE_OPEN,
62 0, AR_READ | AR_WRITE, &finfo);
63 if (!result)
64 goto update;
65 finfo.access = O_RDONLY;
66 result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
67 NULL, NULL, OC_MODE_OPEN,
68 0, AR_READ, &finfo);
69 if (result) {
70 #ifdef NCPFS_PARANOIA
71 printk(KERN_DEBUG "ncp_make_open: failed, result=%d\n", result);
72 #endif
73 goto out_unlock;
76 * Update the inode information.
78 update:
79 ncp_update_inode(inode, &finfo);
82 access = NCP_FINFO(inode)->access;
83 #ifdef NCPFS_PARANOIA
84 printk(KERN_DEBUG "ncp_make_open: file open, access=%x\n", access);
85 #endif
86 if (access == right || access == O_RDWR)
87 error = 0;
89 out_unlock:
90 unlock_super(inode->i_sb);
91 out:
92 return error;
95 static ssize_t
96 ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
98 struct dentry *dentry = file->f_dentry;
99 struct inode *inode = dentry->d_inode;
100 size_t already_read = 0;
101 off_t pos;
102 size_t bufsize;
103 int error;
104 void* freepage;
105 size_t freelen;
107 DPRINTK(KERN_DEBUG "ncp_file_read: enter %s/%s\n",
108 dentry->d_parent->d_name.name, dentry->d_name.name);
110 error = -EINVAL;
111 if (inode == NULL) {
112 DPRINTK(KERN_DEBUG "ncp_file_read: inode = NULL\n");
113 goto out;
115 error = -EIO;
116 if (!ncp_conn_valid(NCP_SERVER(inode)))
117 goto out;
118 error = -EINVAL;
119 if (!S_ISREG(inode->i_mode)) {
120 DPRINTK(KERN_DEBUG "ncp_file_read: read from non-file, mode %07o\n",
121 inode->i_mode);
122 goto out;
125 pos = *ppos;
126 /* leave it out on server ...
127 if (pos + count > inode->i_size) {
128 count = inode->i_size - pos;
131 error = 0;
132 if (!count) /* size_t is never < 0 */
133 goto out;
135 error = ncp_make_open(inode, O_RDONLY);
136 if (error) {
137 printk(KERN_ERR "ncp_file_read: open failed, error=%d\n", error);
138 goto out;
141 bufsize = NCP_SERVER(inode)->buffer_size;
143 error = -EIO;
144 freelen = ncp_read_bounce_size(bufsize);
145 freepage = kmalloc(freelen, GFP_NFS);
146 if (!freepage)
147 goto out;
148 error = 0;
149 /* First read in as much as possible for each bufsize. */
150 while (already_read < count) {
151 int read_this_time;
152 size_t to_read = min(bufsize - (pos % bufsize),
153 count - already_read);
155 error = ncp_read_bounce(NCP_SERVER(inode),
156 NCP_FINFO(inode)->file_handle,
157 pos, to_read, buf, &read_this_time,
158 freepage, freelen);
159 if (error) {
160 kfree(freepage);
161 error = -EIO; /* This is not exact, i know.. */
162 goto out;
164 pos += read_this_time;
165 buf += read_this_time;
166 already_read += read_this_time;
168 if (read_this_time != to_read) {
169 break;
172 kfree(freepage);
174 *ppos = pos;
176 if (!IS_RDONLY(inode)) {
177 inode->i_atime = CURRENT_TIME;
180 DPRINTK(KERN_DEBUG "ncp_file_read: exit %s/%s\n",
181 dentry->d_parent->d_name.name, dentry->d_name.name);
182 out:
183 return already_read ? already_read : error;
186 static ssize_t
187 ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
189 struct dentry *dentry = file->f_dentry;
190 struct inode *inode = dentry->d_inode;
191 size_t already_written = 0;
192 off_t pos;
193 size_t bufsize;
194 int errno;
195 void* bouncebuffer;
197 DPRINTK(KERN_DEBUG "ncp_file_write: enter %s/%s\n",
198 dentry->d_parent->d_name.name, dentry->d_name.name);
199 if (inode == NULL) {
200 DPRINTK(KERN_DEBUG "ncp_file_write: inode = NULL\n");
201 return -EINVAL;
203 errno = -EIO;
204 if (!ncp_conn_valid(NCP_SERVER(inode)))
205 goto out;
206 if (!S_ISREG(inode->i_mode)) {
207 DPRINTK(KERN_DEBUG "ncp_file_write: write to non-file, mode %07o\n",
208 inode->i_mode);
209 return -EINVAL;
212 errno = 0;
213 if (!count)
214 goto out;
215 errno = ncp_make_open(inode, O_RDWR);
216 if (errno) {
217 printk(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno);
218 return errno;
220 pos = *ppos;
222 if (file->f_flags & O_APPEND) {
223 pos = inode->i_size;
225 bufsize = NCP_SERVER(inode)->buffer_size;
227 already_written = 0;
229 bouncebuffer = kmalloc(bufsize, GFP_NFS);
230 if (!bouncebuffer)
231 return -EIO; /* -ENOMEM */
232 while (already_written < count) {
233 int written_this_time;
234 size_t to_write = min(bufsize - (pos % bufsize),
235 count - already_written);
237 if (copy_from_user(bouncebuffer, buf, to_write)) {
238 errno = -EFAULT;
239 break;
241 if (ncp_write_kernel(NCP_SERVER(inode),
242 NCP_FINFO(inode)->file_handle,
243 pos, to_write, buf, &written_this_time) != 0) {
244 errno = -EIO;
245 break;
247 pos += written_this_time;
248 buf += written_this_time;
249 already_written += written_this_time;
251 if (written_this_time != to_write) {
252 break;
255 kfree(bouncebuffer);
256 inode->i_mtime = inode->i_atime = CURRENT_TIME;
258 *ppos = pos;
260 if (pos > inode->i_size) {
261 inode->i_size = pos;
263 DPRINTK(KERN_DEBUG "ncp_file_write: exit %s/%s\n",
264 dentry->d_parent->d_name.name, dentry->d_name.name);
265 out:
266 return already_written ? already_written : errno;
269 static struct file_operations ncp_file_operations =
271 NULL, /* lseek - default */
272 ncp_file_read, /* read */
273 ncp_file_write, /* write */
274 NULL, /* readdir - bad */
275 NULL, /* poll - default */
276 ncp_ioctl, /* ioctl */
277 ncp_mmap, /* mmap */
278 NULL, /* open */
279 NULL, /* flush */
280 NULL, /* release */
281 ncp_fsync, /* fsync */
284 struct inode_operations ncp_file_inode_operations =
286 &ncp_file_operations, /* default file operations */
287 NULL, /* create */
288 NULL, /* lookup */
289 NULL, /* link */
290 NULL, /* unlink */
291 NULL, /* symlink */
292 NULL, /* mkdir */
293 NULL, /* rmdir */
294 NULL, /* mknod */
295 NULL, /* rename */
296 NULL, /* readlink */
297 NULL, /* follow_link */
298 NULL, /* get_block */
299 NULL, /* readpage */
300 NULL, /* writepage */
301 NULL, /* flushpage */
302 NULL, /* truncate */
303 NULL, /* permission */
304 NULL, /* smap */
305 NULL /* revalidate */