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,  /* Optionnal 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 automaticly.
 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_pos = 0;
 354                         while (1){
 355                                 struct dirent dirent;
 356                                 if (umsdos_readdir_kmem (dir,&filp,&dirent,1) <= 0){
 357                                         printk ("UMSDOS: can't locate inode %ld in DOS directory???\n"
 358                                                 ,inode->i_ino);
 359                                 }else if (dirent.d_ino == inode->i_ino){
 360                                         ret = 0;
 361                                         memcpy (entry->name,dirent.d_name,dirent.d_reclen);
 362                                         entry->name[dirent.d_reclen] = '\0';
 363                                         entry->name_len = dirent.d_reclen;
 364                                         inode->u.umsdos_i.i_dir_owner = dir->i_ino;
 365                                         inode->u.umsdos_i.i_emd_owner = 0;
 366                                         umsdos_setup_dir_inode(inode);
 367                                         break;
 368                                 }
 369                         }
 370                 }else{
 371                         /* skip . and .. see umsdos_readdir_x() */
 372                         struct file filp;
 373                         filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
 374                         while (1){
 375                                 struct dirent dirent;
 376                                 off_t f_pos;
 377                                 if (umsdos_readdir_x(dir,&filp,&dirent
 378                                         ,0,1,entry,0,&f_pos) <= 0){
 379                                         printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
 380                                                 ,inode->i_ino);
 381                                         break;
 382                                 }else if (dirent.d_ino == inode->i_ino){
 383                                         ret = 0;
 384                                         umsdos_lookup_patch (dir,inode,entry,f_pos);
 385                                         break;
 386                                 }
 387                         }
 388                 }
 389         }
 390         return ret;
 391 }
 392 /*
 393         Locate the parent of a directory and the info on that directory
 394         Return 0 or a negative error code.
 395 */
 396 static int umsdos_locate_ancestor (
     /* [previous][next][first][last][top][bottom][index][help] */
 397         struct inode *dir,
 398         struct inode **result,
 399         struct umsdos_dirent *entry)
 400 {
 401         int ret;
 402         umsdos_patch_inode (dir,NULL,0);
 403         ret = umsdos_real_lookup (dir,"..",2,result);
 404         PRINTK (("result %d %x ",ret,*result));
 405         if (ret == 0){
 406                 struct inode *adir = *result;
 407                 ret = umsdos_inode2entry (adir,dir,entry);
 408         }
 409         PRINTK (("\n"));
 410         return ret;
 411 }
 412 /*
 413         Build the path name of an inode (relative to the file system.
 414         This function is need to set (pseudo) hard link.
 415 
 416         It uses the same strategy as the standard getcwd().
 417 */
 418 int umsdos_locate_path (
     /* [previous][next][first][last][top][bottom][index][help] */
 419         struct inode *inode,
 420         char *path)
 421 {
 422         int ret = 0;
 423         struct inode *dir = inode;
 424         char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
 425         if (bpath == NULL){
 426                 ret = -ENOMEM;
 427         }else{
 428                 struct umsdos_dirent entry;
 429                 char *ptbpath = bpath+PATH_MAX-1;
 430                 *ptbpath = '\0';
 431                 PRINTK (("locate_path mode %x ",inode->i_mode));
 432                 if (!S_ISDIR(inode->i_mode)){
 433                         ret = umsdos_get_dirowner (inode,&dir);
 434                         PRINTK (("locate_path ret %d ",ret));
 435                         if (ret == 0){
 436                                 ret = umsdos_inode2entry (dir,inode,&entry);
 437                                 if (ret == 0){
 438                                         ptbpath -= entry.name_len;
 439                                         memcpy (ptbpath,entry.name,entry.name_len);
 440                                         PRINTK (("ptbpath :%s: ",ptbpath));
 441                                 }
 442                         }
 443                 }else{
 444                         dir->i_count++;
 445                 }
 446                 if (ret == 0){
 447                         while (dir != dir->i_sb->s_mounted){
 448                                 struct inode *adir;
 449                                 ret = umsdos_locate_ancestor (dir,&adir,&entry);
 450                                 iput (dir);
 451                                 dir = NULL;
 452                                 PRINTK (("ancestor %d ",ret));
 453                                 if (ret == 0){
 454                                         *--ptbpath = '/';
 455                                         ptbpath -= entry.name_len;
 456                                         memcpy (ptbpath,entry.name,entry.name_len);
 457                                         dir = adir;
 458                                         PRINTK (("ptbpath :%s: ",ptbpath));
 459                                 }else{
 460                                         break;
 461                                 }
 462                         }
 463                 }
 464                 strcpy (path,ptbpath);
 465                 kfree (bpath);
 466         }
 467         PRINTK (("\n"));
 468         iput (dir);
 469         return ret;
 470 }
 471 
 472 /*
 473         Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
 474 */
 475 int umsdos_is_pseudodos (
     /* [previous][next][first][last][top][bottom][index][help] */
 476         struct inode *dir,
 477         const char *name,
 478         int len)
 479 {
 480         /* #Specification: pseudo root / DOS hard coded
 481                 The pseudo sub-directory DOS in the pseudo root is hard coded.
 482                 The name is DOS. This is done this way to help standardised
 483                 the umsdos layout. The idea is that from now on /DOS is
 484                 a reserved path and nobody will think of using such a path
 485                 for a package.
 486         */
 487         return dir == pseudo_root
 488                 && len == 3
 489                 && name[0] == 'D' && name[1] == 'O' && name[2] == 'S';
 490 }
 491 /*
 492         Check if a file exist in the current directory.
 493         Return 0 if ok, negative error code if not (ex: -ENOENT).
 494 */
 495 static int umsdos_lookup_x (
     /* [previous][next][first][last][top][bottom][index][help] */
 496         struct inode *dir,
 497         const char *name,
 498         int len,
 499         struct inode **result,  /* Will hold inode of the file, if successful */
 500         int nopseudo)                   /* Don't care about pseudo root mode */
 501 {
 502         int ret = -ENOENT;
 503         *result = NULL;
 504         umsdos_startlookup(dir);        
 505         if (len == 1 && name[0] == '.'){
 506                 *result = dir;
 507                 dir->i_count++;
 508                 ret = 0;
 509         }else if (len == 2 && name[0] == '.' && name[1] == '.'){
 510                 if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){
 511                         /* #Specification: pseudo root / .. in real root
 512                                 Whenever a lookup is those in the real root for
 513                                 the directory .., and pseudo root is active, the
 514                                 pseudo root is returned.
 515                         */
 516                         ret = 0;
 517                         *result = pseudo_root;
 518                         pseudo_root->i_count++;
 519                 }else{
 520                         /* #Specification: locating .. / strategy
 521                                 We use the msdos filesystem to locate the parent directory.
 522                                 But it is more complicated than that.
 523                                 
 524                                 We have to step back even further to
 525                                 get the parent of the parent, so we can get the EMD
 526                                 of the parent of the parent. Using the EMD file, we can
 527                                 locate all the info on the parent, such a permissions
 528                                 and owner.
 529                         */
 530                         ret = umsdos_real_lookup (dir,"..",2,result);
 531                         PRINTK (("ancestor ret %d dir %p *result %p ",ret,dir,*result));
 532                         if (ret == 0
 533                                 && *result != dir->i_sb->s_mounted
 534                                 && *result != pseudo_root){
 535                                 struct inode *aadir;
 536                                 struct umsdos_dirent entry;
 537                                 ret = umsdos_locate_ancestor (*result,&aadir,&entry);
 538                                 iput (aadir);
 539                         }
 540                 }
 541         }else if (umsdos_is_pseudodos(dir,name,len)){
 542                 /* #Specification: pseudo root / lookup(DOS)
 543                         A lookup of DOS in the pseudo root will always succeed
 544                         and return the inode of the real root.
 545                 */
 546                 *result = dir->i_sb->s_mounted;
 547                 (*result)->i_count++;
 548                 ret = 0;
 549         }else{
 550                 struct umsdos_info info;
 551                 ret = umsdos_parse (name,len,&info);
 552                 if (ret == 0) ret = umsdos_findentry (dir,&info,0);
 553                 PRINTK (("lookup %s pos %d ret %d len %d ",info.fake.fname,info.f_pos,ret
 554                         ,info.fake.len));
 555                 if (ret == 0){
 556                         /* #Specification: umsdos / lookup
 557                                 A lookup for a file is done in two step. First, we locate
 558                                 the file in the EMD file. If not present, we return
 559                                 an error code (-ENOENT). If it is there, we repeat the
 560                                 operation on the msdos file system. If this fails, it means
 561                                 that the file system is not in sync with the emd file.
 562                                 We silently remove this entry from the emd file,
 563                                 and return ENOENT.
 564                         */
 565                         struct inode *inode;
 566                         ret = umsdos_real_lookup (dir,info.fake.fname,info.fake.len,result);
 567                         inode = *result;
 568                         if (inode == NULL){
 569                                 printk ("UMSDOS: Erase entry %s, out of sync with MsDOS\n"
 570                                         ,info.fake.fname);
 571                                 umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
 572                         }else{
 573                                 umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
 574                                 PRINTK (("lookup ino %d flags %d\n",inode->i_ino
 575                                         ,info.entry.flags));
 576                                 if (info.entry.flags & UMSDOS_HLINK){
 577                                         ret = umsdos_hlink2inode (inode,result);
 578                                 }
 579                                 if (*result == pseudo_root && !nopseudo){
 580                                         /* #Specification: pseudo root / dir lookup
 581                                                 For the same reason as readdir, a lookup in /DOS for
 582                                                 the pseudo root directory (linux) will fail.
 583                                         */
 584                                         /*
 585                                                 This has to be allowed for resolving hard link
 586                                                 which are recorded independantly of the pseudo-root
 587                                                 mode.
 588                                         */
 589                                         iput (pseudo_root);
 590                                         *result = NULL;
 591                                         ret = -ENOENT;
 592                                 }
 593                         }
 594                 }
 595         }
 596         umsdos_endlookup(dir);  
 597         iput (dir);
 598         return ret;
 599 }
 600 /*
 601         Check if a file exist in the current directory.
 602         Return 0 if ok, negative error code if not (ex: -ENOENT).
 603 */
 604 int UMSDOS_lookup (
     /* [previous][next][first][last][top][bottom][index][help] */
 605         struct inode *dir,
 606         const char *name,
 607         int len,
 608         struct inode **result)  /* Will hold inode of the file, if successful */
 609 {
 610         return umsdos_lookup_x(dir,name,len,result,0);
 611 }
 612 /*
 613         Locate the inode pointed by a (pseudo) hard link
 614         Return 0 if ok, a negative error code if not.
 615 */
 616 int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
     /* [previous][next][first][last][top][bottom][index][help] */
 617 {
 618         int ret = -EIO;
 619         char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
 620         *result = NULL;
 621         if (path == NULL){
 622                 ret = -ENOMEM;
 623                 iput (hlink);
 624         }else{
 625                 struct file filp;
 626                 filp.f_pos = 0;
 627                 PRINTK (("hlink2inode "));
 628                 if (umsdos_file_read_kmem (hlink,&filp,path,hlink->i_size)
 629                         ==hlink->i_size){
 630                         struct inode *dir;
 631                         char *pt = path;
 632                         dir = hlink->i_sb->s_mounted;
 633                         path[hlink->i_size] = '\0';
 634                         iput (hlink);
 635                         dir->i_count++;
 636                         while (1){
 637                                 char *start = pt;
 638                                 int len;
 639                                 while (*pt != '\0' && *pt != '/') pt++;
 640                                 len = (int)(pt - start);
 641                                 if (*pt == '/') *pt++ = '\0';
 642                                 if (dir->u.umsdos_i.i_emd_dir == 0){
 643                                         /* This is a DOS directory */
 644                                         ret = msdos_lookup(dir,start,len,result);
 645                                 }else{
 646                                         ret = umsdos_lookup_x(dir,start,len,result,1);
 647                                 }
 648                                 PRINTK (("h2n lookup :%s: -> %d ",start,ret));
 649                                 if (ret == 0 && *pt != '\0'){
 650                                         dir = *result;
 651                                 }else{
 652                                         break;
 653                                 }
 654                         }
 655                 }else{
 656                         iput (hlink);
 657                 }
 658                 PRINTK (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result));
 659                 kfree (path);
 660         }
 661         return ret;
 662 }
 663 
 664 static struct file_operations umsdos_dir_operations = {
 665         NULL,                           /* lseek - default */
 666         UMSDOS_dir_read,        /* read */
 667         NULL,                           /* write - bad */
 668         UMSDOS_readdir,         /* readdir */
 669         NULL,                           /* select - default */
 670         UMSDOS_ioctl_dir,       /* ioctl - default */
 671         NULL,                           /* mmap */
 672         NULL,                           /* no special open code */
 673         NULL,                           /* no special release code */
 674         NULL                            /* fsync */
 675 };
 676 
 677 struct inode_operations umsdos_dir_inode_operations = {
 678         &umsdos_dir_operations, /* default directory file-ops */
 679         UMSDOS_create,          /* create */
 680         UMSDOS_lookup,          /* lookup */
 681         UMSDOS_link,            /* link */
 682         UMSDOS_unlink,          /* unlink */
 683         UMSDOS_symlink,         /* symlink */
 684         UMSDOS_mkdir,           /* mkdir */
 685         UMSDOS_rmdir,           /* rmdir */
 686         UMSDOS_mknod,           /* mknod */
 687         UMSDOS_rename,          /* rename */
 688         NULL,                   /* readlink */
 689         NULL,                   /* follow_link */
 690         NULL,                   /* bmap */
 691         NULL,                   /* truncate */
 692         NULL                    /* permission */
 693 };
 694 
 695 
 696 
 697 
 698 
 699 
 700 
 701 
 702 
 703 

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