Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.8 298 lines 6.9 kB view raw
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};