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#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, int datasync)
  24{
  25        return 0;
  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};
 298