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

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