root/fs/minix/namei.c

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

DEFINITIONS

This source file includes following definitions.
  1. namecompare
  2. minix_match
  3. minix_find_entry
  4. minix_lookup
  5. minix_add_entry
  6. minix_create
  7. minix_mknod
  8. minix_mkdir
  9. empty_dir
  10. minix_rmdir
  11. minix_unlink
  12. minix_symlink
  13. minix_link
  14. subdir
  15. do_minix_rename
  16. minix_rename

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

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