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         inode = minix_new_inode(dir);
 308         if (!inode) {
 309                 iput(dir);
 310                 return -ENOSPC;
 311         }
 312         inode->i_op = &minix_dir_inode_operations;
 313         inode->i_size = 2 * sizeof (struct minix_dir_entry);
 314         inode->i_mtime = inode->i_atime = CURRENT_TIME;
 315         dir_block = minix_bread(inode,0,1);
 316         if (!dir_block) {
 317                 iput(dir);
 318                 inode->i_nlink--;
 319                 inode->i_dirt = 1;
 320                 iput(inode);
 321                 return -ENOSPC;
 322         }
 323         de = (struct minix_dir_entry *) dir_block->b_data;
 324         de->inode=inode->i_ino;
 325         strcpy(de->name,".");
 326         de++;
 327         de->inode = dir->i_ino;
 328         strcpy(de->name,"..");
 329         inode->i_nlink = 2;
 330         dir_block->b_dirt = 1;
 331         brelse(dir_block);
 332         inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask);
 333         if (dir->i_mode & S_ISGID)
 334                 inode->i_mode |= S_ISGID;
 335         inode->i_dirt = 1;
 336         bh = minix_add_entry(dir,name,len,&de);
 337         if (!bh) {
 338                 iput(dir);
 339                 inode->i_nlink=0;
 340                 iput(inode);
 341                 return -ENOSPC;
 342         }
 343         de->inode = inode->i_ino;
 344         bh->b_dirt = 1;
 345         dir->i_nlink++;
 346         dir->i_dirt = 1;
 347         iput(dir);
 348         iput(inode);
 349         brelse(bh);
 350         return 0;
 351 }
 352 
 353 /*
 354  * routine to check that the specified directory is empty (for rmdir)
 355  */
 356 static int empty_dir(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 357 {
 358         int nr, len;
 359         struct buffer_head * bh;
 360         struct minix_dir_entry * de;
 361 
 362         len = inode->i_size / sizeof (struct minix_dir_entry);
 363         if (len<2 || !(bh = minix_bread(inode,0,0))) {
 364                 printk("warning - bad directory on dev %04x\n",inode->i_dev);
 365                 return 1;
 366         }
 367         de = (struct minix_dir_entry *) bh->b_data;
 368         if (de[0].inode != inode->i_ino || !de[1].inode || 
 369             strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
 370                 printk("warning - bad directory on dev %04x\n",inode->i_dev);
 371                 return 1;
 372         }
 373         nr = 2;
 374         de += 2;
 375         while (nr<len) {
 376                 if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
 377                         brelse(bh);
 378                         bh = minix_bread(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK,0);
 379                         if (!bh) {
 380                                 nr += MINIX_DIR_ENTRIES_PER_BLOCK;
 381                                 continue;
 382                         }
 383                         de = (struct minix_dir_entry *) bh->b_data;
 384                 }
 385                 if (de->inode) {
 386                         brelse(bh);
 387                         return 0;
 388                 }
 389                 de++;
 390                 nr++;
 391         }
 392         brelse(bh);
 393         return 1;
 394 }
 395 
 396 int minix_rmdir(struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 397 {
 398         int retval;
 399         struct inode * inode;
 400         struct buffer_head * bh;
 401         struct minix_dir_entry * de;
 402 
 403         inode = NULL;
 404         bh = minix_find_entry(dir,name,len,&de);
 405         retval = -ENOENT;
 406         if (!bh)
 407                 goto end_rmdir;
 408         retval = -EPERM;
 409         if (!(inode = iget(dir->i_sb, de->inode)))
 410                 goto end_rmdir;
 411         if ((dir->i_mode & S_ISVTX) && current->euid &&
 412            inode->i_uid != current->euid)
 413                 goto end_rmdir;
 414         if (inode->i_dev != dir->i_dev)
 415                 goto end_rmdir;
 416         if (inode == dir)       /* we may not delete ".", but "../dir" is ok */
 417                 goto end_rmdir;
 418         if (!S_ISDIR(inode->i_mode)) {
 419                 retval = -ENOTDIR;
 420                 goto end_rmdir;
 421         }
 422         if (!empty_dir(inode)) {
 423                 retval = -ENOTEMPTY;
 424                 goto end_rmdir;
 425         }
 426         if (inode->i_count > 1) {
 427                 retval = -EBUSY;
 428                 goto end_rmdir;
 429         }
 430         if (inode->i_nlink != 2)
 431                 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
 432         de->inode = 0;
 433         bh->b_dirt = 1;
 434         inode->i_nlink=0;
 435         inode->i_dirt=1;
 436         dir->i_nlink--;
 437         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 438         dir->i_dirt=1;
 439         retval = 0;
 440 end_rmdir:
 441         iput(dir);
 442         iput(inode);
 443         brelse(bh);
 444         return retval;
 445 }
 446 
 447 int minix_unlink(struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 448 {
 449         int retval;
 450         struct inode * inode;
 451         struct buffer_head * bh;
 452         struct minix_dir_entry * de;
 453 
 454 repeat:
 455         retval = -ENOENT;
 456         inode = NULL;
 457         bh = minix_find_entry(dir,name,len,&de);
 458         if (!bh)
 459                 goto end_unlink;
 460         if (!(inode = iget(dir->i_sb, de->inode)))
 461                 goto end_unlink;
 462         if (de->inode != inode->i_ino) {
 463                 iput(inode);
 464                 brelse(bh);
 465                 current->counter = 0;
 466                 schedule();
 467                 goto repeat;
 468         }
 469         retval = -EPERM;
 470         if ((dir->i_mode & S_ISVTX) && !suser() &&
 471             current->euid != inode->i_uid &&
 472             current->euid != dir->i_uid)
 473                 goto end_unlink;
 474         if (S_ISDIR(inode->i_mode))
 475                 goto end_unlink;
 476         if (!inode->i_nlink) {
 477                 printk("Deleting nonexistent file (%04x:%d), %d\n",
 478                         inode->i_dev,inode->i_ino,inode->i_nlink);
 479                 inode->i_nlink=1;
 480         }
 481         de->inode = 0;
 482         bh->b_dirt = 1;
 483         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 484         dir->i_dirt = 1;
 485         inode->i_nlink--;
 486         inode->i_ctime = CURRENT_TIME;
 487         inode->i_dirt = 1;
 488         retval = 0;
 489 end_unlink:
 490         brelse(bh);
 491         iput(inode);
 492         iput(dir);
 493         return retval;
 494 }
 495 
 496 int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
     /* [previous][next][first][last][top][bottom][index][help] */
 497 {
 498         struct minix_dir_entry * de;
 499         struct inode * inode = NULL;
 500         struct buffer_head * bh = NULL, * name_block = NULL;
 501         int i;
 502         char c;
 503 
 504         if (!(inode = minix_new_inode(dir))) {
 505                 iput(dir);
 506                 return -ENOSPC;
 507         }
 508         inode->i_mode = S_IFLNK | 0777;
 509         inode->i_op = &minix_symlink_inode_operations;
 510         name_block = minix_bread(inode,0,1);
 511         if (!name_block) {
 512                 iput(dir);
 513                 inode->i_nlink--;
 514                 inode->i_dirt = 1;
 515                 iput(inode);
 516                 return -ENOSPC;
 517         }
 518         i = 0;
 519         while (i < 1023 && (c=get_fs_byte(symname++)))
 520                 name_block->b_data[i++] = c;
 521         name_block->b_data[i] = 0;
 522         name_block->b_dirt = 1;
 523         brelse(name_block);
 524         inode->i_size = i;
 525         inode->i_dirt = 1;
 526         bh = minix_find_entry(dir,name,len,&de);
 527         if (bh) {
 528                 inode->i_nlink--;
 529                 inode->i_dirt = 1;
 530                 iput(inode);
 531                 brelse(bh);
 532                 iput(dir);
 533                 return -EEXIST;
 534         }
 535         bh = minix_add_entry(dir,name,len,&de);
 536         if (!bh) {
 537                 inode->i_nlink--;
 538                 inode->i_dirt = 1;
 539                 iput(inode);
 540                 iput(dir);
 541                 return -ENOSPC;
 542         }
 543         de->inode = inode->i_ino;
 544         bh->b_dirt = 1;
 545         brelse(bh);
 546         iput(dir);
 547         iput(inode);
 548         return 0;
 549 }
 550 
 551 int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 552 {
 553         struct minix_dir_entry * de;
 554         struct buffer_head * bh;
 555 
 556         if (S_ISDIR(oldinode->i_mode)) {
 557                 iput(oldinode);
 558                 iput(dir);
 559                 return -EPERM;
 560         }
 561         if (oldinode->i_nlink > 126) {
 562                 iput(oldinode);
 563                 iput(dir);
 564                 return -EMLINK;
 565         }
 566         bh = minix_find_entry(dir,name,len,&de);
 567         if (bh) {
 568                 brelse(bh);
 569                 iput(dir);
 570                 iput(oldinode);
 571                 return -EEXIST;
 572         }
 573         bh = minix_add_entry(dir,name,len,&de);
 574         if (!bh) {
 575                 iput(dir);
 576                 iput(oldinode);
 577                 return -ENOSPC;
 578         }
 579         de->inode = oldinode->i_ino;
 580         bh->b_dirt = 1;
 581         brelse(bh);
 582         iput(dir);
 583         oldinode->i_nlink++;
 584         oldinode->i_ctime = CURRENT_TIME;
 585         oldinode->i_dirt = 1;
 586         iput(oldinode);
 587         return 0;
 588 }
 589 
 590 static int subdir(struct inode * new, struct inode * old)
     /* [previous][next][first][last][top][bottom][index][help] */
 591 {
 592         unsigned short fs;
 593         int ino;
 594         int result;
 595 
 596         __asm__("mov %%fs,%0":"=r" (fs));
 597         __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
 598         new->i_count++;
 599         result = 0;
 600         for (;;) {
 601                 if (new == old) {
 602                         result = 1;
 603                         break;
 604                 }
 605                 if (new->i_dev != old->i_dev)
 606                         break;
 607                 ino = new->i_ino;
 608                 if (minix_lookup(new,"..",2,&new))
 609                         break;
 610                 if (new->i_ino == ino)
 611                         break;
 612         }
 613         iput(new);
 614         __asm__("mov %0,%%fs"::"r" (fs));
 615         return result;
 616 }
 617 
 618 #define PARENT_INO(buffer) \
 619 (((struct minix_dir_entry *) (buffer))[1].inode)
 620 
 621 #define PARENT_NAME(buffer) \
 622 (((struct minix_dir_entry *) (buffer))[1].name)
 623 
 624 /*
 625  * rename uses retrying to avoid race-conditions: at least they should be minimal.
 626  * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
 627  * checks fail, it tries to restart itself again. Very practical - no changes
 628  * are done until we know everything works ok.. and then all the changes can be
 629  * done in one fell swoop when we have claimed all the buffers needed.
 630  *
 631  * Anybody can rename anything with this: the permission checks are left to the
 632  * higher-level routines.
 633  */
 634 static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 635         struct inode * new_dir, const char * new_name, int new_len)
 636 {
 637         struct inode * old_inode, * new_inode;
 638         struct buffer_head * old_bh, * new_bh, * dir_bh;
 639         struct minix_dir_entry * old_de, * new_de;
 640         int retval;
 641 
 642         goto start_up;
 643 try_again:
 644         brelse(old_bh);
 645         brelse(new_bh);
 646         brelse(dir_bh);
 647         iput(old_inode);
 648         iput(new_inode);
 649         current->counter = 0;
 650         schedule();
 651 start_up:
 652         old_inode = new_inode = NULL;
 653         old_bh = new_bh = dir_bh = NULL;
 654         old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
 655         retval = -ENOENT;
 656         if (!old_bh)
 657                 goto end_rename;
 658         old_inode = iget(old_dir->i_sb, old_de->inode);
 659         if (!old_inode)
 660                 goto end_rename;
 661         retval = -EPERM;
 662         if ((old_dir->i_mode & S_ISVTX) && 
 663             current->euid != old_inode->i_uid &&
 664             current->euid != old_dir->i_uid && !suser())
 665                 goto end_rename;
 666         new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
 667         if (new_bh) {
 668                 new_inode = iget(new_dir->i_sb, new_de->inode);
 669                 if (!new_inode) {
 670                         brelse(new_bh);
 671                         new_bh = NULL;
 672                 }
 673         }
 674         if (new_inode == old_inode) {
 675                 retval = 0;
 676                 goto end_rename;
 677         }
 678         if (new_inode && S_ISDIR(new_inode->i_mode)) {
 679                 retval = -EEXIST;
 680                 goto end_rename;
 681         }
 682         if (S_ISDIR(old_inode->i_mode)) {
 683                 retval = -EEXIST;
 684                 if (new_bh)
 685                         goto end_rename;
 686                 retval = -EACCES;
 687                 if (!permission(old_inode, MAY_WRITE))
 688                         goto end_rename;
 689                 retval = -EINVAL;
 690                 if (subdir(new_dir, old_inode))
 691                         goto end_rename;
 692                 retval = -EIO;
 693                 dir_bh = minix_bread(old_inode,0,0);
 694                 if (!dir_bh)
 695                         goto end_rename;
 696                 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
 697                         goto end_rename;
 698         }
 699         if (!new_bh)
 700                 new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de);
 701         retval = -ENOSPC;
 702         if (!new_bh)
 703                 goto end_rename;
 704 /* sanity checking before doing the rename - avoid races */
 705         if (new_inode && (new_de->inode != new_inode->i_ino))
 706                 goto try_again;
 707         if (new_de->inode && !new_inode)
 708                 goto try_again;
 709         if (old_de->inode != old_inode->i_ino)
 710                 goto try_again;
 711 /* ok, that's it */
 712         old_de->inode = 0;
 713         new_de->inode = old_inode->i_ino;
 714         if (new_inode) {
 715                 new_inode->i_nlink--;
 716                 new_inode->i_dirt = 1;
 717         }
 718         old_bh->b_dirt = 1;
 719         new_bh->b_dirt = 1;
 720         if (dir_bh) {
 721                 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
 722                 dir_bh->b_dirt = 1;
 723                 old_dir->i_nlink--;
 724                 new_dir->i_nlink++;
 725                 old_dir->i_dirt = 1;
 726                 new_dir->i_dirt = 1;
 727         }
 728         retval = 0;
 729 end_rename:
 730         brelse(dir_bh);
 731         brelse(old_bh);
 732         brelse(new_bh);
 733         iput(old_inode);
 734         iput(new_inode);
 735         iput(old_dir);
 736         iput(new_dir);
 737         return retval;
 738 }
 739 
 740 /*
 741  * Ok, rename also locks out other renames, as they can change the parent of
 742  * a directory, and we don't want any races. Other races are checked for by
 743  * "do_rename()", which restarts if there are inconsistencies.
 744  *
 745  * Note that there is no race between different filesystems: it's only within
 746  * the same device that races occur: many renames can happen at once, as long
 747  * as they are on different partitions.
 748  */
 749 int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 750         struct inode * new_dir, const char * new_name, int new_len)
 751 {
 752         static struct wait_queue * wait = NULL;
 753         static int lock = 0;
 754         int result;
 755 
 756         while (lock)
 757                 sleep_on(&wait);
 758         lock = 1;
 759         result = do_minix_rename(old_dir, old_name, old_len,
 760                 new_dir, new_name, new_len);
 761         lock = 0;
 762         wake_up(&wait);
 763         return result;
 764 }

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