root/fs/xiafs/namei.c

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

DEFINITIONS

This source file includes following definitions.
  1. xiafs_match
  2. xiafs_find_entry
  3. xiafs_lookup
  4. xiafs_add_entry
  5. xiafs_create
  6. xiafs_mknod
  7. xiafs_mkdir
  8. empty_dir
  9. xiafs_rm_entry
  10. xiafs_rmdir
  11. xiafs_unlink
  12. xiafs_symlink
  13. xiafs_link
  14. subdir
  15. do_xiafs_rename
  16. xiafs_rename

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

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