linux/fs/ncpfs/file.c
<<
>>
Prefs
   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};
 299
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.