at v3.15 296 lines 6.6 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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11#include <asm/uaccess.h> 12 13#include <linux/time.h> 14#include <linux/kernel.h> 15#include <linux/errno.h> 16#include <linux/fcntl.h> 17#include <linux/stat.h> 18#include <linux/mm.h> 19#include <linux/vmalloc.h> 20#include <linux/sched.h> 21 22#include "ncp_fs.h" 23 24static int ncp_fsync(struct file *file, loff_t start, loff_t end, int datasync) 25{ 26 return filemap_write_and_wait_range(file->f_mapping, start, end); 27} 28 29/* 30 * Open a file with the specified read/write mode. 31 */ 32int ncp_make_open(struct inode *inode, int right) 33{ 34 int error; 35 int access; 36 37 error = -EINVAL; 38 if (!inode) { 39 pr_err("%s: got NULL inode\n", __func__); 40 goto out; 41 } 42 43 ncp_dbg(1, "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 ncp_vdbg("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 ncp_vdbg("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 94out_unlock: 95 mutex_unlock(&NCP_FINFO(inode)->open_mutex); 96out: 97 return error; 98} 99 100static ssize_t 101ncp_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 ncp_dbg(1, "enter %pd2\n", dentry); 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 ncp_dbg(1, "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 ncp_dbg(1, "exit %pd2\n", dentry); 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 ncp_dbg(1, "enter %pd2\n", dentry); 188 if ((ssize_t) count < 0) 189 return -EINVAL; 190 pos = *ppos; 191 if (file->f_flags & O_APPEND) { 192 pos = i_size_read(inode); 193 } 194 195 if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) { 196 if (pos >= MAX_NON_LFS) { 197 return -EFBIG; 198 } 199 if (count > MAX_NON_LFS - (u32)pos) { 200 count = MAX_NON_LFS - (u32)pos; 201 } 202 } 203 if (pos >= inode->i_sb->s_maxbytes) { 204 if (count || pos > inode->i_sb->s_maxbytes) { 205 return -EFBIG; 206 } 207 } 208 if (pos + count > inode->i_sb->s_maxbytes) { 209 count = inode->i_sb->s_maxbytes - pos; 210 } 211 212 if (!count) 213 return 0; 214 errno = ncp_make_open(inode, O_WRONLY); 215 if (errno) { 216 ncp_dbg(1, "open failed, error=%d\n", errno); 217 return errno; 218 } 219 bufsize = NCP_SERVER(inode)->buffer_size; 220 221 already_written = 0; 222 223 errno = file_update_time(file); 224 if (errno) 225 goto outrel; 226 227 bouncebuffer = vmalloc(bufsize); 228 if (!bouncebuffer) { 229 errno = -EIO; /* -ENOMEM */ 230 goto outrel; 231 } 232 while (already_written < count) { 233 int written_this_time; 234 size_t to_write = min_t(unsigned int, 235 bufsize - (pos % bufsize), 236 count - already_written); 237 238 if (copy_from_user(bouncebuffer, buf, to_write)) { 239 errno = -EFAULT; 240 break; 241 } 242 if (ncp_write_kernel(NCP_SERVER(inode), 243 NCP_FINFO(inode)->file_handle, 244 pos, to_write, bouncebuffer, &written_this_time) != 0) { 245 errno = -EIO; 246 break; 247 } 248 pos += written_this_time; 249 buf += written_this_time; 250 already_written += written_this_time; 251 252 if (written_this_time != to_write) { 253 break; 254 } 255 } 256 vfree(bouncebuffer); 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 ncp_dbg(1, "exit %pd2\n", dentry); 267outrel: 268 ncp_inode_close(inode); 269 return already_written ? already_written : errno; 270} 271 272static int ncp_release(struct inode *inode, struct file *file) { 273 if (ncp_make_closed(inode)) { 274 ncp_dbg(1, "failed to close\n"); 275 } 276 return 0; 277} 278 279const struct file_operations ncp_file_operations = 280{ 281 .llseek = generic_file_llseek, 282 .read = ncp_file_read, 283 .write = ncp_file_write, 284 .unlocked_ioctl = ncp_ioctl, 285#ifdef CONFIG_COMPAT 286 .compat_ioctl = ncp_compat_ioctl, 287#endif 288 .mmap = ncp_mmap, 289 .release = ncp_release, 290 .fsync = ncp_fsync, 291}; 292 293const struct inode_operations ncp_file_inode_operations = 294{ 295 .setattr = ncp_notify_change, 296};