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

Configure Feed

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

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