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 #ifdef MODULE
   8 #include <linux/module.h>
   9 #endif
  10 
  11 #include <linux/sched.h>
  12 #include <linux/minix_fs.h>
  13 #include <linux/kernel.h>
  14 #include <linux/string.h>
  15 #include <linux/stat.h>
  16 #include <linux/fcntl.h>
  17 #include <linux/errno.h>
  18 
  19 #include <asm/segment.h>
  20 
  21 /*
  22  * comment out this line if you want names > info->s_namelen chars to be
  23  * truncated. Else they will be disallowed (ENAMETOOLONG).
  24  */
  25 /* #define NO_TRUNCATE */
  26 
  27 static inline int namecompare(int len, int maxlen,
     /* [previous][next][first][last][top][bottom][index][help] */
  28         const char * name, const char * buffer)
  29 {
  30         if (len > maxlen)
  31                 return 0;
  32         if (len < maxlen && buffer[len])
  33                 return 0;
  34         return !memcmp(name, buffer, len);
  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                         dir->i_dirt = 1;
 197                         for (i = 0; i < info->s_namelen ; i++)
 198                                 de->name[i] = (i < namelen) ? name[i] : 0;
 199                         dir->i_version = ++event;
 200                         mark_buffer_dirty(bh, 1);
 201                         *res_dir = de;
 202                         break;
 203                 }
 204                 if (offset < bh->b_size)
 205                         continue;
 206                 brelse(bh);
 207                 bh = NULL;
 208                 offset = 0;
 209                 block++;
 210         }
 211         *res_buf = bh;
 212         return 0;
 213 }
 214 
 215 int minix_create(struct inode * dir,const char * name, int len, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 216         struct inode ** result)
 217 {
 218         int error;
 219         struct inode * inode;
 220         struct buffer_head * bh;
 221         struct minix_dir_entry * de;
 222 
 223         *result = NULL;
 224         if (!dir)
 225                 return -ENOENT;
 226         inode = minix_new_inode(dir);
 227         if (!inode) {
 228                 iput(dir);
 229                 return -ENOSPC;
 230         }
 231         inode->i_op = &minix_file_inode_operations;
 232         inode->i_mode = mode;
 233         inode->i_dirt = 1;
 234         error = minix_add_entry(dir,name,len, &bh ,&de);
 235         if (error) {
 236                 inode->i_nlink--;
 237                 inode->i_dirt = 1;
 238                 iput(inode);
 239                 iput(dir);
 240                 return error;
 241         }
 242         de->inode = inode->i_ino;
 243         mark_buffer_dirty(bh, 1);
 244         brelse(bh);
 245         iput(dir);
 246         *result = inode;
 247         return 0;
 248 }
 249 
 250 int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
     /* [previous][next][first][last][top][bottom][index][help] */
 251 {
 252         int error;
 253         struct inode * inode;
 254         struct buffer_head * bh;
 255         struct minix_dir_entry * de;
 256 
 257         if (!dir)
 258                 return -ENOENT;
 259         bh = minix_find_entry(dir,name,len,&de);
 260         if (bh) {
 261                 brelse(bh);
 262                 iput(dir);
 263                 return -EEXIST;
 264         }
 265         inode = minix_new_inode(dir);
 266         if (!inode) {
 267                 iput(dir);
 268                 return -ENOSPC;
 269         }
 270         inode->i_uid = current->fsuid;
 271         inode->i_mode = mode;
 272         inode->i_op = NULL;
 273         if (S_ISREG(inode->i_mode))
 274                 inode->i_op = &minix_file_inode_operations;
 275         else if (S_ISDIR(inode->i_mode)) {
 276                 inode->i_op = &minix_dir_inode_operations;
 277                 if (dir->i_mode & S_ISGID)
 278                         inode->i_mode |= S_ISGID;
 279         }
 280         else if (S_ISLNK(inode->i_mode))
 281                 inode->i_op = &minix_symlink_inode_operations;
 282         else if (S_ISCHR(inode->i_mode))
 283                 inode->i_op = &chrdev_inode_operations;
 284         else if (S_ISBLK(inode->i_mode))
 285                 inode->i_op = &blkdev_inode_operations;
 286         else if (S_ISFIFO(inode->i_mode))
 287                 init_fifo(inode);
 288         if (S_ISBLK(mode) || S_ISCHR(mode))
 289                 inode->i_rdev = to_kdev_t(rdev);
 290         inode->i_dirt = 1;
 291         error = minix_add_entry(dir, name, len, &bh, &de);
 292         if (error) {
 293                 inode->i_nlink--;
 294                 inode->i_dirt = 1;
 295                 iput(inode);
 296                 iput(dir);
 297                 return error;
 298         }
 299         de->inode = inode->i_ino;
 300         mark_buffer_dirty(bh, 1);
 301         brelse(bh);
 302         iput(dir);
 303         iput(inode);
 304         return 0;
 305 }
 306 
 307 int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 308 {
 309         int error;
 310         struct inode * inode;
 311         struct buffer_head * bh, *dir_block;
 312         struct minix_dir_entry * de;
 313         struct minix_sb_info * info;
 314 
 315         if (!dir || !dir->i_sb) {
 316                 iput(dir);
 317                 return -EINVAL;
 318         }
 319         info = &dir->i_sb->u.minix_sb;
 320         bh = minix_find_entry(dir,name,len,&de);
 321         if (bh) {
 322                 brelse(bh);
 323                 iput(dir);
 324                 return -EEXIST;
 325         }
 326         if (dir->i_nlink >= MINIX_LINK_MAX) {
 327                 iput(dir);
 328                 return -EMLINK;
 329         }
 330         inode = minix_new_inode(dir);
 331         if (!inode) {
 332                 iput(dir);
 333                 return -ENOSPC;
 334         }
 335         inode->i_op = &minix_dir_inode_operations;
 336         inode->i_size = 2 * info->s_dirsize;
 337         dir_block = minix_bread(inode,0,1);
 338         if (!dir_block) {
 339                 iput(dir);
 340                 inode->i_nlink--;
 341                 inode->i_dirt = 1;
 342                 iput(inode);
 343                 return -ENOSPC;
 344         }
 345         de = (struct minix_dir_entry *) dir_block->b_data;
 346         de->inode=inode->i_ino;
 347         strcpy(de->name,".");
 348         de = (struct minix_dir_entry *) (dir_block->b_data + info->s_dirsize);
 349         de->inode = dir->i_ino;
 350         strcpy(de->name,"..");
 351         inode->i_nlink = 2;
 352         mark_buffer_dirty(dir_block, 1);
 353         brelse(dir_block);
 354         inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
 355         if (dir->i_mode & S_ISGID)
 356                 inode->i_mode |= S_ISGID;
 357         inode->i_dirt = 1;
 358         error = minix_add_entry(dir, name, len, &bh, &de);
 359         if (error) {
 360                 iput(dir);
 361                 inode->i_nlink=0;
 362                 iput(inode);
 363                 return error;
 364         }
 365         de->inode = inode->i_ino;
 366         mark_buffer_dirty(bh, 1);
 367         dir->i_nlink++;
 368         dir->i_dirt = 1;
 369         iput(dir);
 370         iput(inode);
 371         brelse(bh);
 372         return 0;
 373 }
 374 
 375 /*
 376  * routine to check that the specified directory is empty (for rmdir)
 377  */
 378 static int empty_dir(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 379 {
 380         unsigned int block, offset;
 381         struct buffer_head * bh;
 382         struct minix_dir_entry * de;
 383         struct minix_sb_info * info;
 384 
 385         if (!inode || !inode->i_sb)
 386                 return 1;
 387         info = &inode->i_sb->u.minix_sb;
 388         block = 0;
 389         bh = NULL;
 390         offset = 2*info->s_dirsize;
 391         if (inode->i_size & (info->s_dirsize-1))
 392                 goto bad_dir;
 393         if (inode->i_size < offset)
 394                 goto bad_dir;
 395         bh = minix_bread(inode,0,0);
 396         if (!bh)
 397                 goto bad_dir;
 398         de = (struct minix_dir_entry *) bh->b_data;
 399         if (!de->inode || strcmp(de->name,"."))
 400                 goto bad_dir;
 401         de = (struct minix_dir_entry *) (bh->b_data + info->s_dirsize);
 402         if (!de->inode || strcmp(de->name,".."))
 403                 goto bad_dir;
 404         while (block*BLOCK_SIZE+offset < inode->i_size) {
 405                 if (!bh) {
 406                         bh = minix_bread(inode,block,0);
 407                         if (!bh) {
 408                                 block++;
 409                                 continue;
 410                         }
 411                 }
 412                 de = (struct minix_dir_entry *) (bh->b_data + offset);
 413                 offset += info->s_dirsize;
 414                 if (de->inode) {
 415                         brelse(bh);
 416                         return 0;
 417                 }
 418                 if (offset < bh->b_size)
 419                         continue;
 420                 brelse(bh);
 421                 bh = NULL;
 422                 offset = 0;
 423                 block++;
 424         }
 425         brelse(bh);
 426         return 1;
 427 bad_dir:
 428         brelse(bh);
 429         printk("Bad directory on device %s\n",
 430                kdevname(inode->i_dev));
 431         return 1;
 432 }
 433 
 434 int minix_rmdir(struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 435 {
 436         int retval;
 437         struct inode * inode;
 438         struct buffer_head * bh;
 439         struct minix_dir_entry * de;
 440 
 441         inode = NULL;
 442         bh = minix_find_entry(dir,name,len,&de);
 443         retval = -ENOENT;
 444         if (!bh)
 445                 goto end_rmdir;
 446         retval = -EPERM;
 447         if (!(inode = iget(dir->i_sb, de->inode)))
 448                 goto end_rmdir;
 449         if ((dir->i_mode & S_ISVTX) && !fsuser() &&
 450             current->fsuid != inode->i_uid &&
 451             current->fsuid != dir->i_uid)
 452                 goto end_rmdir;
 453         if (inode->i_dev != dir->i_dev)
 454                 goto end_rmdir;
 455         if (inode == dir)       /* we may not delete ".", but "../dir" is ok */
 456                 goto end_rmdir;
 457         if (!S_ISDIR(inode->i_mode)) {
 458                 retval = -ENOTDIR;
 459                 goto end_rmdir;
 460         }
 461         if (!empty_dir(inode)) {
 462                 retval = -ENOTEMPTY;
 463                 goto end_rmdir;
 464         }
 465         if (de->inode != inode->i_ino) {
 466                 retval = -ENOENT;
 467                 goto end_rmdir;
 468         }
 469         if (inode->i_count > 1) {
 470                 retval = -EBUSY;
 471                 goto end_rmdir;
 472         }
 473         if (inode->i_nlink != 2)
 474                 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
 475         de->inode = 0;
 476         dir->i_version = ++event;
 477         mark_buffer_dirty(bh, 1);
 478         inode->i_nlink=0;
 479         inode->i_dirt=1;
 480         inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 481         dir->i_nlink--;
 482         dir->i_dirt=1;
 483         retval = 0;
 484 end_rmdir:
 485         iput(dir);
 486         iput(inode);
 487         brelse(bh);
 488         return retval;
 489 }
 490 
 491 int minix_unlink(struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 492 {
 493         int retval;
 494         struct inode * inode;
 495         struct buffer_head * bh;
 496         struct minix_dir_entry * de;
 497 
 498 repeat:
 499         retval = -ENOENT;
 500         inode = NULL;
 501         bh = minix_find_entry(dir,name,len,&de);
 502         if (!bh)
 503                 goto end_unlink;
 504         if (!(inode = iget(dir->i_sb, de->inode)))
 505                 goto end_unlink;
 506         retval = -EPERM;
 507         if (S_ISDIR(inode->i_mode))
 508                 goto end_unlink;
 509         if (de->inode != inode->i_ino) {
 510                 iput(inode);
 511                 brelse(bh);
 512                 current->counter = 0;
 513                 schedule();
 514                 goto repeat;
 515         }
 516         if ((dir->i_mode & S_ISVTX) && !fsuser() &&
 517             current->fsuid != inode->i_uid &&
 518             current->fsuid != dir->i_uid)
 519                 goto end_unlink;
 520         if (de->inode != inode->i_ino) {
 521                 retval = -ENOENT;
 522                 goto end_unlink;
 523         }
 524         if (!inode->i_nlink) {
 525                 printk("Deleting nonexistent file (%s:%lu), %d\n",
 526                         kdevname(inode->i_dev),
 527                        inode->i_ino, inode->i_nlink);
 528                 inode->i_nlink=1;
 529         }
 530         de->inode = 0;
 531         dir->i_version = ++event;
 532         mark_buffer_dirty(bh, 1);
 533         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 534         dir->i_dirt = 1;
 535         inode->i_nlink--;
 536         inode->i_ctime = dir->i_ctime;
 537         inode->i_dirt = 1;
 538         retval = 0;
 539 end_unlink:
 540         brelse(bh);
 541         iput(inode);
 542         iput(dir);
 543         return retval;
 544 }
 545 
 546 int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
     /* [previous][next][first][last][top][bottom][index][help] */
 547 {
 548         struct minix_dir_entry * de;
 549         struct inode * inode = NULL;
 550         struct buffer_head * bh = NULL, * name_block = NULL;
 551         int i;
 552         char c;
 553 
 554         if (!(inode = minix_new_inode(dir))) {
 555                 iput(dir);
 556                 return -ENOSPC;
 557         }
 558         inode->i_mode = S_IFLNK | 0777;
 559         inode->i_op = &minix_symlink_inode_operations;
 560         name_block = minix_bread(inode,0,1);
 561         if (!name_block) {
 562                 iput(dir);
 563                 inode->i_nlink--;
 564                 inode->i_dirt = 1;
 565                 iput(inode);
 566                 return -ENOSPC;
 567         }
 568         i = 0;
 569         while (i < 1023 && (c=*(symname++)))
 570                 name_block->b_data[i++] = c;
 571         name_block->b_data[i] = 0;
 572         mark_buffer_dirty(name_block, 1);
 573         brelse(name_block);
 574         inode->i_size = i;
 575         inode->i_dirt = 1;
 576         bh = minix_find_entry(dir,name,len,&de);
 577         if (bh) {
 578                 inode->i_nlink--;
 579                 inode->i_dirt = 1;
 580                 iput(inode);
 581                 brelse(bh);
 582                 iput(dir);
 583                 return -EEXIST;
 584         }
 585         i = minix_add_entry(dir, name, len, &bh, &de);
 586         if (i) {
 587                 inode->i_nlink--;
 588                 inode->i_dirt = 1;
 589                 iput(inode);
 590                 iput(dir);
 591                 return i;
 592         }
 593         de->inode = inode->i_ino;
 594         mark_buffer_dirty(bh, 1);
 595         brelse(bh);
 596         iput(dir);
 597         iput(inode);
 598         return 0;
 599 }
 600 
 601 int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 602 {
 603         int error;
 604         struct minix_dir_entry * de;
 605         struct buffer_head * bh;
 606 
 607         if (S_ISDIR(oldinode->i_mode)) {
 608                 iput(oldinode);
 609                 iput(dir);
 610                 return -EPERM;
 611         }
 612         if (oldinode->i_nlink >= MINIX_LINK_MAX) {
 613                 iput(oldinode);
 614                 iput(dir);
 615                 return -EMLINK;
 616         }
 617         bh = minix_find_entry(dir,name,len,&de);
 618         if (bh) {
 619                 brelse(bh);
 620                 iput(dir);
 621                 iput(oldinode);
 622                 return -EEXIST;
 623         }
 624         error = minix_add_entry(dir, name, len, &bh, &de);
 625         if (error) {
 626                 iput(dir);
 627                 iput(oldinode);
 628                 return error;
 629         }
 630         de->inode = oldinode->i_ino;
 631         mark_buffer_dirty(bh, 1);
 632         brelse(bh);
 633         iput(dir);
 634         oldinode->i_nlink++;
 635         oldinode->i_ctime = CURRENT_TIME;
 636         oldinode->i_dirt = 1;
 637         iput(oldinode);
 638         return 0;
 639 }
 640 
 641 static int subdir(struct inode * new_inode, struct inode * old_inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 642 {
 643         int ino;
 644         int result;
 645 
 646         new_inode->i_count++;
 647         result = 0;
 648         for (;;) {
 649                 if (new_inode == old_inode) {
 650                         result = 1;
 651                         break;
 652                 }
 653                 if (new_inode->i_dev != old_inode->i_dev)
 654                         break;
 655                 ino = new_inode->i_ino;
 656                 if (minix_lookup(new_inode,"..",2,&new_inode))
 657                         break;
 658                 if (new_inode->i_ino == ino)
 659                         break;
 660         }
 661         iput(new_inode);
 662         return result;
 663 }
 664 
 665 #define PARENT_INO(buffer) \
 666 (((struct minix_dir_entry *) ((buffer)+info->s_dirsize))->inode)
 667 
 668 /*
 669  * rename uses retrying to avoid race-conditions: at least they should be minimal.
 670  * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
 671  * checks fail, it tries to restart itself again. Very practical - no changes
 672  * are done until we know everything works ok.. and then all the changes can be
 673  * done in one fell swoop when we have claimed all the buffers needed.
 674  *
 675  * Anybody can rename anything with this: the permission checks are left to the
 676  * higher-level routines.
 677  */
 678 static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 679         struct inode * new_dir, const char * new_name, int new_len)
 680 {
 681         struct inode * old_inode, * new_inode;
 682         struct buffer_head * old_bh, * new_bh, * dir_bh;
 683         struct minix_dir_entry * old_de, * new_de;
 684         struct minix_sb_info * info;
 685         int retval;
 686 
 687         info = &old_dir->i_sb->u.minix_sb;
 688         goto start_up;
 689 try_again:
 690         brelse(old_bh);
 691         brelse(new_bh);
 692         brelse(dir_bh);
 693         iput(old_inode);
 694         iput(new_inode);
 695         current->counter = 0;
 696         schedule();
 697 start_up:
 698         old_inode = new_inode = NULL;
 699         old_bh = new_bh = dir_bh = NULL;
 700         old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
 701         retval = -ENOENT;
 702         if (!old_bh)
 703                 goto end_rename;
 704         old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */
 705         if (!old_inode)
 706                 goto end_rename;
 707         retval = -EPERM;
 708         if ((old_dir->i_mode & S_ISVTX) && 
 709             current->fsuid != old_inode->i_uid &&
 710             current->fsuid != old_dir->i_uid && !fsuser())
 711                 goto end_rename;
 712         new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
 713         if (new_bh) {
 714                 new_inode = __iget(new_dir->i_sb, new_de->inode, 0);
 715                 if (!new_inode) {
 716                         brelse(new_bh);
 717                         new_bh = NULL;
 718                 }
 719         }
 720         if (new_inode == old_inode) {
 721                 retval = 0;
 722                 goto end_rename;
 723         }
 724         if (new_inode && S_ISDIR(new_inode->i_mode)) {
 725                 retval = -EISDIR;
 726                 if (!S_ISDIR(old_inode->i_mode))
 727                         goto end_rename;
 728                 retval = -EINVAL;
 729                 if (subdir(new_dir, old_inode))
 730                         goto end_rename;
 731                 retval = -ENOTEMPTY;
 732                 if (!empty_dir(new_inode))
 733                         goto end_rename;
 734                 retval = -EBUSY;
 735                 if (new_inode->i_count > 1)
 736                         goto end_rename;
 737         }
 738         retval = -EPERM;
 739         if (new_inode && (new_dir->i_mode & S_ISVTX) && 
 740             current->fsuid != new_inode->i_uid &&
 741             current->fsuid != new_dir->i_uid && !fsuser())
 742                 goto end_rename;
 743         if (S_ISDIR(old_inode->i_mode)) {
 744                 retval = -ENOTDIR;
 745                 if (new_inode && !S_ISDIR(new_inode->i_mode))
 746                         goto end_rename;
 747                 retval = -EINVAL;
 748                 if (subdir(new_dir, old_inode))
 749                         goto end_rename;
 750                 retval = -EIO;
 751                 dir_bh = minix_bread(old_inode,0,0);
 752                 if (!dir_bh)
 753                         goto end_rename;
 754                 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
 755                         goto end_rename;
 756                 retval = -EMLINK;
 757                 if (!new_inode && new_dir->i_nlink >= MINIX_LINK_MAX)
 758                         goto end_rename;
 759         }
 760         if (!new_bh) {
 761                 retval = minix_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
 762                 if (retval)
 763                         goto end_rename;
 764         }
 765 /* sanity checking before doing the rename - avoid races */
 766         if (new_inode && (new_de->inode != new_inode->i_ino))
 767                 goto try_again;
 768         if (new_de->inode && !new_inode)
 769                 goto try_again;
 770         if (old_de->inode != old_inode->i_ino)
 771                 goto try_again;
 772 /* ok, that's it */
 773         old_de->inode = 0;
 774         new_de->inode = old_inode->i_ino;
 775         old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 776         old_dir->i_dirt = 1;
 777         old_dir->i_version = ++event;
 778         new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
 779         new_dir->i_dirt = 1;
 780         new_dir->i_version = ++event;
 781         if (new_inode) {
 782                 new_inode->i_nlink--;
 783                 new_inode->i_ctime = CURRENT_TIME;
 784                 new_inode->i_dirt = 1;
 785         }
 786         mark_buffer_dirty(old_bh, 1);
 787         mark_buffer_dirty(new_bh, 1);
 788         if (dir_bh) {
 789                 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
 790                 mark_buffer_dirty(dir_bh, 1);
 791                 old_dir->i_nlink--;
 792                 old_dir->i_dirt = 1;
 793                 if (new_inode) {
 794                         new_inode->i_nlink--;
 795                         new_inode->i_dirt = 1;
 796                 } else {
 797                         new_dir->i_nlink++;
 798                         new_dir->i_dirt = 1;
 799                 }
 800         }
 801         retval = 0;
 802 end_rename:
 803         brelse(dir_bh);
 804         brelse(old_bh);
 805         brelse(new_bh);
 806         iput(old_inode);
 807         iput(new_inode);
 808         iput(old_dir);
 809         iput(new_dir);
 810         return retval;
 811 }
 812 
 813 /*
 814  * Ok, rename also locks out other renames, as they can change the parent of
 815  * a directory, and we don't want any races. Other races are checked for by
 816  * "do_rename()", which restarts if there are inconsistencies.
 817  *
 818  * Note that there is no race between different filesystems: it's only within
 819  * the same device that races occur: many renames can happen at once, as long
 820  * as they are on different partitions.
 821  */
 822 int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 823         struct inode * new_dir, const char * new_name, int new_len)
 824 {
 825         static struct wait_queue * wait = NULL;
 826         static int lock = 0;
 827         int result;
 828 
 829         while (lock)
 830                 sleep_on(&wait);
 831         lock = 1;
 832         result = do_minix_rename(old_dir, old_name, old_len,
 833                 new_dir, new_name, new_len);
 834         lock = 0;
 835         wake_up(&wait);
 836         return result;
 837 }

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