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

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