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

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