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

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