Linux Audio

Check our new training course

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