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

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