root/fs/affs/namei.c

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

DEFINITIONS

This source file includes following definitions.
  1. affs_toupper
  2. affs_intl_toupper
  3. affs_match
  4. affs_hash_name
  5. affs_find_entry
  6. affs_lookup
  7. affs_unlink
  8. affs_create
  9. affs_mkdir
  10. empty_dir
  11. affs_rmdir
  12. affs_symlink
  13. affs_link
  14. subdir
  15. affs_rename
  16. affs_fixup

   1 /*
   2  *  linux/fs/affs/namei.c
   3  *
   4  *  (c) 1996  Hans-Joachim Widmaier - Heavily hacked up.
   5  *
   6  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
   7  *
   8  *  (C) 1991  Linus Torvalds - minix filesystem
   9  */
  10 
  11 #include <linux/sched.h>
  12 #include <linux/affs_fs.h>
  13 #include <linux/amigaffs.h>
  14 #include <linux/kernel.h>
  15 #include <linux/string.h>
  16 #include <linux/stat.h>
  17 #include <linux/fcntl.h>
  18 #include <linux/locks.h>
  19 #include <asm/segment.h>
  20 
  21 #include <linux/errno.h>
  22 
  23 /* Simple toupper() for DOS\1 */
  24 
  25 static inline unsigned int
  26 affs_toupper(unsigned int ch)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28         return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
  29 }
  30 
  31 /* International toupper() for DOS\3 */
  32 
  33 static inline unsigned int
  34 affs_intl_toupper(unsigned int ch)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36         return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
  37                 && ch <= 0xFE && ch != 0xF7) ?
  38                 ch - ('a' - 'A') : ch;
  39 }
  40 
  41 /*
  42  * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
  43  */
  44 
  45 static int
  46 affs_match(const char *name, int len, const char *compare, int dlen, int intl)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48         if (!compare)
  49                 return 0;
  50 
  51         if (len > 30)
  52                 len = 30;
  53         if (dlen > 30)
  54                 dlen = 30;
  55 
  56         /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
  57         if (!len && dlen == 1 && compare[0] == '.')
  58                 return 1;
  59         if (dlen != len)
  60                 return 0;
  61         if (intl) {
  62                 while (dlen--) {
  63                         if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF))
  64                                 return 0;
  65                         name++;
  66                         compare++;
  67                 }
  68         } else {
  69                 while (dlen--) {
  70                         if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF))
  71                                 return 0;
  72                         name++;
  73                         compare++;
  74                 }
  75         }
  76         return 1;
  77 }
  78 
  79 int
  80 affs_hash_name(const char *name, int len, int intl, int hashsize)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82         unsigned int i, x;
  83 
  84         if (len > 30)
  85                 len = 30;
  86 
  87         x = len;
  88         for (i = 0; i < len; i++)
  89                 if (intl)
  90                         x = (x * 13 + affs_intl_toupper(name[i] & 0xFF)) & 0x7ff;
  91                 else
  92                         x = (x * 13 + affs_toupper(name[i] & 0xFF)) & 0x7ff;
  93 
  94         return x % hashsize;
  95 }
  96 
  97 static struct buffer_head *
  98 affs_find_entry(struct inode *dir, const char *name, int namelen,
     /* [previous][next][first][last][top][bottom][index][help] */
  99                 unsigned long *ino)
 100 {
 101         struct buffer_head *bh;
 102         int      intl;
 103         ULONG    key;
 104 
 105         pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
 106 
 107         intl = AFFS_I2FSTYPE(dir);
 108         bh   = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
 109         if (!bh)
 110                 return NULL;
 111 
 112         if (affs_match(name,namelen,".",1,intl)) {
 113                 *ino = dir->i_ino;
 114                 return bh;
 115         }
 116         if (affs_match(name,namelen,"..",2,intl)) {
 117                 *ino = affs_parent_ino(dir);
 118                 return bh;
 119         }
 120 
 121         key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));
 122 
 123         for (;;) {
 124                 char *cname;
 125                 int cnamelen;
 126 
 127                 affs_brelse(bh);
 128                 if (key == 0) {
 129                         bh = NULL;
 130                         break;
 131                 }
 132                 bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
 133                 if (!bh)
 134                         break;
 135                 cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
 136                 if (affs_match(name,namelen,cname,cnamelen,intl))
 137                         break;
 138                 key = htonl(FILE_END(bh->b_data,dir)->hash_chain);
 139         }
 140         pr_debug("%lu\n",key);
 141         *ino = key;
 142         return bh;
 143 }
 144 
 145 int
 146 affs_lookup(struct inode *dir, const char *name, int len, struct inode **result)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148         int res;
 149         unsigned long ino;
 150         struct buffer_head *bh;
 151 
 152         pr_debug("AFFS: lookup(%.*s)\n",len,name);
 153 
 154         *result = NULL;
 155         if (!dir)
 156                 return -ENOENT;
 157 
 158         res = -ENOENT;
 159         if (S_ISDIR(dir->i_mode)) {
 160                 if ((bh = affs_find_entry(dir,name,len,&ino))) {
 161                         if (FILE_END(bh->b_data,dir)->original)
 162                                 ino = htonl(FILE_END(bh->b_data,dir)->original);
 163                         affs_brelse(bh);
 164                         if ((*result = iget(dir->i_sb,ino))) 
 165                                 res = 0;
 166                         else
 167                                 res = -EACCES;
 168                 }
 169         }
 170         iput(dir);
 171         return res;
 172 }
 173 
 174 int
 175 affs_unlink(struct inode *dir, const char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 176 {
 177         int                      retval;
 178         struct buffer_head      *bh;
 179         unsigned long            ino;
 180         struct inode            *inode;
 181 
 182         pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,len,name);
 183 
 184         bh      = NULL;
 185         inode   = NULL;
 186         retval  = -ENOENT;
 187         if (!(bh = affs_find_entry(dir,name,len,&ino))) {
 188                 goto unlink_done;
 189         }
 190         if (!(inode = iget(dir->i_sb,ino))) {
 191                 goto unlink_done;
 192         }
 193         if (S_ISDIR(inode->i_mode)) {
 194                 retval = -EPERM;
 195                 goto unlink_done;
 196         }
 197 
 198         if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
 199                                          AFFS_I2HSIZE(dir)) + 6,ino,
 200                                          FILE_END(bh->b_data,dir)->hash_chain)))
 201                 goto unlink_done;
 202 
 203         if ((retval = affs_fixup(bh,inode)))
 204                 goto unlink_done;
 205 
 206         inode->i_nlink=0;
 207         inode->i_dirt=1;
 208         inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 209         dir->i_version = ++event;
 210         dir->i_dirt=1;
 211 unlink_done:
 212         affs_brelse(bh);
 213         iput(inode);
 214         iput(dir);
 215         return retval;
 216 }
 217 
 218 int
 219 affs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result)
     /* [previous][next][first][last][top][bottom][index][help] */
 220 {
 221         struct inode    *inode;
 222         int              error;
 223         
 224         pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
 225 
 226 
 227         *result = NULL;
 228 
 229         if (!dir || !dir->i_sb) {
 230                 iput(dir);
 231                 return -EINVAL;
 232         }
 233         inode = affs_new_inode(dir);
 234         if (!inode) {
 235                 iput (dir);
 236                 return -ENOSPC;
 237         }
 238         inode->i_op   = &affs_file_inode_operations;
 239         inode->i_mode = mode;
 240         error         = affs_add_entry(dir,NULL,inode,name,len,ST_FILE);
 241         if (error) {
 242                 iput(dir);
 243                 inode->i_nlink = 0;
 244                 inode->i_dirt  = 1;
 245                 iput(inode);
 246                 return -ENOSPC;
 247         }
 248         inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
 249 
 250         iput(dir);
 251         *result = inode;
 252 
 253         return 0;
 254 }
 255 
 256 int
 257 affs_mkdir(struct inode *dir, const char *name, int len, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 258 {
 259         struct inode            *inode;
 260         struct buffer_head      *bh;
 261         unsigned long            i;
 262         int                      error;
 263         
 264         pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
 265 
 266         if (!dir || !dir->i_sb) {
 267                 iput(dir);
 268                 return -EINVAL;
 269         }
 270         bh = affs_find_entry(dir,name,len,&i);
 271         if (bh) {
 272                 affs_brelse(bh);
 273                 iput(dir);
 274                 return -EEXIST;
 275         }
 276         inode = affs_new_inode(dir);
 277         if (!inode) {
 278                 iput (dir);
 279                 return -ENOSPC;
 280         }
 281         inode->i_op = &affs_dir_inode_operations;
 282         error       = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR);
 283         if (error) {
 284                 iput(dir);
 285                 inode->i_nlink = 0;
 286                 inode->i_dirt  = 1;
 287                 iput(inode);
 288                 return error;
 289         }
 290         inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
 291         inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
 292 
 293         iput(dir);
 294         iput(inode);
 295 
 296         return 0;
 297 }
 298 
 299 static int
 300 empty_dir(struct buffer_head *bh, int hashsize)
     /* [previous][next][first][last][top][bottom][index][help] */
 301 {
 302         while (--hashsize >= 0) {
 303                 if (((struct dir_front *)bh->b_data)->hashtable[hashsize])
 304                         return 0;
 305         }
 306         return 1;
 307 }
 308 
 309 int
 310 affs_rmdir(struct inode *dir, const char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 311 {
 312         int                      retval;
 313         unsigned long            ino;
 314         struct inode            *inode;
 315         struct buffer_head      *bh;
 316 
 317         pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name);
 318 
 319         inode  = NULL;
 320         retval = -ENOENT;
 321         if (!(bh = affs_find_entry(dir,name,len,&ino))) {
 322                 goto rmdir_done;
 323         }
 324         if (!(inode = iget(dir->i_sb,ino))) {
 325                 goto rmdir_done;
 326         }
 327         retval = -EPERM;
 328         if (!fsuser() && current->fsuid != inode->i_uid &&
 329             current->fsuid != dir->i_uid)
 330                 goto rmdir_done;
 331         if (inode->i_dev != dir->i_dev)
 332                 goto rmdir_done;
 333         if (inode == dir)       /* we may not delete ".", but "../dir" is ok */
 334                 goto rmdir_done;
 335         if (!S_ISDIR(inode->i_mode)) {
 336                 retval = -ENOTDIR;
 337                 goto rmdir_done;
 338         }
 339         if (!empty_dir(bh,AFFS_I2HSIZE(inode))) {
 340                 retval = -ENOTEMPTY;
 341                 goto rmdir_done;
 342         }
 343         if (inode->i_count > 1) {
 344                 retval = -EBUSY;
 345                 goto rmdir_done;
 346         }
 347         if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
 348                                          AFFS_I2HSIZE(dir)) + 6,ino,
 349                                          FILE_END(bh->b_data,dir)->hash_chain)))
 350                 goto rmdir_done;
 351 
 352         if ((retval = affs_fixup(bh,inode)))
 353                 goto rmdir_done;
 354 
 355         inode->i_nlink=0;
 356         inode->i_dirt=1;
 357         inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 358         dir->i_version = ++event;
 359         dir->i_dirt=1;
 360 rmdir_done:
 361         iput(dir);
 362         iput(inode);
 363         affs_brelse(bh);
 364         return retval;
 365 }
 366 
 367 int
 368 affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
     /* [previous][next][first][last][top][bottom][index][help] */
 369 {
 370         struct buffer_head      *bh;
 371         struct inode            *inode;
 372         char                    *p;
 373         unsigned long            tmp;
 374         int                      i, maxlen;
 375         char                     c, lc;
 376 
 377         pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
 378         printk("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
 379         
 380         maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
 381         inode  = affs_new_inode(dir);
 382         if (!inode) {
 383                 iput(dir);
 384                 return -ENOSPC;
 385         }
 386         inode->i_op   = &affs_symlink_inode_operations;
 387         inode->i_mode = S_IFLNK | 0777;
 388         inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
 389         bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
 390         if (!bh) {
 391                 iput(dir);
 392                 inode->i_nlink = 0;
 393                 inode->i_dirt  = 1;
 394                 iput(inode);
 395                 return -EIO;
 396         }
 397         i  = 0;
 398         p  = ((struct slink_front *)bh->b_data)->symname;
 399         lc = '/';
 400         if (*symname == '/') {
 401                 while (*symname == '/')
 402                         symname++;
 403                 while (inode->i_sb->u.affs_sb.s_volume[i])      /* Cannot overflow */
 404                         *p++ = inode->i_sb->u.affs_sb.s_volume[i++];
 405         }
 406         while (i < maxlen && (c = *symname++)) {
 407                 if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
 408                         *p++ = '/';
 409                         i++;
 410                         symname += 2;
 411                         lc = '/';
 412                 } else if (c == '.' && lc == '/' && *symname == '/') {
 413                         symname++;
 414                         lc = '/';
 415                 } else {
 416                         *p++ = c;
 417                         lc   = c;
 418                         i++;
 419                 }
 420                 if (lc == '/')
 421                         while (*symname == '/')
 422                                 symname++;
 423         }
 424         *p = 0;
 425         mark_buffer_dirty(bh,1);
 426         affs_brelse(bh);
 427         inode->i_dirt = 1;
 428         bh = affs_find_entry(dir,name,len,&tmp);
 429         if (bh) {
 430                 inode->i_nlink = 0;
 431                 iput(inode);
 432                 affs_brelse(bh);
 433                 iput(dir);
 434                 return -EEXIST;
 435         }
 436         i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK);
 437         if (i) {
 438                 inode->i_nlink = 0;
 439                 inode->i_dirt  = 1;
 440                 iput(inode);
 441                 affs_brelse(bh);
 442                 iput(dir);
 443                 return i;
 444         }
 445         iput(dir);
 446         iput(inode);
 447         
 448         return 0;
 449 }
 450 
 451 int
 452 affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 453 {
 454         struct inode            *inode;
 455         struct buffer_head      *bh;
 456         unsigned long            i;
 457         int                      error;
 458         
 459         pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,len,name);
 460 
 461         bh = affs_find_entry(dir,name,len,&i);
 462         if (bh) {
 463                 affs_brelse(bh);
 464                 iput(oldinode);
 465                 iput(dir);
 466                 return -EEXIST;
 467         }
 468         if (oldinode->u.affs_i.i_hlink) {
 469                 i = oldinode->u.affs_i.i_original;
 470                 iput(oldinode);
 471                 oldinode = iget(dir->i_sb,i);
 472                 if (!oldinode) {
 473                         printk("AFFS: link(): original does not exist.\n");
 474                         iput(dir);
 475                         return -ENOENT;
 476                 }
 477         }
 478         inode = affs_new_inode(dir);
 479         if (!inode) {
 480                 iput(oldinode);
 481                 iput(dir);
 482                 return -ENOSPC;
 483         }
 484         inode->i_op                = oldinode->i_op;
 485         inode->i_mode              = oldinode->i_mode;
 486         inode->i_uid               = oldinode->i_uid;
 487         inode->i_gid               = oldinode->i_gid;
 488         inode->u.affs_i.i_protect  = mode_to_prot(inode->i_mode);
 489         inode->u.affs_i.i_original = oldinode->i_ino;
 490         inode->u.affs_i.i_hlink    = 1;
 491 
 492         if (S_ISDIR(oldinode->i_mode))
 493                 error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKDIR);
 494         else
 495                 error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE);
 496         if (error) {
 497                 inode->i_nlink = 0;
 498                 inode->i_dirt  = 1;
 499         }
 500         iput(dir);
 501         iput(inode);
 502         iput(oldinode);
 503 
 504         return error;
 505 }
 506 
 507 static int
 508 subdir(struct inode * new_inode, struct inode * old_inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 509 {
 510     int ino;
 511     int result;
 512 
 513     new_inode->i_count++;
 514     result = 0;
 515     for (;;) {
 516         if (new_inode == old_inode) {
 517             result = 1;
 518             break;
 519         }
 520         if (new_inode->i_dev != old_inode->i_dev)
 521             break;
 522         ino = new_inode->i_ino;
 523         if (affs_lookup(new_inode,"..",2,&new_inode))
 524             break;
 525         if (new_inode->i_ino == ino)
 526             break;
 527     }
 528     iput(new_inode);
 529     return result;
 530 }
 531 
 532 /* I'm afraid this might not be race proof. Maybe next time. */
 533 
 534 int
 535 affs_rename(struct inode *old_dir, const char *old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 536             struct inode *new_dir, const char *new_name, int new_len)
 537 {
 538         struct inode            *old_inode;
 539         struct inode            *new_inode;
 540         struct buffer_head      *old_bh;
 541         struct buffer_head      *new_bh;
 542         unsigned long            old_ino;
 543         unsigned long            new_ino;
 544         int                      retval;
 545 
 546         pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name,
 547                 new_dir->i_ino,new_len,new_name);
 548         
 549         if (new_len > 30)
 550                 new_len = 30;
 551         goto start_up;
 552 retry:
 553         affs_brelse(old_bh);
 554         affs_brelse(new_bh);
 555         iput(new_inode);
 556         iput(old_inode);
 557         current->counter = 0;
 558         schedule();
 559 start_up:
 560         old_inode = new_inode = NULL;
 561         old_bh    = new_bh = NULL;
 562         retval    = -ENOENT;
 563 
 564         old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino);
 565         if (!old_bh)
 566                 goto end_rename;
 567         old_inode = __iget(old_dir->i_sb,old_ino,0);
 568         if (!old_inode)
 569                 goto end_rename;
 570         new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
 571         if (new_bh) {
 572                 new_inode = __iget(new_dir->i_sb,new_ino,0);
 573                 if (!new_inode) {               /* What does this mean? */
 574                         affs_brelse(new_bh);
 575                         new_bh = NULL;
 576                 }
 577         }
 578         if (new_inode == old_inode) {           /* Won't happen */
 579                 retval = 0;
 580                 goto end_rename;
 581         }
 582         if (new_inode && S_ISDIR(new_inode->i_mode)) {
 583                 retval = -EISDIR;
 584                 if (!S_ISDIR(old_inode->i_mode))
 585                         goto end_rename;
 586                 retval = -EINVAL;
 587                 if (subdir(new_dir,old_inode))
 588                         goto end_rename;
 589                 retval = -ENOTEMPTY;
 590                 if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
 591                         goto end_rename;
 592                 retval = -EBUSY;
 593                 if (new_inode->i_count > 1)
 594                         goto end_rename;
 595         }
 596         if (S_ISDIR(old_inode->i_mode)) {
 597                 retval = -ENOTDIR;
 598                 if (new_inode && !S_ISDIR(new_inode->i_mode))
 599                         goto end_rename;
 600                 retval = -EINVAL;
 601                 if (subdir(new_dir,old_inode))
 602                         goto end_rename;
 603                 if (affs_parent_ino(old_inode) != old_dir->i_ino)
 604                         goto end_rename;
 605         }
 606         /* Unlink destination if existant */
 607         if (new_inode) {
 608                 if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len,
 609                                                  AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6,
 610                                                  new_ino,
 611                                                  FILE_END(new_bh->b_data,new_dir)->hash_chain)))
 612                         goto retry;
 613                 if ((retval = affs_fixup(new_bh,new_inode)))
 614                         goto retry;
 615                 mark_buffer_dirty(new_bh,1);
 616                 new_dir->i_version = ++event;
 617                 new_dir->i_dirt    = 1;
 618                 new_inode->i_nlink = 0;
 619                 new_inode->i_dirt  = 1;
 620         }
 621         retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir),
 622                                     AFFS_I2HSIZE(old_dir)) + 6,old_ino,
 623                                     FILE_END(old_bh->b_data,old_dir)->hash_chain);
 624         if (retval)
 625                 goto retry;
 626 
 627         retval = affs_add_entry(new_dir,NULL,old_inode,new_name,new_len,
 628                                 htonl(FILE_END(old_bh->b_data,old_dir)->secondary_type));
 629 
 630         new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 631         new_dir->i_version = ++event;
 632         old_dir->i_version = ++event;
 633         new_dir->i_dirt    = 1;
 634         old_dir->i_dirt    = 1;
 635         mark_buffer_dirty(old_bh,1);
 636         
 637 end_rename:
 638         affs_brelse(old_bh);
 639         affs_brelse(new_bh);
 640         iput(new_inode);
 641         iput(old_inode);
 642         iput(old_dir);
 643         iput(new_dir);
 644 
 645         return retval;
 646 }
 647 
 648 int
 649 affs_fixup(struct buffer_head *bh, struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 650 {
 651         ULONG                    key, link_key;
 652         LONG                     type;
 653         struct buffer_head      *nbh;
 654         struct inode            *ofinode;
 655 
 656         type = htonl(FILE_END(bh->b_data,inode)->secondary_type);
 657         if (type == ST_LINKFILE || type == ST_LINKDIR) {
 658                 key = htonl(LINK_END(bh->b_data,inode)->original);
 659                 LINK_END(bh->b_data,inode)->original = 0;
 660                 if (!key) {
 661                         printk("AFFS: fixup(): hard link without original: ino=%lu\n",inode->i_ino);
 662                         return -ENOENT;
 663                 }
 664                 if (!(ofinode = iget(inode->i_sb,key)))
 665                         return -ENOENT;
 666                 type = affs_fix_link_pred(ofinode,inode->i_ino,
 667                                           FILE_END(bh->b_data,inode)->link_chain);
 668                 iput(ofinode);
 669                 return type;
 670         } else if (type == ST_FILE || type == ST_USERDIR) {
 671                 if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) {
 672                         /* Get first link, turn it to a file */
 673                         if (!(ofinode = iget(inode->i_sb,key))) {
 674                                 printk("AFFS: fixup(): cannot read inode %u\n",key);
 675                                 return -ENOENT;
 676                         }
 677                         if (!ofinode->u.affs_i.i_hlink) {
 678                                 printk("AFFS: fixup(): first link to %lu (%u) is not a link?\n",
 679                                         inode->i_ino,key);
 680                                 iput(ofinode);
 681                                 return -ENOENT;
 682                         }
 683                         if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
 684                                 printk("AFFS: fixup(): cannot read block %u\n",key);
 685                                 iput(ofinode);
 686                                 return -ENOENT;
 687                         }
 688                         lock_super(inode->i_sb);
 689                         memcpy(nbh->b_data + 8,bh->b_data + 8,AFFS_I2BSIZE(inode) - 208);
 690                         FILE_END(nbh->b_data,inode)->byte_size = FILE_END(bh->b_data,inode)->
 691                                                                           byte_size;
 692                         FILE_END(nbh->b_data,inode)->extension = FILE_END(bh->b_data,inode)->
 693                                                                           extension;
 694                         FILE_END(nbh->b_data,inode)->secondary_type = FILE_END(bh->b_data,inode)->
 695                                                                           secondary_type;
 696                         FILE_END(nbh->b_data,inode)->original = 0;
 697 
 698                         ofinode->u.affs_i.i_original = 0;
 699                         ofinode->u.affs_i.i_hlink    = 0;
 700                         ofinode->i_size              = inode->i_size;
 701                         ofinode->i_uid               = inode->i_uid;
 702                         ofinode->i_gid               = inode->i_gid;
 703                         ofinode->i_dirt              = 1;
 704                         link_key                     = ofinode->i_ino;
 705 
 706                         /* Let all remaining links point to the new file */
 707                         while (1) {
 708                                 affs_fix_checksum(AFFS_I2BSIZE(inode),nbh->b_data,5);
 709                                 mark_buffer_dirty(nbh,1);
 710                                 key = htonl(FILE_END(nbh->b_data,inode)->link_chain);
 711                                 affs_brelse(nbh);
 712                                 iput(ofinode);
 713                                 if (!key || !(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode))))
 714                                         break;
 715                                 if ((ofinode = iget(inode->i_sb,key))) {
 716                                         if (!ofinode->u.affs_i.i_hlink)
 717                                                 printk("AFFS: fixup() inode %u in link chain is "
 718                                                        "not a link\n",key);
 719                                         ofinode->u.affs_i.i_original = link_key;
 720                                         ofinode->i_dirt              = 1;
 721                                         FILE_END(nbh->b_data,inode)->original = htonl(link_key);
 722                                 } else
 723                                         printk("AFFS: fixup(): cannot get inode %u\n",key);
 724                         }
 725                         /* Turn old inode to a link */
 726                         inode->u.affs_i.i_hlink = 1;
 727                         unlock_super(inode->i_sb);
 728                 }
 729                 return 0;
 730         } else if (type == ST_SOFTLINK) {
 731                 return 0;
 732         } else {
 733                 printk("AFFS: fixup(): secondary type=%d\n",type);
 734                 return -EBADF;
 735         }
 736 }

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