root/fs/umsdos/dir.c

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

DEFINITIONS

This source file includes following definitions.
  1. UMSDOS_dir_read
  2. umsdos_readdir_x
  3. UMSDOS_readdir
  4. umsdos_lookup_patch
  5. umsdos_inode2entry
  6. umsdos_locate_ancestor
  7. umsdos_locate_path
  8. umsdos_is_pseudodos
  9. umsdos_lookup_x
  10. UMSDOS_lookup
  11. umsdos_hlink2inode

   1 /*
   2  *  linux/fs/umsdos/dir.c
   3  *
   4  *  Written 1993 by Jacques Gelinas
   5  *      Inspired from linux/fs/msdos/... : Werner Almesberger
   6  *
   7  *  Extended MS-DOS directory handling functions
   8  */
   9 
  10 #include <asm/segment.h>
  11 
  12 #include <linux/sched.h>
  13 #include <linux/string.h>
  14 #include <linux/fs.h>
  15 #include <linux/msdos_fs.h>
  16 #include <linux/errno.h>
  17 #include <linux/stat.h>
  18 #include <linux/limits.h>
  19 #include <linux/umsdos_fs.h>
  20 #include <linux/malloc.h>
  21 
  22 #define PRINTK(x)
  23 #define Printk(x) printk x
  24 
  25 #define UMSDOS_SPECIAL_DIRFPOS  3
  26 extern struct inode *pseudo_root;
  27 /*
  28         So  grep *  doesn't complain in the presence of directories.
  29 */
  30 int UMSDOS_dir_read(struct inode *inode,struct file *filp,char *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
  31     int count)
  32 {
  33         return -EISDIR;
  34 }
  35 /*
  36         Read count directory entries from directory filp
  37         Return a negative value from linux/errno.h.
  38         Return > 0 if success (the length of the file name).
  39 
  40         This function is used by the normal readdir VFS entry point and by
  41         some function who try to find out info on a file from a pure MSDOS
  42         inode. See umsdos_locate_ancestor() below.
  43 */
  44 static int umsdos_readdir_x(
     /* [previous][next][first][last][top][bottom][index][help] */
  45         struct inode *dir,              /* Point to a description of the super block */
  46         struct file *filp,              /* Point to a directory which is read */
  47     struct dirent *dirent,      /* Will hold count directory entry */
  48         int dirent_in_fs,               /* dirent point in user's space ? */
  49         int count,
  50         struct umsdos_dirent *u_entry,  /* Optional umsdos entry */
  51         int follow_hlink,
  52         off_t *pt_f_pos)                /* will hold the offset of the entry in EMD */
  53 {
  54         int ret = 0;
  55         
  56         umsdos_startlookup(dir);        
  57         if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
  58                 && dir == pseudo_root
  59                 && dirent_in_fs){
  60                 /*
  61                         We don't need to simulate this pseudo directory
  62                         when umsdos_readdir_x is called for internal operation
  63                         of umsdos. This is why dirent_in_fs is tested
  64                 */
  65                 /* #Specification: pseudo root / directory /DOS
  66                         When umsdos operates in pseudo root mode (C:\linux is the
  67                         linux root), it simulate a directory /DOS which points to
  68                         the real root of the file system.
  69                 */
  70                 put_fs_long(dir->i_sb->s_mounted->i_ino,&dirent->d_ino);
  71                 memcpy_tofs (dirent->d_name,"DOS",3);
  72                 put_fs_byte(0,dirent->d_name+3);
  73                 put_fs_word (3,&dirent->d_reclen);
  74                 if (u_entry != NULL) u_entry->flags = 0;
  75                 ret = 3;
  76                 filp->f_pos++;
  77         }else if (filp->f_pos < 2
  78                 || (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){
  79                 /* #Specification: readdir / . and ..
  80                         The msdos filesystem manage the . and .. entry properly
  81                         so the EMD file won't hold any info about it.
  82 
  83                         In readdir, we assume that for the root directory
  84                         the read position will be 0 for ".", 1 for "..". For
  85                         a non root directory, the read position will be 0 for "."
  86                         and 32 for "..".
  87                 */
  88                 /*
  89                         This is a trick used by the msdos file system (fs/msdos/dir.c)
  90                         to manage . and .. for the root directory of a file system.
  91                         Since there is no such entry in the root, fs/msdos/dir.c
  92                         use the following:
  93 
  94                         if f_pos == 0, return ".".
  95                         if f_pos == 1, return "..".
  96 
  97                         So let msdos handle it
  98 
  99                         Since umsdos entries are much larger, we share the same f_pos.
 100                         if f_pos is 0 or 1 or 32, we are clearly looking at . and
 101                         ..
 102 
 103                         As soon as we get f_pos == 2 or f_pos == 64, then back to
 104                         0, but this time we are reading the EMD file.
 105 
 106                         Well, not so true. The problem, is that UMSDOS_REC_SIZE is
 107                         also 64, so as soon as we read the first record in the
 108                         EMD, we are back at offset 64. So we set the offset
 109                         to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
 110                         .. entry from msdos.
 111                 */
 112                 ret = msdos_readdir(dir,filp,dirent,count);
 113                 if (filp->f_pos == 64) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
 114                 if (u_entry != NULL) u_entry->flags = 0;
 115         }else{
 116                 struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
 117                 if (emd_dir != NULL){
 118                         if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0;
 119                         PRINTK (("f_pos %ld i_size %d\n",filp->f_pos,emd_dir->i_size));
 120                         ret = 0;
 121                         while (filp->f_pos < emd_dir->i_size){
 122                                 struct umsdos_dirent entry;
 123                                 off_t cur_f_pos = filp->f_pos;
 124                                 if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){
 125                                         ret = -EIO;
 126                                         break;
 127                                 }else if (entry.name_len != 0){
 128                                         /* #Specification: umsdos / readdir
 129                                                 umsdos_readdir() should fill a struct dirent with
 130                                                 an inode number. The cheap way to get it is to
 131                                                 do a lookup in the MSDOS directory for each
 132                                                 entry processed by the readdir() function.
 133                                                 This is not very efficient, but very simple. The
 134                                                 other way around is to maintain a copy of the inode
 135                                                 number in the EMD file. This is a problem because
 136                                                 this has to be maintained in sync using tricks.
 137                                                 Remember that MSDOS (the OS) does not update the
 138                                                 modification time (mtime) of a directory. There is
 139                                                 no easy way to tell that a directory was modified
 140                                                 during a DOS session and synchronise the EMD file.
 141 
 142                                                 Suggestion welcome.
 143 
 144                                                 So the easy way is used!
 145                                         */
 146                                         struct umsdos_info info;
 147                                         struct inode *inode;
 148                                         int lret;
 149                                         umsdos_parse (entry.name,entry.name_len,&info);
 150                                         info.f_pos = cur_f_pos;
 151                                         *pt_f_pos = cur_f_pos;
 152                                         umsdos_manglename (&info);
 153                                         lret = umsdos_real_lookup (dir,info.fake.fname
 154                                                 ,info.fake.len,&inode);
 155                                         PRINTK (("Cherche inode de %s lret %d flags %d\n"
 156                                                 ,info.fake.fname,lret,entry.flags));
 157                                         if (lret == 0
 158                                                 && (entry.flags & UMSDOS_HLINK)
 159                                                 && follow_hlink){
 160                                                 struct inode *rinode;
 161                                                 lret = umsdos_hlink2inode (inode,&rinode);
 162                                                 inode = rinode;
 163                                         }
 164                                         if (lret == 0){
 165                                                 /* #Specification: pseudo root / reading real root
 166                                                         The pseudo root (/linux) is logically
 167                                                         erased from the real root. This mean that
 168                                                         ls /DOS, won't show "linux". This avoids
 169                                                         infinite recursion /DOS/linux/DOS/linux while
 170                                                         walking the file system.
 171                                                 */
 172                                                 if (inode != pseudo_root){
 173                                                         PRINTK (("Trouve ino %d ",inode->i_ino));
 174                                                         if (dirent_in_fs){
 175                                                                 put_fs_long(inode->i_ino,&dirent->d_ino);
 176                                                                 memcpy_tofs (dirent->d_name,entry.name
 177                                                                         ,entry.name_len);
 178                                                                 put_fs_byte(0,dirent->d_name+entry.name_len);
 179                                                                 put_fs_word (entry.name_len
 180                                                                         ,&dirent->d_reclen);
 181                                                                 /* In this case, the caller only needs */
 182                                                                 /* flags */
 183                                                                 if (u_entry != NULL){
 184                                                                         u_entry->flags = entry.flags;
 185                                                                 }
 186                                                         }else{
 187                                                                 dirent->d_ino = inode->i_ino;
 188                                                                 memcpy (dirent->d_name,entry.name
 189                                                                         ,entry.name_len);
 190                                                                 dirent->d_name[entry.name_len] = '\0';
 191                                                                 dirent->d_reclen = entry.name_len;
 192                                                                 if (u_entry != NULL) *u_entry = entry;
 193                                                         }
 194                                                         ret = entry.name_len;
 195                                                         iput (inode);
 196                                                         break;
 197                                                 }
 198                                                 iput (inode);
 199                                         }else{
 200                                                 /* #Specification: umsdos / readdir / not in MSDOS
 201                                                         During a readdir operation, if the file is not
 202                                                         in the MSDOS directory anymore, the entry is
 203                                                         removed from the EMD file silently.
 204                                                 */
 205                                                 ret = umsdos_writeentry (dir,emd_dir,&info,1);
 206                                                 if (ret != 0){
 207                                                         break;
 208                                                 }
 209                                         }
 210                                 }
 211                         }
 212                         iput(emd_dir);
 213                 }
 214         }
 215         umsdos_endlookup(dir);  
 216         PRINTK (("read dir %p pos %d ret %d\n",dir,filp->f_pos,ret));
 217         return ret;
 218 }
 219 /*
 220         Read count directory entries from directory filp
 221         Return a negative value from linux/errno.h.
 222         Return > 0 if success (the length of the file name).
 223 */
 224 static int UMSDOS_readdir(
     /* [previous][next][first][last][top][bottom][index][help] */
 225         struct inode *dir,              /* Point to a description of the super block */
 226         struct file *filp,              /* Point to a directory which is read */
 227     struct dirent *dirent,      /* Will hold count directory entry */
 228         int count)
 229 {
 230         int ret = -ENOENT;
 231         while (1){
 232                 struct umsdos_dirent entry;
 233                 off_t f_pos;
 234                 ret = umsdos_readdir_x (dir,filp,dirent,1,count,&entry,1,&f_pos);
 235                 if (ret <= 0 || !(entry.flags & UMSDOS_HIDDEN)) break;
 236         }
 237         return ret;
 238 }
 239 /*
 240         Complete the inode content with info from the EMD file
 241 */
 242 void umsdos_lookup_patch (
     /* [previous][next][first][last][top][bottom][index][help] */
 243         struct inode *dir,
 244         struct inode *inode,
 245         struct umsdos_dirent *entry,
 246         off_t  emd_pos)
 247 {
 248         /*
 249                 This function modify the state of a dir inode. It decides
 250                 if the dir is a umsdos dir or a dos dir. This is done
 251                 deeper in umsdos_patch_inode() called at the end of this function.
 252 
 253                 umsdos_patch_inode() may block because it is doing disk access.
 254                 At the same time, another process may get here to initialise
 255                 the same dir inode. There is 3 cases.
 256 
 257                 1-The inode is already initialised. We do nothing.
 258                 2-The inode is not initialised. We lock access and do it.
 259                 3-Like 2 but another process has lock the inode, so we try
 260                   to lock it and right after check if initialisation is still
 261                   needed.
 262 
 263 
 264                 Thanks to the mem option of the kernel command line, it was
 265                 possible to consistently reproduce this problem by limiting
 266                 my mem to 4 meg and running X.
 267         */
 268         /*
 269                 Do this only if the inode is freshly read, because we will lose
 270                 the current (updated) content.
 271         */
 272         /*
 273                 A lookup of a mount point directory yield the inode into
 274                 the other fs, so we don't care about initialising it. iget()
 275                 does this automatically.
 276         */
 277         if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){
 278                 if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode);
 279                 if (!umsdos_isinit(inode)){
 280                         /* #Specification: umsdos / lookup / inode info
 281                                 After successfully reading an inode from the MSDOS
 282                                 filesystem, we use the EMD file to complete it.
 283                                 We update the following field.
 284 
 285                                 uid, gid, atime, ctime, mtime, mode.
 286 
 287                                 We rely on MSDOS for mtime. If the file
 288                                 was modified during an MSDOS session, at least
 289                                 mtime will be meaningful. We do this only for regular
 290                                 file.
 291                                 
 292                                 We don't rely on MSDOS for mtime for directory because
 293                                 the MSDOS directory date is creation time (strange
 294                                 MSDOS behavior) which fit nowhere in the three UNIX
 295                                 time stamp.
 296                         */
 297                         if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime;
 298                         inode->i_mode  = entry->mode;
 299                         inode->i_rdev  = entry->rdev;
 300                         inode->i_atime = entry->atime;
 301                         inode->i_ctime = entry->ctime;
 302                         inode->i_mtime = entry->mtime;
 303                         inode->i_uid   = entry->uid;
 304                         inode->i_gid   = entry->gid;
 305                         /* #Specification: umsdos / i_nlink
 306                                 The nlink field of an inode is maintain by the MSDOS file system
 307                                 for directory and by UMSDOS for other file. The logic is that
 308                                 MSDOS is already figuring out what to do for directories and
 309                                 does nothing for other files. For MSDOS, there are no hard link
 310                                 so all file carry nlink==1. UMSDOS use some info in the
 311                                 EMD file to plug the correct value.
 312                         */
 313                         if (!S_ISDIR(entry->mode)){
 314                                 if (entry->nlink > 0){
 315                                         inode->i_nlink = entry->nlink;
 316                                 }else{
 317                                         printk ("UMSDOS: lookup_patch entry->nlink < 1 ???\n");
 318                                 }
 319                         }
 320                         umsdos_patch_inode(inode,dir,emd_pos);
 321                 }
 322                 if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode);
 323 if (inode->u.umsdos_i.i_emd_owner==0) printk ("emd_owner still 0 ???\n");
 324         }
 325 }
 326 /*
 327         Locate entry of an inode in a directory.
 328         Return 0 or a negative error code.
 329 
 330         Normally, this function must succeed. It means a strange corruption
 331         in the file system if not.
 332 */
 333 int umsdos_inode2entry (
     /* [previous][next][first][last][top][bottom][index][help] */
 334         struct inode *dir,
 335         struct inode *inode,
 336         struct umsdos_dirent *entry)    /* Will hold the entry */
 337 {
 338         int ret = -ENOENT;
 339         if (inode == pseudo_root){
 340                 /*
 341                         Quick way to find the name.
 342                         Also umsdos_readdir_x won't show /linux anyway
 343                 */
 344                 memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1);
 345                 entry->name_len = UMSDOS_PSDROOT_LEN;
 346                 ret = 0;
 347         }else{
 348                 struct inode *emddir = umsdos_emd_dir_lookup(dir,0);
 349                 iput (emddir);
 350                 if (emddir == NULL){
 351                         /* This is a DOS directory */
 352                         struct file filp;
 353                         filp.f_reada = 1;
 354                         filp.f_pos = 0;
 355                         while (1){
 356                                 struct dirent dirent;
 357                                 if (umsdos_readdir_kmem (dir,&filp,&dirent,1) <= 0){
 358                                         printk ("UMSDOS: can't locate inode %ld in DOS directory???\n"
 359                                                 ,inode->i_ino);
 360                                 }else if (dirent.d_ino == inode->i_ino){
 361                                         ret = 0;
 362                                         memcpy (entry->name,dirent.d_name,dirent.d_reclen);
 363                                         entry->name[dirent.d_reclen] = '\0';
 364                                         entry->name_len = dirent.d_reclen;
 365                                         inode->u.umsdos_i.i_dir_owner = dir->i_ino;
 366                                         inode->u.umsdos_i.i_emd_owner = 0;
 367                                         umsdos_setup_dir_inode(inode);
 368                                         break;
 369                                 }
 370                         }
 371                 }else{
 372                         /* skip . and .. see umsdos_readdir_x() */
 373                         struct file filp;
 374                         filp.f_reada = 1;
 375                         filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
 376                         while (1){
 377                                 struct dirent dirent;
 378                                 off_t f_pos;
 379                                 if (umsdos_readdir_x(dir,&filp,&dirent
 380                                         ,0,1,entry,0,&f_pos) <= 0){
 381                                         printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
 382                                                 ,inode->i_ino);
 383                                         break;
 384                                 }else if (dirent.d_ino == inode->i_ino){
 385                                         ret = 0;
 386                                         umsdos_lookup_patch (dir,inode,entry,f_pos);
 387                                         break;
 388                                 }
 389                         }
 390                 }
 391         }
 392         return ret;
 393 }
 394 /*
 395         Locate the parent of a directory and the info on that directory
 396         Return 0 or a negative error code.
 397 */
 398 static int umsdos_locate_ancestor (
     /* [previous][next][first][last][top][bottom][index][help] */
 399         struct inode *dir,
 400         struct inode **result,
 401         struct umsdos_dirent *entry)
 402 {
 403         int ret;
 404         umsdos_patch_inode (dir,NULL,0);
 405         ret = umsdos_real_lookup (dir,"..",2,result);
 406         PRINTK (("result %d %x ",ret,*result));
 407         if (ret == 0){
 408                 struct inode *adir = *result;
 409                 ret = umsdos_inode2entry (adir,dir,entry);
 410         }
 411         PRINTK (("\n"));
 412         return ret;
 413 }
 414 /*
 415         Build the path name of an inode (relative to the file system.
 416         This function is need to set (pseudo) hard link.
 417 
 418         It uses the same strategy as the standard getcwd().
 419 */
 420 int umsdos_locate_path (
     /* [previous][next][first][last][top][bottom][index][help] */
 421         struct inode *inode,
 422         char *path)
 423 {
 424         int ret = 0;
 425         struct inode *dir = inode;
 426         char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
 427         if (bpath == NULL){
 428                 ret = -ENOMEM;
 429         }else{
 430                 struct umsdos_dirent entry;
 431                 char *ptbpath = bpath+PATH_MAX-1;
 432                 *ptbpath = '\0';
 433                 PRINTK (("locate_path mode %x ",inode->i_mode));
 434                 if (!S_ISDIR(inode->i_mode)){
 435                         ret = umsdos_get_dirowner (inode,&dir);
 436                         PRINTK (("locate_path ret %d ",ret));
 437                         if (ret == 0){
 438                                 ret = umsdos_inode2entry (dir,inode,&entry);
 439                                 if (ret == 0){
 440                                         ptbpath -= entry.name_len;
 441                                         memcpy (ptbpath,entry.name,entry.name_len);
 442                                         PRINTK (("ptbpath :%s: ",ptbpath));
 443                                 }
 444                         }
 445                 }else{
 446                         dir->i_count++;
 447                 }
 448                 if (ret == 0){
 449                         while (dir != dir->i_sb->s_mounted){
 450                                 struct inode *adir;
 451                                 ret = umsdos_locate_ancestor (dir,&adir,&entry);
 452                                 iput (dir);
 453                                 dir = NULL;
 454                                 PRINTK (("ancestor %d ",ret));
 455                                 if (ret == 0){
 456                                         *--ptbpath = '/';
 457                                         ptbpath -= entry.name_len;
 458                                         memcpy (ptbpath,entry.name,entry.name_len);
 459                                         dir = adir;
 460                                         PRINTK (("ptbpath :%s: ",ptbpath));
 461                                 }else{
 462                                         break;
 463                                 }
 464                         }
 465                 }
 466                 strcpy (path,ptbpath);
 467                 kfree (bpath);
 468         }
 469         PRINTK (("\n"));
 470         iput (dir);
 471         return ret;
 472 }
 473 
 474 /*
 475         Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
 476 */
 477 int umsdos_is_pseudodos (
     /* [previous][next][first][last][top][bottom][index][help] */
 478         struct inode *dir,
 479         const char *name,
 480         int len)
 481 {
 482         /* #Specification: pseudo root / DOS hard coded
 483                 The pseudo sub-directory DOS in the pseudo root is hard coded.
 484                 The name is DOS. This is done this way to help standardised
 485                 the umsdos layout. The idea is that from now on /DOS is
 486                 a reserved path and nobody will think of using such a path
 487                 for a package.
 488         */
 489         return dir == pseudo_root
 490                 && len == 3
 491                 && name[0] == 'D' && name[1] == 'O' && name[2] == 'S';
 492 }
 493 /*
 494         Check if a file exist in the current directory.
 495         Return 0 if ok, negative error code if not (ex: -ENOENT).
 496 */
 497 static int umsdos_lookup_x (
     /* [previous][next][first][last][top][bottom][index][help] */
 498         struct inode *dir,
 499         const char *name,
 500         int len,
 501         struct inode **result,  /* Will hold inode of the file, if successful */
 502         int nopseudo)                   /* Don't care about pseudo root mode */
 503 {
 504         int ret = -ENOENT;
 505         *result = NULL;
 506         umsdos_startlookup(dir);        
 507         if (len == 1 && name[0] == '.'){
 508                 *result = dir;
 509                 dir->i_count++;
 510                 ret = 0;
 511         }else if (len == 2 && name[0] == '.' && name[1] == '.'){
 512                 if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){
 513                         /* #Specification: pseudo root / .. in real root
 514                                 Whenever a lookup is those in the real root for
 515                                 the directory .., and pseudo root is active, the
 516                                 pseudo root is returned.
 517                         */
 518                         ret = 0;
 519                         *result = pseudo_root;
 520                         pseudo_root->i_count++;
 521                 }else{
 522                         /* #Specification: locating .. / strategy
 523                                 We use the msdos filesystem to locate the parent directory.
 524                                 But it is more complicated than that.
 525                                 
 526                                 We have to step back even further to
 527                                 get the parent of the parent, so we can get the EMD
 528                                 of the parent of the parent. Using the EMD file, we can
 529                                 locate all the info on the parent, such a permissions
 530                                 and owner.
 531                         */
 532                         ret = umsdos_real_lookup (dir,"..",2,result);
 533                         PRINTK (("ancestor ret %d dir %p *result %p ",ret,dir,*result));
 534                         if (ret == 0
 535                                 && *result != dir->i_sb->s_mounted
 536                                 && *result != pseudo_root){
 537                                 struct inode *aadir;
 538                                 struct umsdos_dirent entry;
 539                                 ret = umsdos_locate_ancestor (*result,&aadir,&entry);
 540                                 iput (aadir);
 541                         }
 542                 }
 543         }else if (umsdos_is_pseudodos(dir,name,len)){
 544                 /* #Specification: pseudo root / lookup(DOS)
 545                         A lookup of DOS in the pseudo root will always succeed
 546                         and return the inode of the real root.
 547                 */
 548                 *result = dir->i_sb->s_mounted;
 549                 (*result)->i_count++;
 550                 ret = 0;
 551         }else{
 552                 struct umsdos_info info;
 553                 ret = umsdos_parse (name,len,&info);
 554                 if (ret == 0) ret = umsdos_findentry (dir,&info,0);
 555                 PRINTK (("lookup %s pos %d ret %d len %d ",info.fake.fname,info.f_pos,ret
 556                         ,info.fake.len));
 557                 if (ret == 0){
 558                         /* #Specification: umsdos / lookup
 559                                 A lookup for a file is done in two step. First, we locate
 560                                 the file in the EMD file. If not present, we return
 561                                 an error code (-ENOENT). If it is there, we repeat the
 562                                 operation on the msdos file system. If this fails, it means
 563                                 that the file system is not in sync with the emd file.
 564                                 We silently remove this entry from the emd file,
 565                                 and return ENOENT.
 566                         */
 567                         struct inode *inode;
 568                         ret = umsdos_real_lookup (dir,info.fake.fname,info.fake.len,result);
 569                         inode = *result;
 570                         if (inode == NULL){
 571                                 printk ("UMSDOS: Erase entry %s, out of sync with MsDOS\n"
 572                                         ,info.fake.fname);
 573                                 umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
 574                         }else{
 575                                 umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
 576                                 PRINTK (("lookup ino %d flags %d\n",inode->i_ino
 577                                         ,info.entry.flags));
 578                                 if (info.entry.flags & UMSDOS_HLINK){
 579                                         ret = umsdos_hlink2inode (inode,result);
 580                                 }
 581                                 if (*result == pseudo_root && !nopseudo){
 582                                         /* #Specification: pseudo root / dir lookup
 583                                                 For the same reason as readdir, a lookup in /DOS for
 584                                                 the pseudo root directory (linux) will fail.
 585                                         */
 586                                         /*
 587                                                 This has to be allowed for resolving hard link
 588                                                 which are recorded independently of the pseudo-root
 589                                                 mode.
 590                                         */
 591                                         iput (pseudo_root);
 592                                         *result = NULL;
 593                                         ret = -ENOENT;
 594                                 }
 595                         }
 596                 }
 597         }
 598         umsdos_endlookup(dir);  
 599         iput (dir);
 600         return ret;
 601 }
 602 /*
 603         Check if a file exist in the current directory.
 604         Return 0 if ok, negative error code if not (ex: -ENOENT).
 605 */
 606 int UMSDOS_lookup (
     /* [previous][next][first][last][top][bottom][index][help] */
 607         struct inode *dir,
 608         const char *name,
 609         int len,
 610         struct inode **result)  /* Will hold inode of the file, if successful */
 611 {
 612         return umsdos_lookup_x(dir,name,len,result,0);
 613 }
 614 /*
 615         Locate the inode pointed by a (pseudo) hard link
 616         Return 0 if ok, a negative error code if not.
 617 */
 618 int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
     /* [previous][next][first][last][top][bottom][index][help] */
 619 {
 620         int ret = -EIO;
 621         char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
 622         *result = NULL;
 623         if (path == NULL){
 624                 ret = -ENOMEM;
 625                 iput (hlink);
 626         }else{
 627                 struct file filp;
 628                 filp.f_reada = 1;
 629                 filp.f_pos = 0;
 630                 PRINTK (("hlink2inode "));
 631                 if (umsdos_file_read_kmem (hlink,&filp,path,hlink->i_size)
 632                         ==hlink->i_size){
 633                         struct inode *dir;
 634                         char *pt = path;
 635                         dir = hlink->i_sb->s_mounted;
 636                         path[hlink->i_size] = '\0';
 637                         iput (hlink);
 638                         dir->i_count++;
 639                         while (1){
 640                                 char *start = pt;
 641                                 int len;
 642                                 while (*pt != '\0' && *pt != '/') pt++;
 643                                 len = (int)(pt - start);
 644                                 if (*pt == '/') *pt++ = '\0';
 645                                 if (dir->u.umsdos_i.i_emd_dir == 0){
 646                                         /* This is a DOS directory */
 647                                         ret = msdos_lookup(dir,start,len,result);
 648                                 }else{
 649                                         ret = umsdos_lookup_x(dir,start,len,result,1);
 650                                 }
 651                                 PRINTK (("h2n lookup :%s: -> %d ",start,ret));
 652                                 if (ret == 0 && *pt != '\0'){
 653                                         dir = *result;
 654                                 }else{
 655                                         break;
 656                                 }
 657                         }
 658                 }else{
 659                         iput (hlink);
 660                 }
 661                 PRINTK (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result));
 662                 kfree (path);
 663         }
 664         return ret;
 665 }
 666 
 667 static struct file_operations umsdos_dir_operations = {
 668         NULL,                           /* lseek - default */
 669         UMSDOS_dir_read,        /* read */
 670         NULL,                           /* write - bad */
 671         UMSDOS_readdir,         /* readdir */
 672         NULL,                           /* select - default */
 673         UMSDOS_ioctl_dir,       /* ioctl - default */
 674         NULL,                           /* mmap */
 675         NULL,                           /* no special open code */
 676         NULL,                           /* no special release code */
 677         NULL                            /* fsync */
 678 };
 679 
 680 struct inode_operations umsdos_dir_inode_operations = {
 681         &umsdos_dir_operations, /* default directory file-ops */
 682         UMSDOS_create,          /* create */
 683         UMSDOS_lookup,          /* lookup */
 684         UMSDOS_link,            /* link */
 685         UMSDOS_unlink,          /* unlink */
 686         UMSDOS_symlink,         /* symlink */
 687         UMSDOS_mkdir,           /* mkdir */
 688         UMSDOS_rmdir,           /* rmdir */
 689         UMSDOS_mknod,           /* mknod */
 690         UMSDOS_rename,          /* rename */
 691         NULL,                   /* readlink */
 692         NULL,                   /* follow_link */
 693         NULL,                   /* bmap */
 694         NULL,                   /* truncate */
 695         NULL                    /* permission */
 696 };
 697 
 698 
 699 
 700 
 701 
 702 
 703 
 704 
 705 
 706 

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