linux-old/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/sched.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/locks.h>
  19#include <linux/slab.h>
  20#include <linux/vmalloc.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        down(&NCP_FINFO(inode)->open_sem);
  50        if (!atomic_read(&NCP_FINFO(inode)->opened)) {
  51                struct ncp_entry_info finfo;
  52                int result;
  53
  54                finfo.i.dirEntNum = NCP_FINFO(inode)->dirEntNum;
  55                finfo.i.volNumber = NCP_FINFO(inode)->volNumber;
  56                /* tries max. rights */
  57                finfo.access = O_RDWR;
  58                result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
  59                                        NULL, NULL, OC_MODE_OPEN,
  60                                        0, AR_READ | AR_WRITE, &finfo);
  61                if (!result)
  62                        goto update;
  63                /* RDWR did not succeeded, try readonly or writeonly as requested */
  64                switch (right) {
  65                        case O_RDONLY:
  66                                finfo.access = O_RDONLY;
  67                                result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
  68                                        NULL, NULL, OC_MODE_OPEN,
  69                                        0, AR_READ, &finfo);
  70                                break;
  71                        case O_WRONLY:
  72                                finfo.access = O_WRONLY;
  73                                result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
  74                                        NULL, NULL, OC_MODE_OPEN,
  75                                        0, AR_WRITE, &finfo);
  76                                break;
  77                }
  78                if (result) {
  79                        PPRINTK("ncp_make_open: failed, result=%d\n", result);
  80                        goto out_unlock;
  81                }
  82                /*
  83                 * Update the inode information.
  84                 */
  85        update:
  86                ncp_update_inode(inode, &finfo);
  87                atomic_set(&NCP_FINFO(inode)->opened, 1);
  88        }
  89
  90        access = NCP_FINFO(inode)->access;
  91        PPRINTK("ncp_make_open: file open, access=%x\n", access);
  92        if (access == right || access == O_RDWR) {
  93                atomic_inc(&NCP_FINFO(inode)->opened);
  94                error = 0;
  95        }
  96
  97out_unlock:
  98        up(&NCP_FINFO(inode)->open_sem);
  99out:
 100        return error;
 101}
 102
 103static ssize_t
 104ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 105{
 106        struct dentry *dentry = file->f_dentry;
 107        struct inode *inode = dentry->d_inode;
 108        size_t already_read = 0;
 109        off_t pos;
 110        size_t bufsize;
 111        int error;
 112        void* freepage;
 113        size_t freelen;
 114
 115        DPRINTK("ncp_file_read: enter %s/%s\n",
 116                dentry->d_parent->d_name.name, dentry->d_name.name);
 117
 118        error = -EIO;
 119        if (!ncp_conn_valid(NCP_SERVER(inode)))
 120                goto out;
 121        error = -EINVAL;
 122        if (!S_ISREG(inode->i_mode)) {
 123                DPRINTK("ncp_file_read: read from non-file, mode %07o\n",
 124                        inode->i_mode);
 125                goto out;
 126        }
 127
 128        pos = *ppos;
 129/* leave it out on server ...
 130        if (pos + count > inode->i_size) {
 131                count = inode->i_size - pos;
 132        }
 133*/
 134        error = 0;
 135        if (!count)     /* size_t is never < 0 */
 136                goto out;
 137
 138        error = ncp_make_open(inode, O_RDONLY);
 139        if (error) {
 140                DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%d\n", error);
 141                goto out;
 142        }
 143
 144        bufsize = NCP_SERVER(inode)->buffer_size;
 145
 146        error = -EIO;
 147        freelen = ncp_read_bounce_size(bufsize);
 148        freepage = vmalloc(freelen);
 149        if (!freepage)
 150                goto outrel;
 151        error = 0;
 152        /* First read in as much as possible for each bufsize. */
 153        while (already_read < count) {
 154                int read_this_time;
 155                size_t to_read = min_t(unsigned int,
 156                                     bufsize - (pos % bufsize),
 157                                     count - already_read);
 158
 159                error = ncp_read_bounce(NCP_SERVER(inode),
 160                                NCP_FINFO(inode)->file_handle,
 161                                pos, to_read, buf, &read_this_time, 
 162                                freepage, freelen);
 163                if (error) {
 164                        error = -EIO;   /* NW errno -> Linux errno */
 165                        break;
 166                }
 167                pos += read_this_time;
 168                buf += read_this_time;
 169                already_read += read_this_time;
 170
 171                if (read_this_time != to_read) {
 172                        break;
 173                }
 174        }
 175        vfree(freepage);
 176
 177        *ppos = pos;
 178
 179        if (!IS_RDONLY(inode)) {
 180                inode->i_atime = CURRENT_TIME;
 181        }
 182        
 183        DPRINTK("ncp_file_read: exit %s/%s\n",
 184                dentry->d_parent->d_name.name, dentry->d_name.name);
 185outrel:
 186        ncp_inode_close(inode);         
 187out:
 188        return already_read ? already_read : error;
 189}
 190
 191static ssize_t
 192ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 193{
 194        struct dentry *dentry = file->f_dentry;
 195        struct inode *inode = dentry->d_inode;
 196        size_t already_written = 0;
 197        off_t pos;
 198        size_t bufsize;
 199        int errno;
 200        void* bouncebuffer;
 201
 202        DPRINTK("ncp_file_write: enter %s/%s\n",
 203                dentry->d_parent->d_name.name, dentry->d_name.name);
 204        errno = -EIO;
 205        if (!ncp_conn_valid(NCP_SERVER(inode)))
 206                goto out;
 207        if (!S_ISREG(inode->i_mode)) {
 208                DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
 209                        inode->i_mode);
 210                return -EINVAL;
 211        }
 212
 213        errno = 0;
 214        if (!count)
 215                goto out;
 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        pos = *ppos;
 222
 223        if (file->f_flags & O_APPEND) {
 224                pos = inode->i_size;
 225        }
 226        bufsize = NCP_SERVER(inode)->buffer_size;
 227
 228        already_written = 0;
 229
 230        bouncebuffer = vmalloc(bufsize);
 231        if (!bouncebuffer) {
 232                errno = -EIO;   /* -ENOMEM */
 233                goto outrel;
 234        }
 235        while (already_written < count) {
 236                int written_this_time;
 237                size_t to_write = min_t(unsigned int,
 238                                      bufsize - (pos % bufsize),
 239                                      count - already_written);
 240
 241                if (copy_from_user(bouncebuffer, buf, to_write)) {
 242                        errno = -EFAULT;
 243                        break;
 244                }
 245                if (ncp_write_kernel(NCP_SERVER(inode), 
 246                    NCP_FINFO(inode)->file_handle,
 247                    pos, to_write, bouncebuffer, &written_this_time) != 0) {
 248                        errno = -EIO;
 249                        break;
 250                }
 251                pos += written_this_time;
 252                buf += written_this_time;
 253                already_written += written_this_time;
 254
 255                if (written_this_time != to_write) {
 256                        break;
 257                }
 258        }
 259        vfree(bouncebuffer);
 260        inode->i_mtime = inode->i_atime = CURRENT_TIME;
 261        
 262        *ppos = pos;
 263
 264        if (pos > inode->i_size) {
 265                inode->i_size = pos;
 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);         
 271out:
 272        return already_written ? already_written : errno;
 273}
 274
 275static int ncp_release(struct inode *inode, struct file *file) {
 276        if (ncp_make_closed(inode)) {
 277                DPRINTK("ncp_release: failed to close\n");
 278        }
 279        return 0;
 280}
 281
 282struct file_operations ncp_file_operations =
 283{
 284        llseek:         generic_file_llseek,
 285        read:           ncp_file_read,
 286        write:          ncp_file_write,
 287        ioctl:          ncp_ioctl,
 288        mmap:           ncp_mmap,
 289        release:        ncp_release,
 290        fsync:          ncp_fsync,
 291};
 292
 293struct inode_operations ncp_file_inode_operations =
 294{
 295        setattr:        ncp_notify_change,
 296};
 297
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.