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