root/fs/umsdos/rdir.c

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

DEFINITIONS

This source file includes following definitions.
  1. UMSDOS_rreaddir
  2. UMSDOS_rlookup
  3. 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 static int UMSDOS_rreaddir (
     /* [previous][next][first][last][top][bottom][index][help] */
  32         struct inode *dir,
  33         struct file *filp,
  34     struct dirent *dirent,
  35         int count)
  36 {
  37         int ret = 0;
  38         while (1){
  39                 int len = -1;
  40                 ret = msdos_readdir(dir,filp,dirent,count);
  41                 if (ret > 0) len = get_fs_word(&dirent->d_reclen);
  42                 if (len == 5
  43                         && pseudo_root != NULL
  44                         && dir->i_sb->s_mounted == pseudo_root->i_sb->s_mounted){
  45                         /*
  46                                 In pseudo root mode, we must eliminate logically
  47                                 the directory linux from the real root.
  48                         */
  49                         char name[5];
  50                         memcpy_fromfs (name,dirent->d_name,5);
  51                         if (memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0) break;
  52                 }else{
  53                         if (pseudo_root != NULL
  54                                 && len == 2
  55                                 && dir == dir->i_sb->s_mounted
  56                                 && dir == pseudo_root->i_sb->s_mounted){
  57                                 char name[2];
  58                                 memcpy_fromfs (name,dirent->d_name,2);
  59                                 if (name[0] == '.' && name[1] == '.'){
  60                                         put_fs_long (pseudo_root->i_ino,&dirent->d_ino);
  61                                 }
  62                         }
  63                         break;
  64                 }
  65         }
  66         return ret;
  67 }
  68 
  69 int UMSDOS_rlookup(
     /* [previous][next][first][last][top][bottom][index][help] */
  70         struct inode *dir,
  71         const char *name,
  72         int len,
  73         struct inode **result)  /* Will hold inode of the file, if successful */
  74 {
  75         int ret;
  76         if (pseudo_root != NULL
  77                 && len == 2
  78                 && name[0] == '.'
  79                 && name[1] == '.'
  80                 && dir == dir->i_sb->s_mounted
  81                 && dir == pseudo_root->i_sb->s_mounted){
  82                 *result = pseudo_root;
  83                 pseudo_root->i_count++;
  84                 ret = 0;
  85                 /* #Specification: pseudo root / DOS/..
  86                         In the real root directory (c:\), the directory ..
  87                         is the pseudo root (c:\linux).
  88                 */
  89         }else{
  90                 ret = umsdos_real_lookup (dir,name,len,result);
  91                 if (ret == 0){
  92                         struct inode *inode = *result;
  93                         if (inode == pseudo_root){
  94                                 /* #Specification: pseudo root / DOS/linux
  95                                         Even in the real root directory (c:\), the directory
  96                                         /linux won't show
  97                                 */
  98                                 ret = -ENOENT;
  99                                 iput (pseudo_root);
 100                                 *result = NULL;
 101                         }else if (S_ISDIR(inode->i_mode)){
 102                                 /* We must place the proper function table */
 103                                 /* depending if this is a MsDOS directory or an UMSDOS directory */
 104                                 umsdos_setup_dir_inode(inode);
 105                         }
 106                 }
 107         }
 108         iput (dir);
 109         return ret;
 110 }
 111 
 112 static int UMSDOS_rrmdir (
     /* [previous][next][first][last][top][bottom][index][help] */
 113         struct inode *dir,
 114         const char *name,
 115         int len)
 116 {
 117         /* #Specification: dual mode / rmdir in a DOS directory
 118                 In a DOS (not EMD in it) directory, we use a reverse strategy
 119                 compared with an Umsdos directory. We assume that a subdirectory
 120                 of a DOS directory is also a DOS directory. This is not always
 121                 true (umssync may be used anywhere), but make sense.
 122 
 123                 So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
 124                 then we check if it is a Umsdos directory. We check if it is
 125                 really empty (only . .. and --linux-.--- in it). If it is true
 126                 we remove the EMD and do a msdos_rmdir() again.
 127 
 128                 In a Umsdos directory, we assume all subdirectory are also
 129                 Umsdos directory, so we check the EMD file first.
 130         */
 131         int ret;
 132         if (umsdos_is_pseudodos(dir,name,len)){
 133                 /* #Specification: pseudo root / rmdir /DOS
 134                         The pseudo sub-directory /DOS can't be removed!
 135                         This is done even if the pseudo root is not a Umsdos
 136                         directory anymore (very unlikely), but an accident (under
 137                         MsDOS) is always possible.
 138 
 139                         EPERM is returned.
 140                 */
 141                 ret = -EPERM;
 142         }else{
 143                 umsdos_lockcreate (dir);
 144                 dir->i_count++;
 145                 ret = msdos_rmdir (dir,name,len);
 146                 if (ret == -ENOTEMPTY){
 147                         struct inode *sdir;
 148                         dir->i_count++;
 149                         ret = UMSDOS_rlookup (dir,name,len,&sdir);
 150                         PRINTK (("rrmdir lookup %d ",ret));
 151                         if (ret == 0){
 152                                 int empty;
 153                                 if ((empty = umsdos_isempty (sdir)) != 0){
 154                                         PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
 155                                         if (empty == 2){
 156                                                 /*
 157                                                         Not a Umsdos directory, so the previous msdos_rmdir
 158                                                         was not lying :-)
 159                                                 */
 160                                                 ret = -ENOTEMPTY;
 161                                         }else if (empty == 1){
 162                                                 /* We have to removed the EMD file */
 163                                                 ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
 164                                                         ,UMSDOS_EMD_NAMELEN);
 165                                                 sdir = NULL;
 166                                                 if (ret == 0){
 167                                                         dir->i_count++;
 168                                                         ret = msdos_rmdir (dir,name,len);
 169                                                 }
 170                                         }
 171                                 }else{
 172                                         ret = -ENOTEMPTY;
 173                                 }
 174                                 iput (sdir);
 175                         }
 176                 }
 177                 umsdos_unlockcreate (dir);
 178         }
 179         iput (dir);
 180         return ret;
 181 }
 182 
 183 /* #Specification: dual mode / introduction
 184         One goal of UMSDOS is to allow a practical and simple coexistence
 185         between MsDOS and Linux in a single partition. Using the EMD file
 186         in each directory, UMSDOS add Unix semantics and capabilities to
 187         normal DOS file system. To help and simplify coexistence, here is
 188         the logic related to the EMD file.
 189 
 190         If it is missing, then the directory is managed by the MsDOS driver.
 191         The names are limited to DOS limits (8.3). No links, no device special
 192         and pipe and so on.
 193 
 194         If it is there, it is the directory. If it is there but empty, then
 195         the directory looks empty. The utility umssync allows synchronisation
 196         of the real DOS directory and the EMD.
 197 
 198         Whenever umssync is applied to a directory without EMD, one is
 199         created on the fly. The directory is promoted to full unix semantic.
 200         Of course, the ls command will show exactly the same content as before
 201         the umssync session.
 202 
 203         It is believed that the user/admin will promote directories to unix
 204         semantic as needed.
 205 
 206         The strategy to implement this is to use two function table (struct
 207         inode_operations). One for true UMSDOS directory and one for directory
 208         with missing EMD.
 209 
 210         Functions related to the DOS semantic (but aware of UMSDOS) generally
 211         have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
 212         from the one with full UMSDOS semantic.
 213 */
 214 static struct file_operations umsdos_rdir_operations = {
 215         NULL,                           /* lseek - default */
 216         UMSDOS_dir_read,        /* read */
 217         NULL,                           /* write - bad */
 218         UMSDOS_rreaddir,        /* readdir */
 219         NULL,                           /* select - default */
 220         UMSDOS_ioctl_dir,       /* ioctl - default */
 221         NULL,                           /* mmap */
 222         NULL,                           /* no special open code */
 223         NULL,                           /* no special release code */
 224         NULL                            /* fsync */
 225 };
 226 
 227 struct inode_operations umsdos_rdir_inode_operations = {
 228         &umsdos_rdir_operations,        /* default directory file-ops */
 229         msdos_create,           /* create */
 230         UMSDOS_rlookup,         /* lookup */
 231         NULL,                           /* link */
 232         msdos_unlink,           /* unlink */
 233         NULL,                           /* symlink */
 234         msdos_mkdir,            /* mkdir */
 235         UMSDOS_rrmdir,          /* rmdir */
 236         NULL,                           /* mknod */
 237         msdos_rename,           /* rename */
 238         NULL,                           /* readlink */
 239         NULL,                           /* follow_link */
 240         NULL,                           /* bmap */
 241         NULL,                           /* truncate */
 242         NULL                            /* permission */
 243 };
 244 
 245 

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