root/fs/minix/namei.c

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

DEFINITIONS

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

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