linux/fs/ncpfs/symlink.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/ncpfs/symlink.c
   3 *
   4 *  Code for allowing symbolic links on NCPFS (i.e. NetWare)
   5 *  Symbolic links are not supported on native NetWare, so we use an
   6 *  infrequently-used flag (Sh) and store a two-word magic header in
   7 *  the file to make sure we don't accidentally use a non-link file
   8 *  as a link.
   9 *
  10 *  When using the NFS namespace, we set the mode to indicate a symlink and
  11 *  don't bother with the magic numbers.
  12 *
  13 *  from linux/fs/ext2/symlink.c
  14 *
  15 *  Copyright (C) 1998-99, Frank A. Vorstenbosch
  16 *
  17 *  ncpfs symlink handling code
  18 *  NLS support (c) 1999 Petr Vandrovec
  19 *  Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
  20 *
  21 */
  22
  23
  24#include <linux/uaccess.h>
  25
  26#include <linux/errno.h>
  27#include <linux/fs.h>
  28#include <linux/time.h>
  29#include <linux/slab.h>
  30#include <linux/mm.h>
  31#include <linux/stat.h>
  32#include "ncp_fs.h"
  33
  34/* these magic numbers must appear in the symlink file -- this makes it a bit
  35   more resilient against the magic attributes being set on random files. */
  36
  37#define NCP_SYMLINK_MAGIC0      cpu_to_le32(0x6c6d7973)     /* "symlnk->" */
  38#define NCP_SYMLINK_MAGIC1      cpu_to_le32(0x3e2d6b6e)
  39
  40/* ----- read a symbolic link ------------------------------------------ */
  41
  42static int ncp_symlink_readpage(struct file *file, struct page *page)
  43{
  44        struct inode *inode = page->mapping->host;
  45        int error, length, len;
  46        char *link, *rawlink;
  47        char *buf = kmap(page);
  48
  49        error = -ENOMEM;
  50        rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
  51        if (!rawlink)
  52                goto fail;
  53
  54        if (ncp_make_open(inode,O_RDONLY))
  55                goto failEIO;
  56
  57        error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
  58                         0,NCP_MAX_SYMLINK_SIZE,rawlink,&length);
  59
  60        ncp_inode_close(inode);
  61        /* Close file handle if no other users... */
  62        ncp_make_closed(inode);
  63        if (error)
  64                goto failEIO;
  65
  66        if (NCP_FINFO(inode)->flags & NCPI_KLUDGE_SYMLINK) {
  67                if (length<NCP_MIN_SYMLINK_SIZE || 
  68                    ((__le32 *)rawlink)[0]!=NCP_SYMLINK_MAGIC0 ||
  69                    ((__le32 *)rawlink)[1]!=NCP_SYMLINK_MAGIC1)
  70                        goto failEIO;
  71                link = rawlink + 8;
  72                length -= 8;
  73        } else {
  74                link = rawlink;
  75        }
  76
  77        len = NCP_MAX_SYMLINK_SIZE;
  78        error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link, length, 0);
  79        kfree(rawlink);
  80        if (error)
  81                goto fail;
  82        SetPageUptodate(page);
  83        kunmap(page);
  84        unlock_page(page);
  85        return 0;
  86
  87failEIO:
  88        error = -EIO;
  89        kfree(rawlink);
  90fail:
  91        SetPageError(page);
  92        kunmap(page);
  93        unlock_page(page);
  94        return error;
  95}
  96
  97/*
  98 * symlinks can't do much...
  99 */
 100const struct address_space_operations ncp_symlink_aops = {
 101        .readpage       = ncp_symlink_readpage,
 102};
 103        
 104/* ----- create a new symbolic link -------------------------------------- */
 105 
 106int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
 107        struct inode *inode;
 108        char *rawlink;
 109        int length, err, i, outlen;
 110        int kludge;
 111        umode_t mode;
 112        __le32 attr;
 113        unsigned int hdr;
 114
 115        ncp_dbg(1, "dir=%p, dentry=%p, symname=%s\n", dir, dentry, symname);
 116
 117        if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber))
 118                kludge = 0;
 119        else
 120#ifdef CONFIG_NCPFS_EXTRAS
 121        if (NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS)
 122                kludge = 1;
 123        else
 124#endif
 125        /* EPERM is returned by VFS if symlink procedure does not exist */
 126                return -EPERM;
 127  
 128        rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
 129        if (!rawlink)
 130                return -ENOMEM;
 131
 132        if (kludge) {
 133                mode = 0;
 134                attr = aSHARED | aHIDDEN;
 135                ((__le32 *)rawlink)[0]=NCP_SYMLINK_MAGIC0;
 136                ((__le32 *)rawlink)[1]=NCP_SYMLINK_MAGIC1;
 137                hdr = 8;
 138        } else {
 139                mode = S_IFLNK | S_IRWXUGO;
 140                attr = 0;
 141                hdr = 0;
 142        }                       
 143
 144        length = strlen(symname);
 145        /* map to/from server charset, do not touch upper/lower case as
 146           symlink can point out of ncp filesystem */
 147        outlen = NCP_MAX_SYMLINK_SIZE - hdr;
 148        err = ncp_io2vol(NCP_SERVER(dir), rawlink + hdr, &outlen, symname, length, 0);
 149        if (err)
 150                goto failfree;
 151
 152        outlen += hdr;
 153
 154        err = -EIO;
 155        if (ncp_create_new(dir,dentry,mode,0,attr)) {
 156                goto failfree;
 157        }
 158
 159        inode=d_inode(dentry);
 160
 161        if (ncp_make_open(inode, O_WRONLY))
 162                goto failfree;
 163
 164        if (ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, 
 165                             0, outlen, rawlink, &i) || i!=outlen) {
 166                goto fail;
 167        }
 168
 169        ncp_inode_close(inode);
 170        ncp_make_closed(inode);
 171        kfree(rawlink);
 172        return 0;
 173fail:;
 174        ncp_inode_close(inode);
 175        ncp_make_closed(inode);
 176failfree:;
 177        kfree(rawlink);
 178        return err;
 179}
 180
 181/* ----- EOF ----- */
 182