root/fs/sysv/namei.c

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

DEFINITIONS

This source file includes following definitions.
  1. namecompare
  2. sysv_match
  3. sysv_find_entry
  4. sysv_lookup
  5. sysv_add_entry
  6. sysv_create
  7. sysv_mknod
  8. sysv_mkdir
  9. empty_dir
  10. sysv_rmdir
  11. sysv_unlink
  12. sysv_symlink
  13. sysv_link
  14. subdir
  15. do_sysv_rename
  16. sysv_rename

   1 /*
   2  *  linux/fs/sysv/namei.c
   3  *
   4  *  minix/namei.c
   5  *  Copyright (C) 1991, 1992  Linus Torvalds
   6  *
   7  *  coh/namei.c
   8  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
   9  *
  10  *  sysv/namei.c
  11  *  Copyright (C) 1993  Bruno Haible
  12  */
  13 
  14 #include <linux/sched.h>
  15 #include <linux/kernel.h>
  16 #include <linux/fs.h>
  17 #include <linux/sysv_fs.h>
  18 #include <linux/string.h>
  19 #include <linux/stat.h>
  20 #include <linux/errno.h>
  21 
  22 /* compare strings: name[0..len-1] (not zero-terminated) and
  23  * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1])
  24  */
  25 static inline int namecompare(int len, int maxlen,
     /* [previous][next][first][last][top][bottom][index][help] */
  26         const char * name, const char * buffer)
  27 {
  28         if (len > maxlen)
  29                 return 0;
  30         if (len < maxlen && buffer[len])
  31                 return 0;
  32         return !memcmp(name, buffer, len);
  33 }
  34 
  35 /*
  36  * ok, we cannot use strncmp, as the name is not in our data space. [Now it is!]
  37  * Thus we'll have to use sysv_match. No big problem. Match also makes
  38  * some sanity tests.
  39  *
  40  * NOTE! unlike strncmp, sysv_match returns 1 for success, 0 for failure.
  41  */
  42 static int sysv_match(int len, const char * name, struct sysv_dir_entry * de)
     /* [previous][next][first][last][top][bottom][index][help] */
  43 {
  44         if (!de->inode || len > SYSV_NAMELEN)
  45                 return 0;
  46         /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
  47         if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
  48                 return 1;
  49         return namecompare(len,SYSV_NAMELEN,name,de->name);
  50 }
  51 
  52 /*
  53  *      sysv_find_entry()
  54  *
  55  * finds an entry in the specified directory with the wanted name. It
  56  * returns the cache buffer in which the entry was found, and the entry
  57  * itself (as a parameter - res_dir). It does NOT read the inode of the
  58  * entry - you'll have to do that yourself if you want to.
  59  */
  60 static struct buffer_head * sysv_find_entry(struct inode * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
  61         const char * name, int namelen, struct sysv_dir_entry ** res_dir)
  62 {
  63         struct super_block * sb;
  64         unsigned long pos, block, offset; /* pos = block * block_size + offset */
  65         struct buffer_head * bh;
  66 
  67         *res_dir = NULL;
  68         if (!dir)
  69                 return NULL;
  70         sb = dir->i_sb;
  71         if (namelen > SYSV_NAMELEN)
  72                 if (sb->sv_truncate)
  73                         namelen = SYSV_NAMELEN;
  74                 else
  75                         return NULL;
  76         bh = NULL;
  77         pos = block = offset = 0;
  78         while (pos < dir->i_size) {
  79                 if (!bh) {
  80                         bh = sysv_file_bread(dir,block,0);
  81                         if (!bh) {
  82                                 /* offset = 0; */ block++;
  83                                 pos += sb->sv_block_size;
  84                                 continue;
  85                         }
  86                 }
  87                 if (sysv_match(namelen, name,
  88                                *res_dir = (struct sysv_dir_entry *) (bh->b_data + offset) ))
  89                         return bh;
  90                 pos += SYSV_DIRSIZE;
  91                 offset += SYSV_DIRSIZE;
  92                 if (offset < sb->sv_block_size)
  93                         continue;
  94                 brelse(bh);
  95                 bh = NULL;
  96                 offset = 0; block++;
  97         }
  98         brelse(bh);
  99         *res_dir = NULL;
 100         return NULL;
 101 }
 102 
 103 int sysv_lookup(struct inode * dir,const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 104         struct inode ** result)
 105 {
 106         int ino;
 107         struct sysv_dir_entry * de;
 108         struct buffer_head * bh;
 109 
 110         *result = NULL;
 111         if (!dir)
 112                 return -ENOENT;
 113         if (!S_ISDIR(dir->i_mode)) {
 114                 iput(dir);
 115                 return -ENOENT;
 116         }
 117         if (!(bh = sysv_find_entry(dir,name,len,&de))) {
 118                 iput(dir);
 119                 return -ENOENT;
 120         }
 121         ino = de->inode;
 122         brelse(bh);
 123         if (!(*result = iget(dir->i_sb,ino))) {
 124                 iput(dir);
 125                 return -EACCES;
 126         }
 127         iput(dir);
 128         return 0;
 129 }
 130 
 131 /*
 132  *      sysv_add_entry()
 133  *
 134  * adds a file entry to the specified directory, returning a possible
 135  * error value if it fails.
 136  *
 137  * NOTE!! The inode part of 'de' is left at 0 - which means you
 138  * may not sleep between calling this and putting something into
 139  * the entry, as someone else might have used it while you slept.
 140  */
 141 static int sysv_add_entry(struct inode * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
 142         const char * name, int namelen,
 143         struct buffer_head ** res_buf,
 144         struct sysv_dir_entry ** res_dir)
 145 {
 146         struct super_block * sb;
 147         int i;
 148         unsigned long pos, block, offset; /* pos = block * block_size + offset */
 149         struct buffer_head * bh;
 150         struct sysv_dir_entry * de;
 151 
 152         *res_buf = NULL;
 153         *res_dir = NULL;
 154         if (!dir)
 155                 return -ENOENT;
 156         sb = dir->i_sb;
 157         if (namelen > SYSV_NAMELEN)
 158                 if (sb->sv_truncate)
 159                         namelen = SYSV_NAMELEN;
 160                 else
 161                         return -ENAMETOOLONG;
 162         if (!namelen)
 163                 return -ENOENT;
 164         bh = NULL;
 165         pos = block = offset = 0;
 166         while (1) {
 167                 if (!bh) {
 168                         bh = sysv_file_bread(dir,block,1);
 169                         if (!bh)
 170                                 return -ENOSPC;
 171                 }
 172                 de = (struct sysv_dir_entry *) (bh->b_data + offset);
 173                 pos += SYSV_DIRSIZE;
 174                 offset += SYSV_DIRSIZE;
 175                 if (pos > dir->i_size) {
 176                         de->inode = 0;
 177                         dir->i_size = pos;
 178                         dir->i_dirt = 1;
 179                 }
 180                 if (de->inode) {
 181                         if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) {
 182                                 brelse(bh);
 183                                 return -EEXIST;
 184                         }
 185                 } else {
 186                         dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 187                         dir->i_dirt = 1;
 188                         for (i = 0; i < SYSV_NAMELEN ; i++)
 189                                 de->name[i] = (i < namelen) ? name[i] : 0;
 190                         mark_buffer_dirty(bh, 1);
 191                         *res_dir = de;
 192                         break;
 193                 }
 194                 if (offset < sb->sv_block_size)
 195                         continue;
 196                 brelse(bh);
 197                 bh = NULL;
 198                 offset = 0; block++;
 199         }
 200         *res_buf = bh;
 201         return 0;
 202 }
 203 
 204 int sysv_create(struct inode * dir,const char * name, int len, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 205         struct inode ** result)
 206 {
 207         int error;
 208         struct inode * inode;
 209         struct buffer_head * bh;
 210         struct sysv_dir_entry * de;
 211 
 212         *result = NULL;
 213         if (!dir)
 214                 return -ENOENT;
 215         inode = sysv_new_inode(dir);
 216         if (!inode) {
 217                 iput(dir);
 218                 return -ENOSPC;
 219         }
 220         inode->i_op = &sysv_file_inode_operations;
 221         inode->i_mode = mode;
 222         inode->i_dirt = 1;
 223         error = sysv_add_entry(dir,name,len, &bh ,&de);
 224         if (error) {
 225                 inode->i_nlink--;
 226                 inode->i_dirt = 1;
 227                 iput(inode);
 228                 iput(dir);
 229                 return error;
 230         }
 231         de->inode = inode->i_ino;
 232         mark_buffer_dirty(bh, 1);
 233         brelse(bh);
 234         iput(dir);
 235         *result = inode;
 236         return 0;
 237 }
 238 
 239 int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
     /* [previous][next][first][last][top][bottom][index][help] */
 240 {
 241         int error;
 242         struct inode * inode;
 243         struct buffer_head * bh;
 244         struct sysv_dir_entry * de;
 245 
 246         if (!dir)
 247                 return -ENOENT;
 248         bh = sysv_find_entry(dir,name,len,&de);
 249         if (bh) {
 250                 brelse(bh);
 251                 iput(dir);
 252                 return -EEXIST;
 253         }
 254         inode = sysv_new_inode(dir);
 255         if (!inode) {
 256                 iput(dir);
 257                 return -ENOSPC;
 258         }
 259         inode->i_uid = current->fsuid;
 260         inode->i_mode = mode;
 261         inode->i_op = NULL;
 262         if (S_ISREG(inode->i_mode))
 263                 inode->i_op = &sysv_file_inode_operations;
 264         else if (S_ISDIR(inode->i_mode)) {
 265                 inode->i_op = &sysv_dir_inode_operations;
 266                 if (dir->i_mode & S_ISGID)
 267                         inode->i_mode |= S_ISGID;
 268         }
 269         else if (S_ISLNK(inode->i_mode))
 270                 inode->i_op = &sysv_symlink_inode_operations;
 271         else if (S_ISCHR(inode->i_mode))
 272                 inode->i_op = &chrdev_inode_operations;
 273         else if (S_ISBLK(inode->i_mode))
 274                 inode->i_op = &blkdev_inode_operations;
 275         else if (S_ISFIFO(inode->i_mode))
 276                 init_fifo(inode);
 277         if (S_ISBLK(mode) || S_ISCHR(mode))
 278                 inode->i_rdev = to_kdev_t(rdev);
 279         inode->i_dirt = 1;
 280         error = sysv_add_entry(dir, name, len, &bh, &de);
 281         if (error) {
 282                 inode->i_nlink--;
 283                 inode->i_dirt = 1;
 284                 iput(inode);
 285                 iput(dir);
 286                 return error;
 287         }
 288         de->inode = inode->i_ino;
 289         mark_buffer_dirty(bh, 1);
 290         brelse(bh);
 291         iput(dir);
 292         iput(inode);
 293         return 0;
 294 }
 295 
 296 int sysv_mkdir(struct inode * dir, const char * name, int len, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 297 {
 298         int error;
 299         struct inode * inode;
 300         struct buffer_head * bh, *dir_block;
 301         struct sysv_dir_entry * de;
 302 
 303         if (!dir) {
 304                 iput(dir);
 305                 return -EINVAL;
 306         }
 307         bh = sysv_find_entry(dir,name,len,&de);
 308         if (bh) {
 309                 brelse(bh);
 310                 iput(dir);
 311                 return -EEXIST;
 312         }
 313         if (dir->i_nlink >= dir->i_sb->sv_link_max) {
 314                 iput(dir);
 315                 return -EMLINK;
 316         }
 317         inode = sysv_new_inode(dir);
 318         if (!inode) {
 319                 iput(dir);
 320                 return -ENOSPC;
 321         }
 322         inode->i_op = &sysv_dir_inode_operations;
 323         inode->i_size = 2 * SYSV_DIRSIZE;
 324         dir_block = sysv_file_bread(inode,0,1);
 325         if (!dir_block) {
 326                 iput(dir);
 327                 inode->i_nlink--;
 328                 inode->i_dirt = 1;
 329                 iput(inode);
 330                 return -ENOSPC;
 331         }
 332         de = (struct sysv_dir_entry *) (dir_block->b_data + 0*SYSV_DIRSIZE);
 333         de->inode = inode->i_ino;
 334         strcpy(de->name,"."); /* rest of de->name is zero, see sysv_new_block */
 335         de = (struct sysv_dir_entry *) (dir_block->b_data + 1*SYSV_DIRSIZE);
 336         de->inode = dir->i_ino;
 337         strcpy(de->name,".."); /* rest of de->name is zero, see sysv_new_block */
 338         inode->i_nlink = 2;
 339         mark_buffer_dirty(dir_block, 1);
 340         brelse(dir_block);
 341         inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
 342         if (dir->i_mode & S_ISGID)
 343                 inode->i_mode |= S_ISGID;
 344         inode->i_dirt = 1;
 345         error = sysv_add_entry(dir, name, len, &bh, &de);
 346         if (error) {
 347                 iput(dir);
 348                 inode->i_nlink=0;
 349                 iput(inode);
 350                 return error;
 351         }
 352         de->inode = inode->i_ino;
 353         mark_buffer_dirty(bh, 1);
 354         dir->i_nlink++;
 355         dir->i_dirt = 1;
 356         iput(dir);
 357         iput(inode);
 358         brelse(bh);
 359         return 0;
 360 }
 361 
 362 /*
 363  * routine to check that the specified directory is empty (for rmdir)
 364  */
 365 static int empty_dir(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 366 {
 367         struct super_block * sb;
 368         unsigned long pos, block, offset; /* pos = block * block_size + offset */
 369         struct buffer_head * bh;
 370         struct sysv_dir_entry * de;
 371 
 372         if (!inode)
 373                 return 1;
 374         block = 0;
 375         bh = NULL;
 376         pos = offset = 2*SYSV_DIRSIZE;
 377         if (inode->i_size % SYSV_DIRSIZE)
 378                 goto bad_dir;
 379         if (inode->i_size < pos)
 380                 goto bad_dir;
 381         bh = sysv_file_bread(inode,0,0);
 382         if (!bh)
 383                 goto bad_dir;
 384         de = (struct sysv_dir_entry *) (bh->b_data + 0*SYSV_DIRSIZE);
 385         if (!de->inode || strcmp(de->name,"."))
 386                 goto bad_dir;
 387         de = (struct sysv_dir_entry *) (bh->b_data + 1*SYSV_DIRSIZE);
 388         if (!de->inode || strcmp(de->name,".."))
 389                 goto bad_dir;
 390         sb = inode->i_sb;
 391         while (pos < inode->i_size) {
 392                 if (!bh) {
 393                         bh = sysv_file_bread(inode,block,0);
 394                         if (!bh) {
 395                                 /* offset = 0; */ block++;
 396                                 pos += sb->sv_block_size;
 397                                 continue;
 398                         }
 399                 }
 400                 de = (struct sysv_dir_entry *) (bh->b_data + offset);
 401                 pos += SYSV_DIRSIZE;
 402                 offset += SYSV_DIRSIZE;
 403                 if (de->inode) {
 404                         brelse(bh);
 405                         return 0;
 406                 }
 407                 if (offset < sb->sv_block_size)
 408                         continue;
 409                 brelse(bh);
 410                 bh = NULL;
 411                 offset = 0; block++;
 412         }
 413         brelse(bh);
 414         return 1;
 415 bad_dir:
 416         brelse(bh);
 417         printk("Bad directory on device %s\n",
 418                kdevname(inode->i_dev));
 419         return 1;
 420 }
 421 
 422 int sysv_rmdir(struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 423 {
 424         int retval;
 425         struct inode * inode;
 426         struct buffer_head * bh;
 427         struct sysv_dir_entry * de;
 428 
 429         inode = NULL;
 430         bh = sysv_find_entry(dir,name,len,&de);
 431         retval = -ENOENT;
 432         if (!bh)
 433                 goto end_rmdir;
 434         retval = -EPERM;
 435         if (!(inode = iget(dir->i_sb, de->inode)))
 436                 goto end_rmdir;
 437         if ((dir->i_mode & S_ISVTX) && !fsuser() &&
 438             current->fsuid != inode->i_uid &&
 439             current->fsuid != dir->i_uid)
 440                 goto end_rmdir;
 441         if (inode->i_dev != dir->i_dev)
 442                 goto end_rmdir;
 443         if (inode == dir)       /* we may not delete ".", but "../dir" is ok */
 444                 goto end_rmdir;
 445         if (!S_ISDIR(inode->i_mode)) {
 446                 retval = -ENOTDIR;
 447                 goto end_rmdir;
 448         }
 449         if (!empty_dir(inode)) {
 450                 retval = -ENOTEMPTY;
 451                 goto end_rmdir;
 452         }
 453         if (de->inode != inode->i_ino) {
 454                 retval = -ENOENT;
 455                 goto end_rmdir;
 456         }
 457         if (inode->i_count > 1) {
 458                 retval = -EBUSY;
 459                 goto end_rmdir;
 460         }
 461         if (inode->i_nlink != 2)
 462                 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
 463         de->inode = 0;
 464         mark_buffer_dirty(bh, 1);
 465         inode->i_nlink=0;
 466         inode->i_dirt=1;
 467         dir->i_nlink--;
 468         inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 469         dir->i_dirt=1;
 470         retval = 0;
 471 end_rmdir:
 472         iput(dir);
 473         iput(inode);
 474         brelse(bh);
 475         return retval;
 476 }
 477 
 478 int sysv_unlink(struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 479 {
 480         int retval;
 481         struct inode * inode;
 482         struct buffer_head * bh;
 483         struct sysv_dir_entry * de;
 484 
 485 repeat:
 486         retval = -ENOENT;
 487         inode = NULL;
 488         bh = sysv_find_entry(dir,name,len,&de);
 489         if (!bh)
 490                 goto end_unlink;
 491         if (!(inode = iget(dir->i_sb, de->inode)))
 492                 goto end_unlink;
 493         retval = -EPERM;
 494         if (S_ISDIR(inode->i_mode))
 495                 goto end_unlink;
 496         if (de->inode != inode->i_ino) {
 497                 iput(inode);
 498                 brelse(bh);
 499                 current->counter = 0;
 500                 schedule();
 501                 goto repeat;
 502         }
 503         if ((dir->i_mode & S_ISVTX) && !fsuser() &&
 504             current->fsuid != inode->i_uid &&
 505             current->fsuid != dir->i_uid)
 506                 goto end_unlink;
 507         if (de->inode != inode->i_ino) {
 508                 retval = -ENOENT;
 509                 goto end_unlink;
 510         }
 511         if (!inode->i_nlink) {
 512                 printk("Deleting nonexistent file (%s:%lu), %d\n",
 513                        kdevname(inode->i_dev),
 514                        inode->i_ino, inode->i_nlink);
 515                 inode->i_nlink=1;
 516         }
 517         de->inode = 0;
 518         mark_buffer_dirty(bh, 1);
 519         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 520         dir->i_dirt = 1;
 521         inode->i_nlink--;
 522         inode->i_ctime = dir->i_ctime;
 523         inode->i_dirt = 1;
 524         retval = 0;
 525 end_unlink:
 526         brelse(bh);
 527         iput(inode);
 528         iput(dir);
 529         return retval;
 530 }
 531 
 532 int sysv_symlink(struct inode * dir, const char * name, int len, const char * symname)
     /* [previous][next][first][last][top][bottom][index][help] */
 533 {
 534         struct sysv_dir_entry * de;
 535         struct inode * inode;
 536         struct buffer_head * name_block;
 537         char * name_block_data;
 538         struct super_block * sb;
 539         int i;
 540         char c;
 541         struct buffer_head * bh;
 542 
 543         if (!(inode = sysv_new_inode(dir))) {
 544                 iput(dir);
 545                 return -ENOSPC;
 546         }
 547         inode->i_mode = S_IFLNK | 0777;
 548         inode->i_op = &sysv_symlink_inode_operations;
 549         name_block = sysv_file_bread(inode,0,1);
 550         if (!name_block) {
 551                 iput(dir);
 552                 inode->i_nlink--;
 553                 inode->i_dirt = 1;
 554                 iput(inode);
 555                 return -ENOSPC;
 556         }
 557         sb = inode->i_sb;
 558         name_block_data = name_block->b_data;
 559         i = 0;
 560         while (i < sb->sv_block_size_1 && (c = *(symname++)))
 561                 name_block_data[i++] = c;
 562         name_block_data[i] = 0;
 563         mark_buffer_dirty(name_block, 1);
 564         brelse(name_block);
 565         inode->i_size = i;
 566         inode->i_dirt = 1;
 567         bh = sysv_find_entry(dir,name,len,&de);
 568         if (bh) {
 569                 inode->i_nlink--;
 570                 inode->i_dirt = 1;
 571                 iput(inode);
 572                 brelse(bh);
 573                 iput(dir);
 574                 return -EEXIST;
 575         }
 576         i = sysv_add_entry(dir, name, len, &bh, &de);
 577         if (i) {
 578                 inode->i_nlink--;
 579                 inode->i_dirt = 1;
 580                 iput(inode);
 581                 iput(dir);
 582                 return i;
 583         }
 584         de->inode = inode->i_ino;
 585         mark_buffer_dirty(bh, 1);
 586         brelse(bh);
 587         iput(dir);
 588         iput(inode);
 589         return 0;
 590 }
 591 
 592 int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 593 {
 594         int error;
 595         struct sysv_dir_entry * de;
 596         struct buffer_head * bh;
 597 
 598         if (S_ISDIR(oldinode->i_mode)) {
 599                 iput(oldinode);
 600                 iput(dir);
 601                 return -EPERM;
 602         }
 603         if (oldinode->i_nlink >= oldinode->i_sb->sv_link_max) {
 604                 iput(oldinode);
 605                 iput(dir);
 606                 return -EMLINK;
 607         }
 608         bh = sysv_find_entry(dir,name,len,&de);
 609         if (bh) {
 610                 brelse(bh);
 611                 iput(dir);
 612                 iput(oldinode);
 613                 return -EEXIST;
 614         }
 615         error = sysv_add_entry(dir, name, len, &bh, &de);
 616         if (error) {
 617                 iput(dir);
 618                 iput(oldinode);
 619                 return error;
 620         }
 621         de->inode = oldinode->i_ino;
 622         mark_buffer_dirty(bh, 1);
 623         brelse(bh);
 624         iput(dir);
 625         oldinode->i_nlink++;
 626         oldinode->i_ctime = CURRENT_TIME;
 627         oldinode->i_dirt = 1;
 628         iput(oldinode);
 629         return 0;
 630 }
 631 
 632 /* return 1 if `new' is a subdir of `old' on the same device */
 633 static int subdir(struct inode * new_inode, struct inode * old_inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 634 {
 635         int ino;
 636         int result;
 637 
 638         new_inode->i_count++;
 639         result = 0;
 640         for (;;) {
 641                 if (new_inode == old_inode) {
 642                         result = 1;
 643                         break;
 644                 }
 645                 if (new_inode->i_dev != old_inode->i_dev)
 646                         break;
 647                 ino = new_inode->i_ino;
 648                 if (sysv_lookup(new_inode,"..",2,&new_inode))
 649                         break;
 650                 if (new_inode->i_ino == ino) /* root dir reached ? */
 651                         break;
 652         }
 653         iput(new_inode);
 654         return result;
 655 }
 656 
 657 #define PARENT_INO(buffer) \
 658 (((struct sysv_dir_entry *) ((buffer) + 1*SYSV_DIRSIZE))->inode)
 659 
 660 /*
 661  * rename uses retrying to avoid race-conditions: at least they should be minimal.
 662  * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
 663  * checks fail, it tries to restart itself again. Very practical - no changes
 664  * are done until we know everything works ok.. and then all the changes can be
 665  * done in one fell swoop when we have claimed all the buffers needed.
 666  *
 667  * Anybody can rename anything with this: the permission checks are left to the
 668  * higher-level routines.
 669  */
 670 static int do_sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 671         struct inode * new_dir, const char * new_name, int new_len)
 672 {
 673         struct inode * old_inode, * new_inode;
 674         struct buffer_head * old_bh, * new_bh, * dir_bh;
 675         struct sysv_dir_entry * old_de, * new_de;
 676         int retval;
 677 
 678         goto start_up;
 679 try_again:
 680         brelse(old_bh);
 681         brelse(new_bh);
 682         brelse(dir_bh);
 683         iput(old_inode);
 684         iput(new_inode);
 685         current->counter = 0;
 686         schedule();
 687 start_up:
 688         old_inode = new_inode = NULL;
 689         old_bh = new_bh = dir_bh = NULL;
 690         old_bh = sysv_find_entry(old_dir,old_name,old_len,&old_de);
 691         retval = -ENOENT;
 692         if (!old_bh)
 693                 goto end_rename;
 694         old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
 695         if (!old_inode)
 696                 goto end_rename;
 697         retval = -EPERM;
 698         if ((old_dir->i_mode & S_ISVTX) && 
 699             current->fsuid != old_inode->i_uid &&
 700             current->fsuid != old_dir->i_uid && !fsuser())
 701                 goto end_rename;
 702         new_bh = sysv_find_entry(new_dir,new_name,new_len,&new_de);
 703         if (new_bh) {
 704                 new_inode = __iget(new_dir->i_sb, new_de->inode, 0);
 705                 if (!new_inode) {
 706                         brelse(new_bh);
 707                         new_bh = NULL;
 708                 }
 709         }
 710         if (new_inode == old_inode) {
 711                 retval = 0;
 712                 goto end_rename;
 713         }
 714         if (new_inode && S_ISDIR(new_inode->i_mode)) {
 715                 retval = -EISDIR;
 716                 if (!S_ISDIR(old_inode->i_mode))
 717                         goto end_rename;
 718                 retval = -EINVAL;
 719                 if (subdir(new_dir, old_inode))
 720                         goto end_rename;
 721                 retval = -ENOTEMPTY;
 722                 if (!empty_dir(new_inode))
 723                         goto end_rename;
 724                 retval = -EBUSY;
 725                 if (new_inode->i_count > 1)
 726                         goto end_rename;
 727         }
 728         retval = -EPERM;
 729         if (new_inode && (new_dir->i_mode & S_ISVTX) && 
 730             current->fsuid != new_inode->i_uid &&
 731             current->fsuid != new_dir->i_uid && !fsuser())
 732                 goto end_rename;
 733         if (S_ISDIR(old_inode->i_mode)) {
 734                 retval = -ENOTDIR;
 735                 if (new_inode && !S_ISDIR(new_inode->i_mode))
 736                         goto end_rename;
 737                 retval = -EINVAL;
 738                 if (subdir(new_dir, old_inode))
 739                         goto end_rename;
 740                 retval = -EIO;
 741                 dir_bh = sysv_file_bread(old_inode,0,0);
 742                 if (!dir_bh)
 743                         goto end_rename;
 744                 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
 745                         goto end_rename;
 746                 retval = -EMLINK;
 747                 if (!new_inode && new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
 748                         goto end_rename;
 749         }
 750         if (!new_bh) {
 751                 retval = sysv_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
 752                 if (retval)
 753                         goto end_rename;
 754         }
 755 /* sanity checking before doing the rename - avoid races */
 756         if (new_inode && (new_de->inode != new_inode->i_ino))
 757                 goto try_again;
 758         if (new_de->inode && !new_inode)
 759                 goto try_again;
 760         if (old_de->inode != old_inode->i_ino)
 761                 goto try_again;
 762 /* ok, that's it */
 763         old_de->inode = 0;
 764         new_de->inode = old_inode->i_ino;
 765         old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 766         old_dir->i_dirt = 1;
 767         new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
 768         new_dir->i_dirt = 1;
 769         if (new_inode) {
 770                 new_inode->i_nlink--;
 771                 new_inode->i_ctime = CURRENT_TIME;
 772                 new_inode->i_dirt = 1;
 773         }
 774         mark_buffer_dirty(old_bh, 1);
 775         mark_buffer_dirty(new_bh, 1);
 776         if (dir_bh) {
 777                 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
 778                 mark_buffer_dirty(dir_bh, 1);
 779                 old_dir->i_nlink--;
 780                 old_dir->i_dirt = 1;
 781                 if (new_inode) {
 782                         new_inode->i_nlink--;
 783                         new_inode->i_dirt = 1;
 784                 } else {
 785                         new_dir->i_nlink++;
 786                         new_dir->i_dirt = 1;
 787                 }
 788         }
 789         retval = 0;
 790 end_rename:
 791         brelse(dir_bh);
 792         brelse(old_bh);
 793         brelse(new_bh);
 794         iput(old_inode);
 795         iput(new_inode);
 796         iput(old_dir);
 797         iput(new_dir);
 798         return retval;
 799 }
 800 
 801 /*
 802  * Ok, rename also locks out other renames, as they can change the parent of
 803  * a directory, and we don't want any races. Other races are checked for by
 804  * "do_rename()", which restarts if there are inconsistencies.
 805  *
 806  * Note that there is no race between different filesystems: it's only within
 807  * the same device that races occur: many renames can happen at once, as long
 808  * as they are on different partitions.
 809  */
 810 int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 811         struct inode * new_dir, const char * new_name, int new_len)
 812 {
 813         static struct wait_queue * wait = NULL;
 814         static int lock = 0;
 815         int result;
 816 
 817         while (lock)
 818                 sleep_on(&wait);
 819         lock = 1;
 820         result = do_sysv_rename(old_dir, old_name, old_len,
 821                 new_dir, new_name, new_len);
 822         lock = 0;
 823         wake_up(&wait);
 824         return result;
 825 }

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