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

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