root/fs/umsdos/rdir.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rdir_filldir
  2. UMSDOS_rreaddir
  3. umsdos_rlookup_x
  4. UMSDOS_rlookup
  5. UMSDOS_rrmdir

   1 /*
   2  *  linux/fs/umsdos/rdir.c
   3  *
   4  *  Written 1994 by Jacques Gelinas
   5  *
   6  *  Extended MS-DOS directory pure MS-DOS handling functions
   7  *  (For directory without EMD file).
   8  */
   9 
  10 #ifdef MODULE
  11 #include <linux/module.h>
  12 #endif
  13 
  14 #include <asm/segment.h>
  15 
  16 #include <linux/sched.h>
  17 #include <linux/fs.h>
  18 #include <linux/msdos_fs.h>
  19 #include <linux/errno.h>
  20 #include <linux/stat.h>
  21 #include <linux/limits.h>
  22 #include <linux/umsdos_fs.h>
  23 #include <linux/malloc.h>
  24 
  25 #define PRINTK(x)
  26 #define Printk(x) printk x
  27 
  28 
  29 extern struct inode *pseudo_root;
  30 
  31 struct RDIR_FILLDIR {
  32         void *dirbuf;
  33         filldir_t filldir;
  34         int real_root;
  35 };
  36 
  37 static int rdir_filldir(
     /* [previous][next][first][last][top][bottom][index][help] */
  38         void * buf,
  39         const char * name,
  40         int name_len,
  41         off_t offset,
  42         ino_t ino)
  43 {
  44         int ret = 0;
  45         struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf;
  46         if (d->real_root){
  47                 /* real root of a pseudo_rooted partition */
  48                 if (name_len != UMSDOS_PSDROOT_LEN
  49                         || memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){
  50                         /* So it is not the /linux directory */
  51                         if (name_len == 2
  52                                 && name[0] == '.'
  53                                 && name[1] == '.'){
  54                                 /* Make sure the .. entry points back to the pseudo_root */
  55                                 ino = pseudo_root->i_ino;
  56                         }
  57                         ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
  58                 }
  59         }else{
  60                 /* Any DOS directory */
  61                 ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
  62         }
  63         return ret;
  64 }
  65 
  66 
  67 static int UMSDOS_rreaddir (
     /* [previous][next][first][last][top][bottom][index][help] */
  68         struct inode *dir,
  69         struct file *filp,
  70     void *dirbuf,
  71         filldir_t filldir)
  72 {
  73         struct RDIR_FILLDIR bufk;
  74         bufk.filldir = filldir;
  75         bufk.dirbuf = dirbuf;
  76         bufk.real_root = pseudo_root != NULL
  77                 && dir == dir->i_sb->s_mounted
  78                 && dir == pseudo_root->i_sb->s_mounted;
  79         return msdos_readdir(dir,filp,&bufk,rdir_filldir);
  80 }
  81 
  82 /*
  83         Lookup into a non promoted directory.
  84         If the result is a directory, make sure we find out if it is
  85         a promoted one or not (calling umsdos_setup_dir_inode(inode)).
  86 */
  87 int umsdos_rlookup_x(
     /* [previous][next][first][last][top][bottom][index][help] */
  88         struct inode *dir,
  89         const char *name,
  90         int len,
  91         struct inode **result,  /* Will hold inode of the file, if successful */
  92         int nopseudo)                   /* Don't care about pseudo root mode */
  93                                                         /* so locating "linux" will work */
  94 {
  95         int ret;
  96         if (pseudo_root != NULL
  97                 && len == 2
  98                 && name[0] == '.'
  99                 && name[1] == '.'
 100                 && dir == dir->i_sb->s_mounted
 101                 && dir == pseudo_root->i_sb->s_mounted){
 102                 *result = pseudo_root;
 103                 pseudo_root->i_count++;
 104                 ret = 0;
 105                 /* #Specification: pseudo root / DOS/..
 106                         In the real root directory (c:\), the directory ..
 107                         is the pseudo root (c:\linux).
 108                 */
 109         }else{
 110                 ret = umsdos_real_lookup (dir,name,len,result);
 111                 if (ret == 0){
 112                         struct inode *inode = *result;
 113                         if (inode == pseudo_root && !nopseudo){
 114                                 /* #Specification: pseudo root / DOS/linux
 115                                         Even in the real root directory (c:\), the directory
 116                                         /linux won't show
 117                                 */
 118                                 ret = -ENOENT;
 119                                 iput (pseudo_root);
 120                                 *result = NULL;
 121                         }else if (S_ISDIR(inode->i_mode)){
 122                                 /* We must place the proper function table */
 123                                 /* depending if this is a MsDOS directory or an UMSDOS directory */
 124                                 umsdos_setup_dir_inode(inode);
 125                         }
 126                 }
 127         }
 128         iput (dir);
 129         return ret;
 130 }
 131 int UMSDOS_rlookup(
     /* [previous][next][first][last][top][bottom][index][help] */
 132         struct inode *dir,
 133         const char *name,
 134         int len,
 135         struct inode **result)  /* Will hold inode of the file, if successful */
 136 {
 137         return umsdos_rlookup_x(dir,name,len,result,0);
 138 }
 139 
 140 static int UMSDOS_rrmdir (
     /* [previous][next][first][last][top][bottom][index][help] */
 141         struct inode *dir,
 142         const char *name,
 143         int len)
 144 {
 145         /* #Specification: dual mode / rmdir in a DOS directory
 146                 In a DOS (not EMD in it) directory, we use a reverse strategy
 147                 compared with an Umsdos directory. We assume that a subdirectory
 148                 of a DOS directory is also a DOS directory. This is not always
 149                 true (umssync may be used anywhere), but make sense.
 150 
 151                 So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
 152                 then we check if it is a Umsdos directory. We check if it is
 153                 really empty (only . .. and --linux-.--- in it). If it is true
 154                 we remove the EMD and do a msdos_rmdir() again.
 155 
 156                 In a Umsdos directory, we assume all subdirectory are also
 157                 Umsdos directory, so we check the EMD file first.
 158         */
 159         int ret;
 160         if (umsdos_is_pseudodos(dir,name,len)){
 161                 /* #Specification: pseudo root / rmdir /DOS
 162                         The pseudo sub-directory /DOS can't be removed!
 163                         This is done even if the pseudo root is not a Umsdos
 164                         directory anymore (very unlikely), but an accident (under
 165                         MsDOS) is always possible.
 166 
 167                         EPERM is returned.
 168                 */
 169                 ret = -EPERM;
 170         }else{
 171                 umsdos_lockcreate (dir);
 172                 dir->i_count++;
 173                 ret = msdos_rmdir (dir,name,len);
 174                 if (ret == -ENOTEMPTY){
 175                         struct inode *sdir;
 176                         dir->i_count++;
 177                         ret = UMSDOS_rlookup (dir,name,len,&sdir);
 178                         PRINTK (("rrmdir lookup %d ",ret));
 179                         if (ret == 0){
 180                                 int empty;
 181                                 if ((empty = umsdos_isempty (sdir)) != 0){
 182                                         PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
 183                                         if (empty == 2){
 184                                                 /*
 185                                                         Not a Umsdos directory, so the previous msdos_rmdir
 186                                                         was not lying :-)
 187                                                 */
 188                                                 ret = -ENOTEMPTY;
 189                                         }else if (empty == 1){
 190                                                 /* We have to removed the EMD file */
 191                                                 ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
 192                                                         ,UMSDOS_EMD_NAMELEN);
 193                                                 sdir = NULL;
 194                                                 if (ret == 0){
 195                                                         dir->i_count++;
 196                                                         ret = msdos_rmdir (dir,name,len);
 197                                                 }
 198                                         }
 199                                 }else{
 200                                         ret = -ENOTEMPTY;
 201                                 }
 202                                 iput (sdir);
 203                         }
 204                 }
 205                 umsdos_unlockcreate (dir);
 206         }
 207         iput (dir);
 208         return ret;
 209 }
 210 
 211 /* #Specification: dual mode / introduction
 212         One goal of UMSDOS is to allow a practical and simple coexistence
 213         between MsDOS and Linux in a single partition. Using the EMD file
 214         in each directory, UMSDOS add Unix semantics and capabilities to
 215         normal DOS file system. To help and simplify coexistence, here is
 216         the logic related to the EMD file.
 217 
 218         If it is missing, then the directory is managed by the MsDOS driver.
 219         The names are limited to DOS limits (8.3). No links, no device special
 220         and pipe and so on.
 221 
 222         If it is there, it is the directory. If it is there but empty, then
 223         the directory looks empty. The utility umssync allows synchronisation
 224         of the real DOS directory and the EMD.
 225 
 226         Whenever umssync is applied to a directory without EMD, one is
 227         created on the fly. The directory is promoted to full unix semantic.
 228         Of course, the ls command will show exactly the same content as before
 229         the umssync session.
 230 
 231         It is believed that the user/admin will promote directories to unix
 232         semantic as needed.
 233 
 234         The strategy to implement this is to use two function table (struct
 235         inode_operations). One for true UMSDOS directory and one for directory
 236         with missing EMD.
 237 
 238         Functions related to the DOS semantic (but aware of UMSDOS) generally
 239         have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
 240         from the one with full UMSDOS semantic.
 241 */
 242 static struct file_operations umsdos_rdir_operations = {
 243         NULL,                           /* lseek - default */
 244         UMSDOS_dir_read,        /* read */
 245         NULL,                           /* write - bad */
 246         UMSDOS_rreaddir,        /* readdir */
 247         NULL,                           /* select - default */
 248         UMSDOS_ioctl_dir,       /* ioctl - default */
 249         NULL,                           /* mmap */
 250         NULL,                           /* no special open code */
 251         NULL,                           /* no special release code */
 252         NULL                            /* fsync */
 253 };
 254 
 255 struct inode_operations umsdos_rdir_inode_operations = {
 256         &umsdos_rdir_operations,        /* default directory file-ops */
 257         msdos_create,           /* create */
 258         UMSDOS_rlookup,         /* lookup */
 259         NULL,                           /* link */
 260         msdos_unlink,           /* unlink */
 261         NULL,                           /* symlink */
 262         msdos_mkdir,            /* mkdir */
 263         UMSDOS_rrmdir,          /* rmdir */
 264         NULL,                           /* mknod */
 265         msdos_rename,           /* rename */
 266         NULL,                           /* readlink */
 267         NULL,                           /* follow_link */
 268         NULL,                           /* bmap */
 269         NULL,                           /* truncate */
 270         NULL                            /* permission */
 271 };
 272 
 273 

/* [previous][next][first][last][top][bottom][index][help] */