root/fs/ext2/namei.c

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

DEFINITIONS

This source file includes following definitions.
  1. ext2_match
  2. ext2_find_entry
  3. ext2_lookup
  4. ext2_add_entry
  5. ext2_delete_entry
  6. ext2_create
  7. ext2_mknod
  8. ext2_mkdir
  9. empty_dir
  10. ext2_rmdir
  11. ext2_unlink
  12. ext2_symlink
  13. ext2_link
  14. subdir
  15. do_ext2_rename
  16. ext2_rename

   1 /*
   2  *  linux/fs/ext2/namei.c
   3  *
   4  *  Copyright (C) 1992, 1993  Remy Card (card@masi.ibp.fr)
   5  *
   6  *  from
   7  *
   8  *  linux/fs/minix/namei.c
   9  *
  10  *  Copyright (C) 1991, 1992  Linus Torvalds
  11  */
  12 
  13 #include <linux/sched.h>
  14 #include <linux/ext2_fs.h>
  15 #include <linux/kernel.h>
  16 #include <linux/string.h>
  17 #include <linux/stat.h>
  18 #include <linux/fcntl.h>
  19 #include <linux/errno.h>
  20 
  21 #include <asm/segment.h>
  22 
  23 /*
  24  * comment out this line if you want names > EXT2_NAME_LEN chars to be
  25  * truncated. Else they will be disallowed.
  26  */
  27 /* #define NO_TRUNCATE */
  28 
  29 /*
  30  * ok, we cannot use strncmp, as the name is not in our data space.
  31  * Thus we'll have to use ext2_match. No big problem. ext2_match also makes
  32  * some sanity tests.
  33  *
  34  * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
  35  */
  36 static int ext2_match (int len, const char * name,
     /* [previous][next][first][last][top][bottom][index][help] */
  37                        struct ext2_dir_entry * de)
  38 {
  39         register int same __asm__("ax");
  40 
  41         if (!de || !de->inode || len > EXT2_NAME_LEN)
  42                 return 0;
  43         /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
  44         if (!len && (de->name[0] == '.') && (de->name[1] == '\0'))
  45                 return 1;
  46         if (len < EXT2_NAME_LEN && len != de->name_len)
  47                 return 0;
  48         __asm__("cld\n\t"
  49                 "repe ; cmpsb\n\t"
  50                 "setz %%al"
  51                 :"=a" (same)
  52                 :"0" (0), "S" ((long) name), "D" ((long) de->name), "c" (len)
  53                 :"cx", "di", "si");
  54         return same;
  55 }
  56 
  57 /*
  58  *      ext2_find_entry()
  59  *
  60  * finds an entry in the specified directory with the wanted name. It
  61  * returns the cache buffer in which the entry was found, and the entry
  62  * itself (as a parameter - res_dir). It does NOT read the inode of the
  63  * entry - you'll have to do that yourself if you want to.
  64  *
  65  * In the ext2 file system, this function also returns a pointer on the
  66  * previous directory entry because functions which remove directory
  67  * entries need it
  68  */
  69 static struct buffer_head * ext2_find_entry (struct inode * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
  70                                              const char * name, int namelen,
  71                                              struct ext2_dir_entry ** res_dir,
  72                                              struct ext2_dir_entry ** prev_dir)
  73 {
  74         long offset;
  75         struct buffer_head * bh;
  76         struct ext2_dir_entry * de;
  77         struct super_block * sb;
  78 
  79         *res_dir = NULL;
  80         if (!dir)
  81                 return NULL;
  82         sb = dir->i_sb;
  83 #ifdef NO_TRUNCATE
  84         if (namelen > EXT2_NAME_LEN)
  85                 return NULL;
  86 #else
  87         if (namelen > EXT2_NAME_LEN)
  88                 namelen = EXT2_NAME_LEN;
  89 #endif
  90         bh = ext2_bread (dir, 0, 0);
  91         if (!bh)
  92                 return NULL;
  93         if (prev_dir)
  94                 *prev_dir = NULL;
  95         offset = 0;
  96         de = (struct ext2_dir_entry *) bh->b_data;
  97         while (offset < dir->i_size) {
  98                 if ((char *)de >= sb->s_blocksize + bh->b_data) {
  99                         brelse (bh);
 100                         bh = NULL;
 101                         bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0);
 102                         if (!bh)
 103                                 continue;
 104                         de = (struct ext2_dir_entry *) bh->b_data;
 105                         if (prev_dir)
 106                                 *prev_dir = NULL;
 107                 }
 108                 if (! ext2_check_dir_entry ("ext2_find_entry", dir, de, bh,
 109                                             offset)) {
 110                         brelse (bh);
 111                         return NULL;
 112                 }
 113                 if (ext2_match (namelen, name, de)) {
 114                         *res_dir = de;
 115                         return bh;
 116                 }
 117                 offset += de->rec_len;
 118                 if (prev_dir)
 119                         *prev_dir = de;
 120                 de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
 121         }
 122         brelse (bh);
 123         return NULL;
 124 }
 125 
 126 int ext2_lookup (struct inode * dir, const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 127                  struct inode ** result)
 128 {
 129         int ino;
 130         struct ext2_dir_entry * de;
 131         struct buffer_head * bh;
 132 
 133         *result = NULL;
 134         if (!dir)
 135                 return -ENOENT;
 136         if (!S_ISDIR(dir->i_mode)) {
 137                 iput (dir);
 138                 return -ENOENT;
 139         }
 140 #ifndef DONT_USE_DCACHE
 141         if (!(ino = ext2_dcache_lookup (dir->i_dev, dir->i_ino, name, len))) {
 142 #endif
 143                 if (!(bh = ext2_find_entry (dir, name, len, &de, NULL))) {
 144                         iput (dir);
 145                         return -ENOENT;
 146                 }
 147                 ino = de->inode;
 148 #ifndef DONT_USE_DCACHE
 149                 ext2_dcache_add (dir->i_dev, dir->i_ino, de->name,
 150                                  de->name_len, ino);
 151 #endif
 152                 brelse (bh);
 153 #ifndef DONT_USE_DCACHE
 154         }
 155 #endif
 156         if (!(*result = iget (dir->i_sb, ino))) {
 157                 iput (dir);
 158                 return -EACCES;
 159         }
 160         iput (dir);
 161         return 0;
 162 }
 163 
 164 /*
 165  *      ext2_add_entry()
 166  *
 167  * adds a file entry to the specified directory, using the same
 168  * semantics as ext2_find_entry(). It returns NULL if it failed.
 169  *
 170  * NOTE!! The inode part of 'de' is left at 0 - which means you
 171  * may not sleep between calling this and putting something into
 172  * the entry, as someone else might have used it while you slept.
 173  */
 174 static struct buffer_head * ext2_add_entry (struct inode * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
 175                                             const char * name, int namelen,
 176                                             struct ext2_dir_entry ** res_dir)
 177 {
 178         int i;
 179         long offset;
 180         unsigned short rec_len;
 181         struct buffer_head * bh;
 182         struct ext2_dir_entry * de, * de1;
 183         struct super_block * sb;
 184 
 185         *res_dir = NULL;
 186         if (!dir)
 187                 return NULL;
 188         sb = dir->i_sb;
 189 #ifdef NO_TRUNCATE
 190         if (namelen > EXT2_NAME_LEN)
 191                 return NULL;
 192 #else
 193         if (namelen > EXT2_NAME_LEN)
 194                 namelen = EXT2_NAME_LEN;
 195 #endif
 196         if (!namelen)
 197                 return NULL;
 198         bh = ext2_bread (dir, 0, 0);
 199         if (!bh)
 200                 return NULL;
 201         rec_len = EXT2_DIR_REC_LEN(namelen);
 202         offset = 0;
 203         de = (struct ext2_dir_entry *) bh->b_data;
 204         while (1) {
 205                 if ((char *)de >= sb->s_blocksize + bh->b_data) {
 206                         brelse (bh);
 207                         bh = NULL;
 208                         bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0);
 209                         if (!bh) {
 210 #ifdef EXT2FS_DEBUG
 211                                 printk ("ext2_add_entry: creating next block\n");
 212 #endif
 213                                 bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1);
 214                                 if (!bh)
 215                                         return NULL;
 216                                 de = (struct ext2_dir_entry *) bh->b_data;
 217                                 de->inode = 0;
 218                                 de->rec_len = sb->s_blocksize;
 219                                 dir->i_size += sb->s_blocksize;
 220                                 dir->i_dirt = 1;
 221                         } else {
 222 #ifdef EXT2FS_DEBUG
 223                                 printk ("ext2_add_entry: skipping to next block\n");
 224 #endif
 225                                 de = (struct ext2_dir_entry *) bh->b_data;
 226                         }
 227                 }
 228                 if (! ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
 229                                             offset)) {
 230                         brelse (bh);
 231                         return NULL;
 232                 }
 233                 if ((!de->inode && de->rec_len >= rec_len) ||
 234                     (de->rec_len >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
 235                         offset += de->rec_len;
 236                         if (de->inode) {
 237                                 de1 = (struct ext2_dir_entry *) ((char *) de +
 238                                         EXT2_DIR_REC_LEN(de->name_len));
 239                                 de1->rec_len = de->rec_len -
 240                                         EXT2_DIR_REC_LEN(de->name_len);
 241                                 de->rec_len = EXT2_DIR_REC_LEN(de->name_len);
 242                                 de = de1;
 243                         }
 244                         de->inode = 0;
 245                         de->name_len = namelen;
 246                         for (i = 0; i < namelen ; i++)
 247                                 de->name[i] = name [i];
 248                         dir->i_mtime = CURRENT_TIME;
 249                         bh->b_dirt = 1;
 250                         *res_dir = de;
 251                         return bh;
 252                 }
 253                 offset += de->rec_len;
 254                 de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
 255         }
 256         brelse (bh);
 257         return NULL;
 258 }
 259 
 260 /*
 261  * ext2_delete_entry deletes a directory entry by merging it with the
 262  * previous entry
 263  */
 264 static void ext2_delete_entry (struct ext2_dir_entry * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
 265                                struct ext2_dir_entry * prev_dir)
 266 {
 267         if (prev_dir != NULL)
 268                 prev_dir->rec_len += dir->rec_len;
 269         else
 270                 dir->inode = 0;
 271 }
 272 
 273 int ext2_create (struct inode * dir,const char * name, int len, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 274                  struct inode ** result)
 275 {
 276         struct inode * inode;
 277         struct buffer_head * bh;
 278         struct ext2_dir_entry * de;
 279 
 280         *result = NULL;
 281         if (!dir)
 282                 return -ENOENT;
 283         inode = ext2_new_inode (dir, mode);
 284         if (!inode) {
 285                 iput (dir);
 286                 return -ENOSPC;
 287         }
 288         inode->i_op = &ext2_file_inode_operations;
 289         inode->i_mode = mode;
 290         inode->i_dirt = 1;
 291         bh = ext2_add_entry (dir, name, len, &de);
 292         if (!bh) {
 293                 inode->i_nlink --;
 294                 inode->i_dirt = 1;
 295                 iput (inode);
 296                 iput (dir);
 297                 return -ENOSPC;
 298         }
 299         de->inode = inode->i_ino;
 300 #ifndef DONT_USE_DCACHE
 301         ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
 302                          de->inode);
 303 #endif
 304         bh->b_dirt = 1;
 305         brelse (bh);
 306         iput (dir);
 307         *result = inode;
 308         return 0;
 309 }
 310 
 311 int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 312                 int rdev)
 313 {
 314         struct inode * inode;
 315         struct buffer_head * bh;
 316         struct ext2_dir_entry * de;
 317 
 318         if (!dir)
 319                 return -ENOENT;
 320         bh = ext2_find_entry (dir, name, len, &de, NULL);
 321         if (bh) {
 322                 brelse (bh);
 323                 iput (dir);
 324                 return -EEXIST;
 325         }
 326         inode = ext2_new_inode (dir, mode);
 327         if (!inode) {
 328                 iput (dir);
 329                 return -ENOSPC;
 330         }
 331         inode->i_uid = current->euid;
 332         inode->i_mode = mode;
 333         inode->i_op = NULL;
 334         if (S_ISREG(inode->i_mode))
 335                 inode->i_op = &ext2_file_inode_operations;
 336         else if (S_ISDIR(inode->i_mode)) {
 337                 inode->i_op = &ext2_dir_inode_operations;
 338                 if (dir->i_mode & S_ISGID)
 339                         inode->i_mode |= S_ISGID;
 340         }
 341         else if (S_ISLNK(inode->i_mode))
 342                 inode->i_op = &ext2_symlink_inode_operations;
 343         else if (S_ISCHR(inode->i_mode))
 344                 inode->i_op = &chrdev_inode_operations;
 345         else if (S_ISBLK(inode->i_mode))
 346                 inode->i_op = &blkdev_inode_operations;
 347         else if (S_ISFIFO(inode->i_mode)) 
 348                 init_fifo(inode);
 349         if (S_ISBLK(mode) || S_ISCHR(mode))
 350                 inode->i_rdev = rdev;
 351         inode->i_mtime = inode->i_atime = CURRENT_TIME;
 352         inode->i_dirt = 1;
 353         bh = ext2_add_entry (dir, name, len, &de);
 354         if (!bh) {
 355                 inode->i_nlink --;
 356                 inode->i_dirt = 1;
 357                 iput (inode);
 358                 iput (dir);
 359                 return -ENOSPC;
 360         }
 361         de->inode = inode->i_ino;
 362 #ifndef DONT_USE_DCACHE
 363         ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
 364                          de->inode);
 365 #endif
 366         bh->b_dirt = 1;
 367         brelse (bh);
 368         iput (dir);
 369         iput (inode);
 370         return 0;
 371 }
 372 
 373 int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 374 {
 375         struct inode * inode;
 376         struct buffer_head * bh, * dir_block;
 377         struct ext2_dir_entry * de;
 378         
 379         bh = ext2_find_entry (dir, name, len, &de, NULL);
 380         if (bh) {
 381                 brelse (bh);
 382                 iput (dir);
 383                 return -EEXIST;
 384         }
 385         inode = ext2_new_inode (dir, S_IFDIR);
 386         if (!inode) {
 387                 iput (dir);
 388                 return -ENOSPC;
 389         }
 390         inode->i_op = &ext2_dir_inode_operations;
 391         inode->i_size = inode->i_sb->s_blocksize;
 392         inode->i_mtime = inode->i_atime = CURRENT_TIME;
 393         dir_block = ext2_bread (inode, 0, 1);
 394         if (!dir_block) {
 395                 iput (dir);
 396                 inode->i_nlink --;
 397                 inode->i_dirt = 1;
 398                 iput (inode);
 399                 return -ENOSPC;
 400         }
 401         inode->i_blocks = inode->i_sb->s_blocksize / 512;
 402         de = (struct ext2_dir_entry *) dir_block->b_data;
 403         de->inode = inode->i_ino;
 404         de->name_len = 1;
 405         de->rec_len = EXT2_DIR_REC_LEN(de->name_len);
 406         strcpy (de->name, ".");
 407         de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
 408         de->inode = dir->i_ino;
 409         de->rec_len = inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1);
 410         de->name_len = 2;
 411         strcpy (de->name, "..");
 412         inode->i_nlink = 2;
 413         dir_block->b_dirt = 1;
 414         brelse (dir_block);
 415         inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask);
 416         if (dir->i_mode & S_ISGID)
 417                 inode->i_mode |= S_ISGID;
 418         inode->i_dirt = 1;
 419         bh = ext2_add_entry (dir, name, len, &de);
 420         if (!bh) {
 421                 iput (dir);
 422                 inode->i_nlink = 0;
 423                 iput (inode);
 424                 return -ENOSPC;
 425         }
 426         de->inode = inode->i_ino;
 427 #ifndef DONT_USE_DCACHE
 428         ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
 429                          de->inode);
 430 #endif
 431         bh->b_dirt = 1;
 432         dir->i_nlink ++;
 433         dir->i_dirt = 1;
 434         iput (dir);
 435         iput (inode);
 436         brelse (bh);
 437         return 0;
 438 }
 439 
 440 /*
 441  * routine to check that the specified directory is empty (for rmdir)
 442  */
 443 static int empty_dir (struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 444 {
 445         unsigned long offset;
 446         struct buffer_head * bh;
 447         struct ext2_dir_entry * de, * de1;
 448         struct super_block * sb;
 449 
 450         sb = inode->i_sb;
 451         if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) ||
 452             !(bh = ext2_bread (inode, 0, 0))) {
 453                 printk ("warning - bad directory (dev %04x, dir %d)\n",
 454                         inode->i_dev, inode->i_ino);
 455                 return 1;
 456         }
 457         de = (struct ext2_dir_entry *) bh->b_data;
 458         de1 = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
 459         if (de->inode != inode->i_ino || !de1->inode || 
 460             strcmp (".", de->name) || strcmp ("..", de1->name)) {
 461                 printk ("warning - bad directory (dev %04x, dir %d)\n",
 462                         inode->i_dev, inode->i_ino);
 463                 return 1;
 464         }
 465         offset = de->rec_len + de1->rec_len;
 466         de = (struct ext2_dir_entry *) ((char *) de1 + de1->rec_len);
 467         while (offset < inode->i_size ) {
 468                 if ((void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
 469                         brelse (bh);
 470                         bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1);
 471                         if (!bh) {
 472                                 offset += sb->s_blocksize;
 473                                 continue;
 474                         }
 475                         de = (struct ext2_dir_entry *) bh->b_data;
 476                 }
 477                 if (! ext2_check_dir_entry ("empty_dir", inode, de, bh,
 478                                             offset)) {
 479                         brelse (bh);
 480                         return 1;
 481                 }
 482                 if (de->inode) {
 483                         brelse (bh);
 484                         return 0;
 485                 }
 486                 offset += de->rec_len;
 487                 de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
 488         }
 489         brelse (bh);
 490         return 1;
 491 }
 492 
 493 int ext2_rmdir (struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 494 {
 495         int retval;
 496         struct inode * inode;
 497         struct buffer_head * bh;
 498         struct ext2_dir_entry * de, * pde;
 499 
 500         inode = NULL;
 501         bh = ext2_find_entry (dir, name, len, &de, &pde);
 502         retval = -ENOENT;
 503         if (!bh)
 504                 goto end_rmdir;
 505         retval = -EPERM;
 506         if (!(inode = iget (dir->i_sb, de->inode)))
 507                 goto end_rmdir;
 508         if ((dir->i_mode & S_ISVTX) && current->euid &&
 509             inode->i_uid != current->euid)
 510                 goto end_rmdir;
 511         if (inode->i_dev != dir->i_dev)
 512                 goto end_rmdir;
 513         if (inode == dir)       /* we may not delete ".", but "../dir" is ok */
 514                 goto end_rmdir;
 515         if (!S_ISDIR(inode->i_mode)) {
 516                 retval = -ENOTDIR;
 517                 goto end_rmdir;
 518         }
 519         if (!empty_dir (inode)) {
 520                 retval = -ENOTEMPTY;
 521                 goto end_rmdir;
 522         }
 523         if (inode->i_count > 1) {
 524                 retval = -EBUSY;
 525                 goto end_rmdir;
 526         }
 527         if (inode->i_nlink != 2)
 528                 printk ("empty  directory has nlink!=2 (%d)\n", inode->i_nlink);
 529 #ifndef DONT_USE_DCACHE
 530         ext2_dcache_remove (dir->i_dev, dir->i_ino, de->name, de->name_len);
 531 #endif
 532         ext2_delete_entry (de, pde);
 533 #if 0   
 534         if (pde)
 535                 pde->rec_len += de->rec_len;
 536         else
 537                 de->inode = 0;
 538 #endif
 539         bh->b_dirt = 1;
 540         inode->i_nlink = 0;
 541         inode->i_dirt = 1;
 542         dir->i_nlink --;
 543         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 544         dir->i_dirt = 1;
 545         retval = 0;
 546 end_rmdir:
 547         iput (dir);
 548         iput (inode);
 549         brelse (bh);
 550         return retval;
 551 }
 552 
 553 int ext2_unlink (struct inode * dir, const char * name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 554 {
 555         int retval;
 556         struct inode * inode;
 557         struct buffer_head * bh;
 558         struct ext2_dir_entry * de, * pde;
 559 
 560         retval = -ENOENT;
 561         inode = NULL;
 562         bh = ext2_find_entry (dir, name, len, &de, &pde);
 563         if (!bh)
 564                 goto end_unlink;
 565         if (!(inode = iget (dir->i_sb, de->inode)))
 566                 goto end_unlink;
 567         retval = -EPERM;
 568         if ((dir->i_mode & S_ISVTX) && !suser() &&
 569             current->euid != inode->i_uid &&
 570             current->euid != dir->i_uid)
 571                 goto end_unlink;
 572         if (S_ISDIR(inode->i_mode))
 573                 goto end_unlink;
 574         if (!inode->i_nlink) {
 575                 printk ("Deleting nonexistent file (%04x:%d), %d\n",
 576                         inode->i_dev, inode->i_ino, inode->i_nlink);
 577                 inode->i_nlink = 1;
 578         }
 579 #ifndef DONT_USE_DCACHE
 580         ext2_dcache_remove (dir->i_dev, dir->i_ino, de->name, de->name_len);
 581 #endif
 582         ext2_delete_entry (de, pde);
 583 #if 0
 584         if (pde)
 585                 pde->rec_len += de->rec_len;
 586         else
 587                 de->inode = 0;
 588 #endif
 589         bh->b_dirt = 1;
 590         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 591         dir->i_dirt = 1;
 592         inode->i_nlink --;
 593         inode->i_dirt = 1;
 594         inode->i_ctime = CURRENT_TIME;
 595         retval = 0;
 596 end_unlink:
 597         brelse (bh);
 598         iput (inode);
 599         iput (dir);
 600         return retval;
 601 }
 602 
 603 int ext2_symlink (struct inode * dir, const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 604                   const char * symname)
 605 {
 606         struct ext2_dir_entry * de;
 607         struct inode * inode = NULL;
 608         struct buffer_head * bh = NULL, * name_block = NULL;
 609         char * link;
 610         int i;
 611         int l;
 612         char c;
 613 
 614         if (!(inode = ext2_new_inode (dir, S_IFLNK))) {
 615                 iput (dir);
 616                 return -ENOSPC;
 617         }
 618         inode->i_mode = S_IFLNK | 0777;
 619         inode->i_op = &ext2_symlink_inode_operations;
 620         for (l = 0; l < inode->i_sb->s_blocksize - 1 &&
 621              symname [l]; l++)
 622                 ;
 623         if (l >= EXT2_N_BLOCKS * sizeof (unsigned long)) {
 624 #ifdef EXT2FS_DEBUG
 625                 printk ("ext2_symlink: l=%d, normal symlink\n", l);
 626 #endif
 627                 name_block = ext2_bread (inode, 0, 1);
 628                 if (!name_block) {
 629                         iput (dir);
 630                         inode->i_nlink --;
 631                         inode->i_dirt = 1;
 632                         iput (inode);
 633                         return -ENOSPC;
 634                 }
 635                 link = name_block->b_data;
 636         } else {
 637                 link = (char *) inode->u.ext2_i.i_data;
 638 #ifdef EXT2FS_DEBUG
 639                 printk ("ext2_symlink: l=%d, fast symlink\n", l);
 640 #endif
 641         }
 642         i = 0;
 643         while (i < inode->i_sb->s_blocksize - 1 && (c = *(symname ++)))
 644                 link[i++] = c;
 645         link[i] = 0;
 646         if (name_block) {
 647                 name_block->b_dirt = 1;
 648                 brelse (name_block);
 649         }
 650         inode->i_size = i;
 651         inode->i_dirt = 1;
 652         bh = ext2_find_entry (dir, name, len, &de, NULL);
 653         if (bh) {
 654                 inode->i_nlink --;
 655                 inode->i_dirt = 1;
 656                 iput (inode);
 657                 brelse (bh);
 658                 iput (dir);
 659                 return -EEXIST;
 660         }
 661         bh = ext2_add_entry (dir, name, len, &de);
 662         if (!bh) {
 663                 inode->i_nlink --;
 664                 inode->i_dirt = 1;
 665                 iput (inode);
 666                 iput (dir);
 667                 return -ENOSPC;
 668         }
 669         de->inode = inode->i_ino;
 670 #ifndef DONT_USE_DCACHE
 671         ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
 672                          de->inode);
 673 #endif
 674         bh->b_dirt = 1;
 675         brelse (bh);
 676         iput (dir);
 677         iput (inode);
 678         return 0;
 679 }
 680 
 681 int ext2_link (struct inode * oldinode, struct inode * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
 682                const char * name, int len)
 683 {
 684         struct ext2_dir_entry * de;
 685         struct buffer_head * bh;
 686 
 687         if (S_ISDIR(oldinode->i_mode)) {
 688                 iput (oldinode);
 689                 iput (dir);
 690                 return -EPERM;
 691         }
 692         if (oldinode->i_nlink > 32000) {
 693                 iput (oldinode);
 694                 iput (dir);
 695                 return -EMLINK;
 696         }
 697         bh = ext2_find_entry (dir, name, len, &de, NULL);
 698         if (bh) {
 699                 brelse (bh);
 700                 iput (dir);
 701                 iput (oldinode);
 702                 return -EEXIST;
 703         }
 704         bh = ext2_add_entry (dir, name, len, &de);
 705         if (!bh) {
 706                 iput (dir);
 707                 iput (oldinode);
 708                 return -ENOSPC;
 709         }
 710         de->inode = oldinode->i_ino;
 711 #ifndef DONT_USE_DCACHE
 712         ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
 713                          de->inode);
 714 #endif
 715         bh->b_dirt = 1;
 716         brelse (bh);
 717         iput (dir);
 718         oldinode->i_nlink ++;
 719         oldinode->i_ctime = CURRENT_TIME;
 720         oldinode->i_dirt = 1;
 721         iput (oldinode);
 722         return 0;
 723 }
 724 
 725 static int subdir (struct inode * new, struct inode * old)
     /* [previous][next][first][last][top][bottom][index][help] */
 726 {
 727         int ino;
 728         int result;
 729 
 730         new->i_count ++;
 731         result = 0;
 732         for (;;) {
 733                 if (new == old) {
 734                         result = 1;
 735                         break;
 736                 }
 737                 if (new->i_dev != old->i_dev)
 738                         break;
 739                 ino = new->i_ino;
 740                 if (ext2_lookup (new, "..", 2, &new))
 741                         break;
 742                 if (new->i_ino == ino)
 743                         break;
 744         }
 745         iput (new);
 746         return result;
 747 }
 748 
 749 #define PARENT_INO(buffer) \
 750         ((struct ext2_dir_entry *) ((char *) buffer + \
 751         ((struct ext2_dir_entry *) buffer)->rec_len))->inode
 752 
 753 #define PARENT_NAME(buffer) \
 754         ((struct ext2_dir_entry *) ((char *) buffer + \
 755         ((struct ext2_dir_entry *) buffer)->rec_len))->name
 756 
 757 /*
 758  * rename uses retrying to avoid race-conditions: at least they should be
 759  * minimal.
 760  * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
 761  * checks fail, it tries to restart itself again. Very practical - no changes
 762  * are done until we know everything works ok.. and then all the changes can be
 763  * done in one fell swoop when we have claimed all the buffers needed.
 764  *
 765  * Anybody can rename anything with this: the permission checks are left to the
 766  * higher-level routines.
 767  */
 768 static int do_ext2_rename (struct inode * old_dir, const char * old_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 769                            int old_len, struct inode * new_dir,
 770                            const char * new_name, int new_len)
 771 {
 772         struct inode * old_inode, * new_inode;
 773         struct buffer_head * old_bh, * new_bh, * dir_bh;
 774         struct ext2_dir_entry * old_de, * new_de, * pde;
 775         int retval;
 776 
 777         goto start_up;
 778 try_again:
 779         brelse (old_bh);
 780         brelse (new_bh);
 781         brelse (dir_bh);
 782         iput (old_inode);
 783         iput (new_inode);
 784         current->counter = 0;
 785         schedule ();
 786 start_up:
 787         old_inode = new_inode = NULL;
 788         old_bh = new_bh = dir_bh = NULL;
 789         old_bh = ext2_find_entry (old_dir, old_name, old_len, &old_de, &pde);
 790         retval = -ENOENT;
 791         if (!old_bh)
 792                 goto end_rename;
 793         old_inode = iget (old_dir->i_sb, old_de->inode);
 794         if (!old_inode)
 795                 goto end_rename;
 796         if ((old_dir->i_mode & S_ISVTX) && 
 797             current->euid != old_inode->i_uid &&
 798             current->euid != old_dir->i_uid && !suser())
 799                 goto end_rename;
 800         new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de, NULL);
 801         if (new_bh) {
 802                 new_inode = iget (new_dir->i_sb, new_de->inode);
 803                 if (!new_inode) {
 804                         brelse (new_bh);
 805                         new_bh = NULL;
 806                 }
 807         }
 808         if (new_inode == old_inode) {
 809                 retval = 0;
 810                 goto end_rename;
 811         }
 812         if (new_inode && S_ISDIR(new_inode->i_mode)) {
 813                 retval = -EEXIST;
 814                 goto end_rename;
 815         }
 816         retval = -EPERM;
 817         if (new_inode && (new_dir->i_mode & S_ISVTX) &&
 818             current->euid != new_inode->i_uid &&
 819             current->euid != new_dir->i_uid && !suser())
 820                 goto end_rename;
 821         if (S_ISDIR(old_inode->i_mode)) {
 822                 retval = -EEXIST;
 823                 if (new_bh)
 824                         goto end_rename;
 825                 retval = -EACCES;
 826                 if (!permission (old_inode, MAY_WRITE))
 827                         goto end_rename;
 828                 retval = -EINVAL;
 829                 if (subdir (new_dir, old_inode))
 830                         goto end_rename;
 831                 retval = -EIO;
 832                 dir_bh = ext2_bread (old_inode, 0, 0);
 833                 if (!dir_bh)
 834                         goto end_rename;
 835                 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
 836                         goto end_rename;
 837         }
 838         if (!new_bh)
 839                 new_bh = ext2_add_entry (new_dir, new_name, new_len, &new_de);
 840         retval = -ENOSPC;
 841         if (!new_bh)
 842                 goto end_rename;
 843 /* sanity checking before doing the rename - avoid races */
 844         if (new_inode && (new_de->inode != new_inode->i_ino))
 845                 goto try_again;
 846         if (new_de->inode && !new_inode)
 847                 goto try_again;
 848         if (old_de->inode != old_inode->i_ino)
 849                 goto try_again;
 850 /* ok, that's it */
 851         new_de->inode = old_inode->i_ino;
 852 #ifndef DONT_USE_DCACHE
 853         ext2_dcache_remove (old_dir->i_dev, old_dir->i_ino, old_de->name,
 854                             old_de->name_len);
 855         ext2_dcache_add (new_dir->i_dev, new_dir->i_ino, new_de->name,
 856                          new_de->name_len, new_de->inode);
 857 #endif
 858         if (old_bh->b_blocknr == new_bh->b_blocknr &&
 859             ((char *) new_de) + new_de->rec_len == (char *) old_de)
 860                 new_de->rec_len += old_de->rec_len;
 861         else
 862                 ext2_delete_entry (old_de, pde);
 863 #if 0
 864         if (((char *) new_de) + new_de->rec_len == (char *) old_de)
 865                 new_de->rec_len += old_de->rec_len;
 866         else if (pde)
 867                 pde->rec_len += old_de->rec_len;
 868         else
 869                 old_de->inode = 0;
 870 #endif
 871         if (new_inode) {
 872                 new_inode->i_nlink --;
 873                 new_inode->i_dirt = 1;
 874         }
 875         old_bh->b_dirt = 1;
 876         new_bh->b_dirt = 1;
 877         if (dir_bh) {
 878                 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
 879                 dir_bh->b_dirt = 1;
 880                 old_dir->i_nlink --;
 881                 new_dir->i_nlink ++;
 882                 old_dir->i_dirt = 1;
 883                 new_dir->i_dirt = 1;
 884         }
 885         retval = 0;
 886 end_rename:
 887         brelse (dir_bh);
 888         brelse (old_bh);
 889         brelse (new_bh);
 890         iput (old_inode);
 891         iput (new_inode);
 892         iput (old_dir);
 893         iput (new_dir);
 894         return retval;
 895 }
 896 
 897 /*
 898  * Ok, rename also locks out other renames, as they can change the parent of
 899  * a directory, and we don't want any races. Other races are checked for by
 900  * "do_rename()", which restarts if there are inconsistencies.
 901  *
 902  * Note that there is no race between different filesystems: it's only within
 903  * the same device that races occur: many renames can happen at once, as long
 904  * as they are on different partitions.
 905  *
 906  * In the second extended file system, we use a lock flag stored in the memory
 907  * super-block.  This way, we really lock other renames only if they occur
 908  * on the same file system
 909  */
 910 int ext2_rename (struct inode * old_dir, const char * old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 911                  struct inode * new_dir, const char * new_name, int new_len)
 912 {
 913         int result;
 914 
 915         while (old_dir->i_sb->u.ext2_sb.s_rename_lock)
 916                 sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
 917         old_dir->i_sb->u.ext2_sb.s_rename_lock = 1;
 918         result = do_ext2_rename (old_dir, old_name, old_len, new_dir,
 919                                  new_name, new_len);
 920         old_dir->i_sb->u.ext2_sb.s_rename_lock = 0;
 921         wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
 922         return result;
 923 }

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