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_sb,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  * Arggh. To avoid race-conditions, we copy the name into kernel
 141  * space before actually writing it into the buffer...
 142  */
 143 static struct buffer_head * minix_add_entry(struct inode * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
 144         const char * name, int namelen, struct minix_dir_entry ** res_dir)
 145 {
 146         int i;
 147         struct buffer_head * bh;
 148         struct minix_dir_entry * de;
 149         char name_buffer[MINIX_NAME_LEN];
 150 
 151         *res_dir = NULL;
 152         if (!dir)
 153                 return NULL;
 154         if (namelen > MINIX_NAME_LEN) {
 155 #ifdef NO_TRUNCATE
 156                 return NULL;
 157 #else
 158                 namelen = MINIX_NAME_LEN;
 159 #endif
 160         }
 161         if (!namelen)
 162                 return NULL;
 163         bh =  minix_bread(dir,0,0);
 164         if (!bh)
 165                 return NULL;
 166         for (i = 0; i < MINIX_NAME_LEN ; i++)
 167                 name_buffer[i] = (i<namelen) ? get_fs_byte(name+i) : 0;
 168         i = 0;
 169         de = (struct minix_dir_entry *) bh->b_data;
 170         while (1) {
 171                 if ((char *)de >= BLOCK_SIZE+bh->b_data) {
 172                         brelse(bh);
 173                         bh = minix_bread(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK,1);
 174                         if (!bh)
 175                                 return NULL;
 176                         de = (struct minix_dir_entry *) bh->b_data;
 177                 }
 178                 if (i*sizeof(struct minix_dir_entry) >= dir->i_size) {
 179                         de->inode=0;
 180                         dir->i_size = (i+1)*sizeof(struct minix_dir_entry);
 181                         dir->i_dirt = 1;
 182                         dir->i_ctime = CURRENT_TIME;
 183                 }
 184                 if (!de->inode) {
 185                         dir->i_mtime = CURRENT_TIME;
 186                         memcpy(de->name,name_buffer,MINIX_NAME_LEN);
 187                         bh->b_dirt = 1;
 188                         *res_dir = de;
 189                         return bh;
 190                 }
 191                 de++;
 192                 i++;
 193         }
 194         brelse(bh);
 195         return NULL;
 196 }
 197 
 198 int minix_create(struct inode * dir,const char * name, int len, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 199         struct inode ** result)
 200 {
 201         struct inode * inode;
 202         struct buffer_head * bh;
 203         struct minix_dir_entry * de;
 204 
 205         *result = NULL;
 206         if (!dir)
 207                 return -ENOENT;
 208         inode = minix_new_inode(dir);
 209         if (!inode) {
 210                 iput(dir);
 211                 return -ENOSPC;
 212         }
 213         inode->i_op = &minix_file_inode_operations;
 214         inode->i_mode = mode;
 215         inode->i_dirt = 1;
 216         bh = minix_add_entry(dir,name,len,&de);
 217         if (!bh) {
 218                 inode->i_nlink--;
 219                 inode->i_dirt = 1;
 220                 iput(inode);
 221                 iput(dir);
 222                 return -ENOSPC;
 223         }
 224         de->inode = inode->i_ino;
 225         bh->b_dirt = 1;
 226         brelse(bh);
 227         iput(dir);
 228         *result = inode;
 229         return 0;
 230 }
 231 
 232 int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         struct inode * inode;
 235         struct buffer_head * bh;
 236         struct minix_dir_entry * de;
 237 
 238         if (!dir)
 239                 return -ENOENT;
 240         bh = minix_find_entry(dir,name,len,&de);
 241         if (bh) {
 242                 brelse(bh);
 243                 iput(dir);
 244                 return -EEXIST;
 245         }
 246         inode = minix_new_inode(dir);
 247         if (!inode) {
 248                 iput(dir);
 249                 return -ENOSPC;
 250         }
 251         inode->i_uid = current->euid;
 252         inode->i_mode = mode;
 253         inode->i_op = NULL;
 254         if (S_ISREG(inode->i_mode))
 255                 inode->i_op = &minix_file_inode_operations;
 256         else if (S_ISDIR(inode->i_mode)) {
 257                 inode->i_op = &minix_dir_inode_operations;
 258                 if (dir->i_mode & S_ISGID)
 259                         inode->i_mode |= S_ISGID;
 260         }
 261         else if (S_ISLNK(inode->i_mode))
 262                 inode->i_op = &minix_symlink_inode_operations;
 263         else if (S_ISCHR(inode->i_mode))
 264                 inode->i_op = &minix_chrdev_inode_operations;
 265         else if (S_ISBLK(inode->i_mode))
 266                 inode->i_op = &minix_blkdev_inode_operations;
 267         else if (S_ISFIFO(inode->i_mode)) {
 268                 inode->i_op = &minix_fifo_inode_operations;
 269                 inode->i_pipe = 1;
 270                 PIPE_BASE(*inode) = NULL;
 271                 PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
 272                 PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
 273                 PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
 274         }
 275         if (S_ISBLK(mode) || S_ISCHR(mode))
 276                 inode->i_rdev = rdev;
 277         inode->i_mtime = inode->i_atime = CURRENT_TIME;
 278         inode->i_dirt = 1;
 279         bh = minix_add_entry(dir,name,len,&de);
 280         if (!bh) {
 281                 inode->i_nlink--;
 282                 inode->i_dirt = 1;
 283                 iput(inode);
 284                 iput(dir);
 285                 return -ENOSPC;
 286         }
 287         de->inode = inode->i_ino;
 288         bh->b_dirt = 1;
 289         brelse(bh);
 290         iput(dir);
 291         iput(inode);
 292         return 0;
 293 }
 294 
 295 int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 296 {
 297         struct inode * inode;
 298         struct buffer_head * bh, *dir_block;
 299         struct minix_dir_entry * de;
 300         
 301         bh = minix_find_entry(dir,name,len,&de);
 302         if (bh) {
 303                 brelse(bh);
 304                 iput(dir);
 305                 return -EEXIST;
 306         }
 307         if (dir->i_nlink > 250) {
 308                 iput(dir);
 309                 return -EMLINK;
 310         }
 311         inode = minix_new_inode(dir);
 312         if (!inode) {
 313                 iput(dir);
 314                 return -ENOSPC;
 315         }
 316         inode->i_op = &minix_dir_inode_operations;
 317         inode->i_size = 2 * sizeof (struct minix_dir_entry);
 318         inode->i_mtime = inode->i_atime = CURRENT_TIME;
 319         dir_block = minix_bread(inode,0,1);
 320         if (!dir_block) {
 321                 iput(dir);
 322                 inode->i_nlink--;
 323                 inode->i_dirt = 1;
 324                 iput(inode);
 325                 return -ENOSPC;
 326         }
 327         de = (struct minix_dir_entry *) dir_block->b_data;
 328         de->inode=inode->i_ino;
 329         strcpy(de->name,".");
 330         de++;
 331         de->inode = dir->i_ino;
 332         strcpy(de->name,"..");
 333         inode->i_nlink = 2;
 334         dir_block->b_dirt = 1;
 335         brelse(dir_block);
 336         inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask);
 337         if (dir->i_mode & S_ISGID)
 338                 inode->i_mode |= S_ISGID;
 339         inode->i_dirt = 1;
 340         bh = minix_add_entry(dir,name,len,&de);
 341         if (!bh) {
 342                 iput(dir);
 343                 inode->i_nlink=0;
 344                 iput(inode);
 345                 return -ENOSPC;
 346         }
 347         de->inode = inode->i_ino;
 348         bh->b_dirt = 1;
 349         dir->i_nlink++;
 350         dir->i_dirt = 1;
 351         iput(dir);
 352         iput(inode);
 353         brelse(bh);
 354         return 0;
 355 }
 356 
 357 /*
 358  * routine to check that the specified directory is empty (for rmdir)
 359  */
 360 static int empty_dir(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 361 {
 362         int nr, len;
 363         struct buffer_head * bh;
 364         struct minix_dir_entry * de;
 365 
 366         len = inode->i_size / sizeof (struct minix_dir_entry);
 367         if (len<2 || !(bh = minix_bread(inode,0,0))) {
 368                 printk("warning - bad directory on dev %04x\n",inode->i_dev);
 369                 return 1;
 370         }
 371         de = (struct minix_dir_entry *) bh->b_data;
 372         if (de[0].inode != inode->i_ino || !de[1].inode || 
 373             strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
 374                 printk("warning - bad directory on dev %04x\n",inode->i_dev);
 375                 return 1;
 376         }
 377         nr = 2;
 378         de += 2;
 379         while (nr<len) {
 380                 if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
 381                         brelse(bh);
 382                         bh = minix_bread(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK,0);
 383                         if (!bh) {
 384                                 nr += MINIX_DIR_ENTRIES_PER_BLOCK;
 385                                 continue;
 386                         }
 387                         de = (struct minix_dir_entry *) bh->b_data;
 388                 }
 389                 if (de->inode) {
 390                         brelse(bh);
 391                         return 0;
 392                 }
 393                 de++;
 394                 nr++;
 395         }
 396         brelse(bh);
 397         return 1;
 398 }
 399 
 400 int minix_rmdir(struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 401 {
 402         int retval;
 403         struct inode * inode;
 404         struct buffer_head * bh;
 405         struct minix_dir_entry * de;
 406 
 407         inode = NULL;
 408         bh = minix_find_entry(dir,name,len,&de);
 409         retval = -ENOENT;
 410         if (!bh)
 411                 goto end_rmdir;
 412         retval = -EPERM;
 413         if (!(inode = iget(dir->i_sb, de->inode)))
 414                 goto end_rmdir;
 415         if ((dir->i_mode & S_ISVTX) && current->euid &&
 416            inode->i_uid != current->euid)
 417                 goto end_rmdir;
 418         if (inode->i_dev != dir->i_dev)
 419                 goto end_rmdir;
 420         if (inode == dir)       /* we may not delete ".", but "../dir" is ok */
 421                 goto end_rmdir;
 422         if (!S_ISDIR(inode->i_mode)) {
 423                 retval = -ENOTDIR;
 424                 goto end_rmdir;
 425         }
 426         if (!empty_dir(inode)) {
 427                 retval = -ENOTEMPTY;
 428                 goto end_rmdir;
 429         }
 430         if (inode->i_count > 1) {
 431                 retval = -EBUSY;
 432                 goto end_rmdir;
 433         }
 434         if (inode->i_nlink != 2)
 435                 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
 436         de->inode = 0;
 437         bh->b_dirt = 1;
 438         inode->i_nlink=0;
 439         inode->i_dirt=1;
 440         dir->i_nlink--;
 441         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 442         dir->i_dirt=1;
 443         retval = 0;
 444 end_rmdir:
 445         iput(dir);
 446         iput(inode);
 447         brelse(bh);
 448         return retval;
 449 }
 450 
 451 int minix_unlink(struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 452 {
 453         int retval;
 454         struct inode * inode;
 455         struct buffer_head * bh;
 456         struct minix_dir_entry * de;
 457 
 458 repeat:
 459         retval = -ENOENT;
 460         inode = NULL;
 461         bh = minix_find_entry(dir,name,len,&de);
 462         if (!bh)
 463                 goto end_unlink;
 464         if (!(inode = iget(dir->i_sb, de->inode)))
 465                 goto end_unlink;
 466         if (de->inode != inode->i_ino) {
 467                 iput(inode);
 468                 brelse(bh);
 469                 current->counter = 0;
 470                 schedule();
 471                 goto repeat;
 472         }
 473         retval = -EPERM;
 474         if ((dir->i_mode & S_ISVTX) && !suser() &&
 475             current->euid != inode->i_uid &&
 476             current->euid != dir->i_uid)
 477                 goto end_unlink;
 478         if (S_ISDIR(inode->i_mode))
 479                 goto end_unlink;
 480         if (!inode->i_nlink) {
 481                 printk("Deleting nonexistent file (%04x:%d), %d\n",
 482                         inode->i_dev,inode->i_ino,inode->i_nlink);
 483                 inode->i_nlink=1;
 484         }
 485         de->inode = 0;
 486         bh->b_dirt = 1;
 487         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 488         dir->i_dirt = 1;
 489         inode->i_nlink--;
 490         inode->i_ctime = CURRENT_TIME;
 491         inode->i_dirt = 1;
 492         retval = 0;
 493 end_unlink:
 494         brelse(bh);
 495         iput(inode);
 496         iput(dir);
 497         return retval;
 498 }
 499 
 500 int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
     /* [previous][next][first][last][top][bottom][index][help] */
 501 {
 502         struct minix_dir_entry * de;
 503         struct inode * inode = NULL;
 504         struct buffer_head * bh = NULL, * name_block = NULL;
 505         int i;
 506         char c;
 507 
 508         if (!(inode = minix_new_inode(dir))) {
 509                 iput(dir);
 510                 return -ENOSPC;
 511         }
 512         inode->i_mode = S_IFLNK | 0777;
 513         inode->i_op = &minix_symlink_inode_operations;
 514         name_block = minix_bread(inode,0,1);
 515         if (!name_block) {
 516                 iput(dir);
 517                 inode->i_nlink--;
 518                 inode->i_dirt = 1;
 519                 iput(inode);
 520                 return -ENOSPC;
 521         }
 522         i = 0;
 523         while (i < 1023 && (c=get_fs_byte(symname++)))
 524                 name_block->b_data[i++] = c;
 525         name_block->b_data[i] = 0;
 526         name_block->b_dirt = 1;
 527         brelse(name_block);
 528         inode->i_size = i;
 529         inode->i_dirt = 1;
 530         bh = minix_find_entry(dir,name,len,&de);
 531         if (bh) {
 532                 inode->i_nlink--;
 533                 inode->i_dirt = 1;
 534                 iput(inode);
 535                 brelse(bh);
 536                 iput(dir);
 537                 return -EEXIST;
 538         }
 539         bh = minix_add_entry(dir,name,len,&de);
 540         if (!bh) {
 541                 inode->i_nlink--;
 542                 inode->i_dirt = 1;
 543                 iput(inode);
 544                 iput(dir);
 545                 return -ENOSPC;
 546         }
 547         de->inode = inode->i_ino;
 548         bh->b_dirt = 1;
 549         brelse(bh);
 550         iput(dir);
 551         iput(inode);
 552         return 0;
 553 }
 554 
 555 int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 556 {
 557         struct minix_dir_entry * de;
 558         struct buffer_head * bh;
 559 
 560         if (S_ISDIR(oldinode->i_mode)) {
 561                 iput(oldinode);
 562                 iput(dir);
 563                 return -EPERM;
 564         }
 565         if (oldinode->i_nlink > 126) {
 566                 iput(oldinode);
 567                 iput(dir);
 568                 return -EMLINK;
 569         }
 570         bh = minix_find_entry(dir,name,len,&de);
 571         if (bh) {
 572                 brelse(bh);
 573                 iput(dir);
 574                 iput(oldinode);
 575                 return -EEXIST;
 576         }
 577         bh = minix_add_entry(dir,name,len,&de);
 578         if (!bh) {
 579                 iput(dir);
 580                 iput(oldinode);
 581                 return -ENOSPC;
 582         }
 583         de->inode = oldinode->i_ino;
 584         bh->b_dirt = 1;
 585         brelse(bh);
 586         iput(dir);
 587         oldinode->i_nlink++;
 588         oldinode->i_ctime = CURRENT_TIME;
 589         oldinode->i_dirt = 1;
 590         iput(oldinode);
 591         return 0;
 592 }
 593 
 594 static int subdir(struct inode * new, struct inode * old)
     /* [previous][next][first][last][top][bottom][index][help] */
 595 {
 596         unsigned short fs;
 597         int ino;
 598         int result;
 599 
 600         __asm__("mov %%fs,%0":"=r" (fs));
 601         __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
 602         new->i_count++;
 603         result = 0;
 604         for (;;) {
 605                 if (new == old) {
 606                         result = 1;
 607                         break;
 608                 }
 609                 if (new->i_dev != old->i_dev)
 610                         break;
 611                 ino = new->i_ino;
 612                 if (minix_lookup(new,"..",2,&new))
 613                         break;
 614                 if (new->i_ino == ino)
 615                         break;
 616         }
 617         iput(new);
 618         __asm__("mov %0,%%fs"::"r" (fs));
 619         return result;
 620 }
 621 
 622 #define PARENT_INO(buffer) \
 623 (((struct minix_dir_entry *) (buffer))[1].inode)
 624 
 625 #define PARENT_NAME(buffer) \
 626 (((struct minix_dir_entry *) (buffer))[1].name)
 627 
 628 /*
 629  * rename uses retrying to avoid race-conditions: at least they should be minimal.
 630  * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
 631  * checks fail, it tries to restart itself again. Very practical - no changes
 632  * are done until we know everything works ok.. and then all the changes can be
 633  * done in one fell swoop when we have claimed all the buffers needed.
 634  *
 635  * Anybody can rename anything with this: the permission checks are left to the
 636  * higher-level routines.
 637  */
 638 static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 639         struct inode * new_dir, const char * new_name, int new_len)
 640 {
 641         struct inode * old_inode, * new_inode;
 642         struct buffer_head * old_bh, * new_bh, * dir_bh;
 643         struct minix_dir_entry * old_de, * new_de;
 644         int retval;
 645 
 646         goto start_up;
 647 try_again:
 648         brelse(old_bh);
 649         brelse(new_bh);
 650         brelse(dir_bh);
 651         iput(old_inode);
 652         iput(new_inode);
 653         current->counter = 0;
 654         schedule();
 655 start_up:
 656         old_inode = new_inode = NULL;
 657         old_bh = new_bh = dir_bh = NULL;
 658         old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
 659         retval = -ENOENT;
 660         if (!old_bh)
 661                 goto end_rename;
 662         old_inode = iget(old_dir->i_sb, old_de->inode);
 663         if (!old_inode)
 664                 goto end_rename;
 665         retval = -EPERM;
 666         if ((old_dir->i_mode & S_ISVTX) && 
 667             current->euid != old_inode->i_uid &&
 668             current->euid != old_dir->i_uid && !suser())
 669                 goto end_rename;
 670         new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
 671         if (new_bh) {
 672                 new_inode = iget(new_dir->i_sb, new_de->inode);
 673                 if (!new_inode) {
 674                         brelse(new_bh);
 675                         new_bh = NULL;
 676                 }
 677         }
 678         if (new_inode == old_inode) {
 679                 retval = 0;
 680                 goto end_rename;
 681         }
 682         if (new_inode && S_ISDIR(new_inode->i_mode)) {
 683                 retval = -EEXIST;
 684                 goto end_rename;
 685         }
 686         retval = -EPERM;
 687         if (new_inode && (new_dir->i_mode & S_ISVTX) && 
 688             current->euid != new_inode->i_uid &&
 689             current->euid != new_dir->i_uid && !suser())
 690                 goto end_rename;
 691         if (S_ISDIR(old_inode->i_mode)) {
 692                 retval = -EEXIST;
 693                 if (new_bh)
 694                         goto end_rename;
 695                 retval = -EACCES;
 696                 if (!permission(old_inode, MAY_WRITE))
 697                         goto end_rename;
 698                 retval = -EINVAL;
 699                 if (subdir(new_dir, old_inode))
 700                         goto end_rename;
 701                 retval = -EIO;
 702                 dir_bh = minix_bread(old_inode,0,0);
 703                 if (!dir_bh)
 704                         goto end_rename;
 705                 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
 706                         goto end_rename;
 707                 retval = -EMLINK;
 708                 if (new_dir->i_nlink > 250)
 709                         goto end_rename;
 710         }
 711         if (!new_bh)
 712                 new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de);
 713         retval = -ENOSPC;
 714         if (!new_bh)
 715                 goto end_rename;
 716 /* sanity checking before doing the rename - avoid races */
 717         if (new_inode && (new_de->inode != new_inode->i_ino))
 718                 goto try_again;
 719         if (new_de->inode && !new_inode)
 720                 goto try_again;
 721         if (old_de->inode != old_inode->i_ino)
 722                 goto try_again;
 723 /* ok, that's it */
 724         old_de->inode = 0;
 725         new_de->inode = old_inode->i_ino;
 726         if (new_inode) {
 727                 new_inode->i_nlink--;
 728                 new_inode->i_dirt = 1;
 729         }
 730         old_bh->b_dirt = 1;
 731         new_bh->b_dirt = 1;
 732         if (dir_bh) {
 733                 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
 734                 dir_bh->b_dirt = 1;
 735                 old_dir->i_nlink--;
 736                 new_dir->i_nlink++;
 737                 old_dir->i_dirt = 1;
 738                 new_dir->i_dirt = 1;
 739         }
 740         retval = 0;
 741 end_rename:
 742         brelse(dir_bh);
 743         brelse(old_bh);
 744         brelse(new_bh);
 745         iput(old_inode);
 746         iput(new_inode);
 747         iput(old_dir);
 748         iput(new_dir);
 749         return retval;
 750 }
 751 
 752 /*
 753  * Ok, rename also locks out other renames, as they can change the parent of
 754  * a directory, and we don't want any races. Other races are checked for by
 755  * "do_rename()", which restarts if there are inconsistencies.
 756  *
 757  * Note that there is no race between different filesystems: it's only within
 758  * the same device that races occur: many renames can happen at once, as long
 759  * as they are on different partitions.
 760  */
 761 int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 762         struct inode * new_dir, const char * new_name, int new_len)
 763 {
 764         static struct wait_queue * wait = NULL;
 765         static int lock = 0;
 766         int result;
 767 
 768         while (lock)
 769                 sleep_on(&wait);
 770         lock = 1;
 771         result = do_minix_rename(old_dir, old_name, old_len,
 772                 new_dir, new_name, new_len);
 773         lock = 0;
 774         wake_up(&wait);
 775         return result;
 776 }

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