root/fs/vfat/namei.c

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

DEFINITIONS

This source file includes following definitions.
  1. vfat_put_super
  2. vfat_read_super
  3. dump_fat
  4. dump_de
  5. vfat_valid_longname
  6. vfat_valid_shortname
  7. vfat_format_name
  8. vfat_create_shortname
  9. vfat_find_free_slots
  10. vfat_build_slots
  11. vfat_get_longname
  12. vfat_find
  13. vfat_lookup
  14. vfat_create_entry
  15. vfat_create
  16. vfat_create_a_dotdir
  17. vfat_create_dotdirs
  18. vfat_empty
  19. vfat_rmdir_free_ino
  20. vfat_unlink_free_ino
  21. vfat_remove_entry
  22. vfat_rmdirx
  23. vfat_rmdir
  24. vfat_unlinkx
  25. vfat_mkdir
  26. vfat_unlink
  27. vfat_rename
  28. vfat_read_inode
  29. init_vfat_fs
  30. init_module
  31. cleanup_module

   1 /*
   2  *  linux/fs/vfat/namei.c
   3  *
   4  *  Written 1992,1993 by Werner Almesberger
   5  *
   6  *  Windows95/Windows NT compatible extended MSDOS filesystem
   7  *    by Gordon Chaffee Copyright (C) 1995
   8  */
   9 
  10 #include <linux/module.h>
  11 
  12 #include <linux/sched.h>
  13 #include <linux/msdos_fs.h>
  14 #include <linux/kernel.h>
  15 #include <linux/errno.h>
  16 #include <linux/string.h>
  17 #include <linux/stat.h>
  18 
  19 #include <asm/segment.h>
  20 
  21 #include "../fat/msbuffer.h"
  22 #include "../fat/tables.h"
  23 
  24 #if 0
  25 #define PRINTK(x) printk x
  26 #else
  27 #define PRINTK(x)
  28 #endif
  29 
  30 
  31 void vfat_read_inode(struct inode *inode);
  32 
  33 
  34 void vfat_put_super(struct super_block *sb)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36         fat_put_super(sb);
  37         MOD_DEC_USE_COUNT;
  38 }
  39 
  40 
  41 static struct super_operations vfat_sops = { 
  42         vfat_read_inode,
  43         fat_notify_change,
  44         fat_write_inode,
  45         fat_put_inode,
  46         vfat_put_super,
  47         NULL, /* added in 0.96c */
  48         fat_statfs,
  49         NULL
  50 };
  51 
  52 struct super_block *vfat_read_super(struct super_block *sb,void *data,
     /* [previous][next][first][last][top][bottom][index][help] */
  53                                     int silent)
  54 {
  55         struct super_block *res;
  56   
  57         MOD_INC_USE_COUNT;
  58         
  59         sb->s_op = &vfat_sops;
  60         res = fat_read_super(sb, data, silent);
  61         if (res == NULL) {
  62           MOD_DEC_USE_COUNT;
  63         } else {
  64           MSDOS_SB(sb)->vfat = 1;
  65           MSDOS_SB(sb)->dotsOK = 0;
  66         }
  67 
  68         return res;
  69 }
  70 
  71 
  72 
  73 #ifdef DEBUG
  74 
  75 static void dump_fat(struct super_block *sb,int start)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77         printk("[");
  78         while (start) {
  79                 printk("%d ",start);
  80                 start = fat_access(sb,start,-1);
  81                 if (!start) {
  82                         printk("ERROR");
  83                         break;
  84                 }
  85                 if (start == -1) break;
  86         }
  87         printk("]\n");
  88 }
  89 
  90 static void dump_de(struct msdos_dir_entry *de)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         int i;
  93         unsigned char *p = (unsigned char *) de;
  94         printk("[");
  95 
  96         for (i = 0; i < 32; i++, p++) {
  97                 printk("%02x ", *p);
  98         }
  99         printk("]\n");
 100 }
 101 
 102 #endif
 103 
 104 /* MS-DOS "device special files" */
 105 
 106 static const char *reserved_names[] = {
 107         "CON     ","PRN     ","NUL     ","AUX     ",
 108         "LPT1    ","LPT2    ","LPT3    ","LPT4    ",
 109         "COM1    ","COM2    ","COM3    ","COM4    ",
 110         NULL };
 111 
 112 
 113 /* Characters that are undesirable in an MS-DOS file name */
 114 
 115 #if 1  /* Steve Searle's characters */
 116 static char bad_chars[] = "*?<>|\":/\\";
 117 static char bad_if_strict[] = "+=,; []";
 118 #else
 119 static char bad_chars[] = "*?<>|\"";
 120 static char bad_if_strict[] = "+=,; ";
 121 #endif
 122 static char replace_chars[] = "[];,+=";
 123 
 124 static int vfat_find(struct inode *dir,const char *name,int len,
 125                       int find_long,int new_filename,int is_dir,
 126                       struct slot_info *sinfo_out);
 127 
 128 /* Checks the validity of an long MS-DOS filename */
 129 /* Returns negative number on error, 0 for a normal
 130  * return, and 1 for . or .. */
 131 
 132 static int vfat_valid_longname(const char *name, int len, int dot_dirs)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134         const char **reserved;
 135         unsigned char c;
 136         int i;
 137 
 138         if (IS_FREE(name)) return -EINVAL;
 139         if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
 140                 if (!dot_dirs) return -EEXIST;
 141                 return 1;
 142         }
 143 
 144         if (len && name[len-1] == ' ') return -EINVAL;
 145         if (len >= 256) return -EINVAL;
 146         for (i = 0; i < len; i++) {
 147                 c = name[i];
 148                 if (strchr(bad_chars,c)) return -EINVAL;
 149         }
 150         if (len == 3 || len == 4) {
 151                 for (reserved = reserved_names; *reserved; reserved++)
 152                         if (!strncmp(name,*reserved,8)) return -EINVAL;
 153         }
 154         return 0;
 155 }
 156 
 157 static int vfat_valid_shortname(char conv,const char *name,int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 158                                  int dot_dirs)
 159 {
 160         const char *walk, **reserved;
 161         unsigned char c;
 162         int space;
 163 
 164         if (IS_FREE(name)) return -EINVAL;
 165         if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
 166                 if (!dot_dirs) return -EEXIST;
 167                 return 1;
 168         }
 169 
 170         space = 1; /* disallow names starting with a dot */
 171         c = 0;
 172         for (walk = name; len && walk-name < 8;) {
 173                 c = *walk++;
 174                 len--;
 175                 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
 176                 if (conv == 'x' && strchr(replace_chars,c)) return -EINVAL;
 177                 if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
 178                 if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
 179                 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
 180                 if ((walk == name) && (c == 0xE5)) c = 0x05;
 181                 if (c == '.') break;
 182                 space = c == ' ';
 183         }
 184         if (space) return -EINVAL;
 185         if ((conv == 's' || conv == 'x') && len && c != '.') {
 186                 c = *walk++;
 187                 len--;
 188                 if (c != '.') return -EINVAL;
 189         }
 190         while (c != '.' && len--) c = *walk++;
 191         if (c == '.') {
 192                 if (len >= 4) return -EINVAL;
 193                 while (len > 0 && walk-name < (MSDOS_NAME+1)) {
 194                         c = *walk++;
 195                         len--;
 196                         if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
 197                         if (conv == 's' && strchr(bad_if_strict,c))
 198                                 return -EINVAL;
 199                         if (conv == 'x' && strchr(replace_chars,c))
 200                                 return -EINVAL;
 201                         if (c < ' ' || c == ':' || c == '\\' || c == '.')
 202                                 return -EINVAL;
 203                         if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
 204                         space = c == ' ';
 205                 }
 206                 if (space) return -EINVAL;
 207                 if ((conv == 's' || conv == 'x') && len) return -EINVAL;
 208         }
 209         for (reserved = reserved_names; *reserved; reserved++)
 210                 if (!strncmp(name,*reserved,8)) return -EINVAL;
 211 
 212         return 0;
 213 }
 214 
 215 /* Takes a short filename and converts it to a formatted MS-DOS filename.
 216  * If the short filename is not a valid MS-DOS filename, an error is 
 217  * returned.  The formatted short filename is returned in 'res'.
 218  */
 219 
 220 static int vfat_format_name(char conv,const char *name,int len,char *res,
     /* [previous][next][first][last][top][bottom][index][help] */
 221   int dot_dirs)
 222 {
 223         char *walk;
 224         const char **reserved;
 225         unsigned char c;
 226         int space;
 227 
 228         if (IS_FREE(name)) return -EINVAL;
 229         if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
 230                 if (!dot_dirs) return -EEXIST;
 231                 memset(res+1,' ',10);
 232                 while (len--) *res++ = '.';
 233                 return 0;
 234         }
 235 
 236         space = 1; /* disallow names starting with a dot */
 237         c = 0;
 238         for (walk = res; len && walk-res < 8; walk++) {
 239                 c = *name++;
 240                 len--;
 241                 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
 242                 if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
 243                 if (conv == 'x' && strchr(replace_chars,c)) return -EINVAL;
 244                 if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
 245                 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
 246                 if (c == '.') break;
 247                 space = c == ' ';
 248                 *walk = c >= 'a' && c <= 'z' ? c-32 : c;
 249         }
 250         if (space) return -EINVAL;
 251         if ((conv == 's' || conv == 'x') && len && c != '.') {
 252                 c = *name++;
 253                 len--;
 254                 if (c != '.') return -EINVAL;
 255         }
 256         while (c != '.' && len--) c = *name++;
 257         if (c == '.') {
 258                 while (walk-res < 8) *walk++ = ' ';
 259                 while (len > 0 && walk-res < MSDOS_NAME) {
 260                         c = *name++;
 261                         len--;
 262                         if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
 263                         if (conv == 's' && strchr(bad_if_strict,c))
 264                                 return -EINVAL;
 265                         if (conv == 'x' && strchr(replace_chars,c))
 266                                 return -EINVAL;
 267                         if (c < ' ' || c == ':' || c == '\\' || c == '.')
 268                                 return -EINVAL;
 269                         if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
 270                         space = c == ' ';
 271                         *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
 272                 }
 273                 if (space) return -EINVAL;
 274                 if ((conv == 's' || conv == 'x') && len) return -EINVAL;
 275         }
 276         while (walk-res < MSDOS_NAME) *walk++ = ' ';
 277         for (reserved = reserved_names; *reserved; reserved++)
 278                 if (!strncmp(res,*reserved,8)) return -EINVAL;
 279 
 280         return 0;
 281 }
 282 
 283 static char skip_chars[] = ".:\"?<>| ";
 284 
 285 /* Given a valid longname, create a unique shortname.  Make sure the
 286  * shortname does not exist
 287  */
 288 static int vfat_create_shortname(struct inode *dir, const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
 289      int len, char *name_res)
 290 {
 291         const char *ip, *ext_start, *end;
 292         char *p;
 293         int valid;
 294         int sz, extlen, baselen, totlen;
 295         char msdos_name[13];
 296         char base[9], ext[4];
 297         int i;
 298         int res;
 299         int ino;
 300         int spaces;
 301         int count;
 302         char buf[8];
 303         struct slot_info sinfo;
 304         const char *name_start;
 305 
 306         PRINTK(("Entering vfat_create_shortname: name=%s, len=%d\n", name, len));
 307         sz = 0;                 /* Make compiler happy */
 308         valid = 1;
 309         if (len && name[len-1]==' ') return -EINVAL;
 310         if (len <= 12) {
 311                 /* Do a case insensitive search if the name would be a valid
 312                  * shortname if is were all capitalized */
 313                 for (i = 0, p = msdos_name, ip = name; i < len; i++, p++, ip++)
 314                 {
 315                         if (*ip >= 'A' && *ip <= 'Z') {
 316                                 *p = *ip + 32;
 317                         } else {
 318                                 *p = *ip;
 319                         }
 320                 }
 321                 res = vfat_format_name('x', msdos_name, len, name_res, 1);
 322                 if (res > -1) {
 323                         PRINTK(("vfat_create_shortname 1\n"));
 324                         res = vfat_find(dir, msdos_name, len, 0, 0, 0, &sinfo);
 325                         ino = sinfo.ino;
 326                         PRINTK(("vfat_create_shortname 2\n"));
 327                         if (res > -1) return -EEXIST;
 328                         return 0;
 329                 }
 330         }
 331 
 332         PRINTK(("vfat_create_shortname 3\n"));
 333         /* Now, we need to create a shortname from the long name */
 334         ext_start = end = &name[len];
 335         while (--ext_start >= name) {
 336                 if (*ext_start == '.') {
 337                         if (ext_start == end - 1) {
 338                                 sz = len;
 339                                 ext_start = NULL;
 340                         }
 341                         break;
 342                 }
 343         }
 344         if (ext_start == name - 1) {
 345                 sz = len;
 346                 ext_start = NULL;
 347         } else if (ext_start) {
 348                 /*
 349                  * Names which start with a dot could be just
 350                  * an extension eg. "...test".  In this case Win95
 351                  * uses the extension as the name and sets no extension.
 352                  */
 353                 name_start = &name[0];
 354                 while (name_start < ext_start)
 355                 {
 356                         if (!strchr(skip_chars,*name_start)) break;
 357                         name_start++;
 358                 }
 359                 if (name_start != ext_start) {
 360                         sz = ext_start - name;
 361                         ext_start++;
 362                 } else {
 363                         sz = len;
 364                         ext_start=NULL;
 365                 }
 366         }
 367 
 368         for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++)
 369         {
 370                 if (!strchr(skip_chars, *ip)) {
 371                         if (*ip >= 'A' && *ip <= 'Z') {
 372                                 *p = *ip + 32;
 373                         } else {
 374                                 *p = *ip;
 375                         }
 376                         p++; baselen++;
 377                 }
 378                 ip++;
 379         }
 380         if (baselen == 0) {
 381                 return -EINVAL;
 382         }
 383                 
 384         spaces = 8 - baselen;
 385 
 386         if (ext_start) {
 387                 extlen = 0;
 388                 for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
 389                         if (!strchr(skip_chars, *ip)) {
 390                                 if (*ip >= 'A' && *ip <= 'Z') {
 391                                         *p = *ip + 32;
 392                                 } else {
 393                                         *p = *ip;
 394                                 }
 395                                 if (strchr(replace_chars, *p)) *p='_';
 396                                 extlen++;
 397                                 p++;
 398                         }
 399                 }
 400         } else {
 401                 extlen = 0;
 402         }
 403         ext[extlen] = '\0';
 404         base[baselen] = '\0';
 405 
 406         count = 0;
 407         strcpy(msdos_name, base);
 408         msdos_name[baselen] = '.';
 409         strcpy(&msdos_name[baselen+1], ext);
 410 
 411         totlen = baselen + extlen + 1;
 412         res = 0;
 413         while (res > -1) {
 414                 /* Create the next shortname to try */
 415                 count++;
 416                 if (count == 10000000) return -EEXIST;
 417                 sprintf(buf, "%d", count);
 418                 sz = strlen(buf);
 419                 if (sz + 1 > spaces) {
 420                         baselen = baselen - (sz + 1 - spaces);
 421                         spaces = sz + 1;
 422                 }
 423 
 424                 strncpy(msdos_name, base, baselen);
 425                 msdos_name[baselen] = '~';
 426                 strcpy(&msdos_name[baselen+1], buf);
 427                 msdos_name[baselen+sz+1] = '.';
 428                 strcpy(&msdos_name[baselen+sz+2], ext);
 429 
 430                 totlen = baselen + sz + 2 + extlen;
 431                 res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
 432         }
 433         res = vfat_format_name('x', msdos_name, totlen, name_res, 1);
 434         return res;
 435 }
 436 
 437 static loff_t vfat_find_free_slots(struct inode *dir,int slots)
     /* [previous][next][first][last][top][bottom][index][help] */
 438 {
 439         struct super_block *sb = dir->i_sb;
 440         loff_t offset, curr;
 441         struct msdos_dir_entry *de;
 442         struct buffer_head *bh;
 443         struct inode *inode;
 444         int ino;
 445         int row;
 446         int done;
 447         int res;
 448         int added;
 449 
 450         PRINTK(("vfat_find_free_slots: find %d free slots\n", slots));
 451         offset = curr = 0;
 452         bh = NULL;
 453         row = 0;
 454         ino = fat_get_entry(dir,&curr,&bh,&de);
 455 
 456         for (added = 0; added < 2; added++) {
 457                 while (ino > -1) {
 458                         done = IS_FREE(de->name);
 459                         if (done) {
 460                                 inode = iget(sb,ino);
 461                                 if (inode) {
 462                                         /* Directory slots of busy deleted files aren't available yet. */
 463                                         done = !MSDOS_I(inode)->i_busy;
 464                                         /* PRINTK(("inode %d still busy\n", ino)); */
 465                                 }
 466                                 iput(inode);
 467                         }
 468                         if (done) {
 469                                 row++;
 470                                 if (row == slots) {
 471                                         brelse(bh);
 472                                         /* printk("----- Free offset at %d\n", offset); */
 473                                         return offset;
 474                                 }
 475                         } else {
 476                                 row = 0;
 477                                 offset = curr;
 478                         }
 479                         ino = fat_get_entry(dir,&curr,&bh,&de);
 480                 }
 481 
 482                 if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
 483                 if ((res = fat_add_cluster(dir)) < 0) return res;
 484                 ino = fat_get_entry(dir,&curr,&bh,&de);
 485         }
 486         /* Should never get here, but if it does */
 487         printk("vfat_find_free_slots: Unable to find any\n");
 488         return -ENOSPC;
 489 }
 490                 
 491 static int vfat_build_slots(struct inode *dir,const char *name,int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 492      int find_long, int new_filename,
 493      struct msdos_dir_slot *ds, struct msdos_dir_slot *ds_mask,
 494      int *slots, int *is_long)
 495 {
 496         struct msdos_dir_slot *ps, *ps_mask;
 497         struct msdos_dir_entry *de, *de_mask;
 498         char msdos_name[MSDOS_NAME];
 499         int res;
 500         int slot;
 501         int i;
 502         const unsigned char *ip;
 503         loff_t offset;
 504         unsigned char alias_checksum;
 505 
 506         PRINTK(("Entering vfat_build_slots: name=%s, len=%d\n", name, len));
 507         de = (struct msdos_dir_entry *) ds;
 508         de_mask = (struct msdos_dir_entry *) ds_mask;
 509 
 510         *slots = 1;
 511         *is_long = 0;
 512         memset(ds_mask, 0, sizeof(struct msdos_dir_slot) * MSDOS_SLOTS);
 513         if (len == 1 && name[0] == '.') {
 514                 strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
 515                 memset(de_mask, 0xff, MSDOS_NAME);
 516         } else if (len == 2 && name[0] == '.' && name[1] == '.') {
 517                 strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
 518                 memset(de_mask, 0xff, MSDOS_NAME);
 519         } else {
 520                 PRINTK(("vfat_build_slots 4\n"));
 521                 res = vfat_valid_shortname('x', name, len, 1);
 522                 if (res > -1) {
 523                         PRINTK(("vfat_build_slots 5a\n"));
 524                         res = vfat_format_name('x', name, len, de->name, 1);
 525                         PRINTK(("vfat_build_slots 5b\n"));
 526                         memset(de_mask->name, 0xff, MSDOS_NAME);
 527                         PRINTK(("vfat_build_slots 5c\n"));
 528                 } else {
 529                         PRINTK(("vfat_build_slots 5A: %s (len=%d) is an invalid shortname\n", name, len));
 530                         if (new_filename) {
 531                                 unsigned char sum;
 532 
 533                                 PRINTK(("vfat_build_slots 5Z\n"));
 534                                 res = vfat_create_shortname(dir, name, len, msdos_name);
 535                                 PRINTK(("vfat_build_slots 5Y\n"));
 536                                 if (res < 0) {
 537                                         return res;
 538                                 }
 539 
 540                                 for (sum = i = 0; i < 11; i++) {
 541                                         sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + msdos_name[i];
 542                                 }
 543                                 PRINTK(("vfat_build_slots 5X: msdos_name=%s\n", msdos_name));
 544                                 alias_checksum = sum;
 545                         } else {
 546                                 alias_checksum = 0;
 547                         }
 548 
 549                         if (!find_long) return -EINVAL;
 550                         res = vfat_valid_longname(name, len, 1);
 551                         if (res < 0) return res;
 552 
 553                         *is_long = 1;
 554                         *slots = (len + 12) / 13;
 555                         PRINTK(("vfat_build_slots 6: slots=%d\n",*slots));
 556 
 557                         for (ps = ds, slot = *slots, ps_mask = ds_mask;
 558                              slot > 0; slot--, ps++, ps_mask++)
 559                         {
 560                                 int end, j;
 561 
 562                                 PRINTK(("vfat_build_slots 6a\n"));
 563                                 ps->id = slot; ps_mask->id = 0xff;
 564                                 ps->attr = ATTR_EXT; ps_mask->attr = 0xff;
 565                                 ps->reserved = 0; ps_mask->reserved = 0xff;
 566                                 ps->alias_checksum = alias_checksum;
 567                                 ps_mask->alias_checksum = 0;
 568                                 ps->start[0] = 0; ps_mask->start[0] = 0xff;
 569                                 ps->start[1] = 0; ps_mask->start[1] = 0xff;
 570                                 PRINTK(("vfat_build_slots 6b: name=%s\n",name));
 571                                 offset = (slot - 1) * 13;
 572                                 ip = &name[offset];
 573                                 j = offset;
 574                                 end = 0;
 575                                 for (i = 0; i < 10; i += 2) {
 576                                         if (!end && j == len) {
 577                                                 end = 1;
 578                                                 ps->name0_4[i] = 0;
 579                                                 ps_mask->name0_4[i] = 0xff;
 580                                                 ps->name0_4[i+1] = 0;
 581                                                 ps_mask->name0_4[i] = 0xff;
 582                                                 continue;
 583                                         } else if (end) {
 584                                                 ps->name0_4[i] = 0xff;
 585                                                 ps_mask->name0_4[i] = 0xff;
 586                                                 ps->name0_4[i+1] = 0xff;
 587                                                 ps_mask->name0_4[i+1] = 0xff;
 588                                                 continue;
 589                                         }
 590                                         ps->name0_4[i] = fat_a2uni[*ip].uni1;
 591                                         ps->name0_4[i+1] = fat_a2uni[*ip].uni2;
 592                                         if ((*ip >= 'a' && *ip <= 'z') ||
 593                                             (*ip >= 'A' && *ip <= 'Z')) {
 594                                                 ps_mask->name0_4[i] = 0xdf;
 595                                         } else {
 596                                                 ps_mask->name0_4[i] = 0xff;
 597                                         }
 598                                         ps_mask->name0_4[i+1] = 0xff;
 599                                         j++; ip++;
 600                                 }
 601                                 PRINTK(("vfat_build_slots 6c\n"));
 602                                 for (i = 0; i < 12; i += 2) {
 603                                         if (!end && j == len) {
 604                                                 end = 1;
 605                                                 ps->name5_10[i] = 0;
 606                                                 ps->name5_10[i+1] = 0;
 607                                                 continue;
 608                                         } else if (end) {
 609                                                 ps->name5_10[i] = 0xff;
 610                                                 ps_mask->name5_10[i] = 0xff;
 611                                                 ps->name5_10[i+1] = 0xff;
 612                                                 ps_mask->name5_10[i+1] = 0xff;
 613                                                 continue;
 614                                         }
 615                                         ps->name5_10[i] = fat_a2uni[*ip].uni1;
 616                                         ps->name5_10[i+1] = fat_a2uni[*ip].uni2;
 617                                         if ((*ip >= 'a' && *ip <= 'z') ||
 618                                             (*ip >= 'A' && *ip <= 'Z')) {
 619                                                 ps_mask->name5_10[i] = 0xdf;
 620                                         } else {
 621                                                 ps_mask->name5_10[i] = 0xff;
 622                                         }
 623                                         ps_mask->name5_10[i+1] = 0xff;
 624                                         j++; ip++;
 625                                 }
 626                                 PRINTK(("vfat_build_slots 6d\n"));
 627                                 for (i = 0; i < 4; i += 2) {
 628                                         if (!end && j == len) {
 629                                                 end = 1;
 630                                                 ps->name11_12[i] = 0;
 631                                                 ps->name11_12[i+1] = 0;
 632                                                 continue;
 633                                         } else if (end) {
 634                                                 ps->name11_12[i] = 0xff;
 635                                                 ps_mask->name11_12[i] = 0xff;
 636                                                 ps->name11_12[i+1] = 0xff;
 637                                                 ps_mask->name11_12[i+1] = 0xff;
 638                                                 continue;
 639                                         }
 640                                         ps->name11_12[i] = fat_a2uni[*ip].uni1;
 641                                         ps->name11_12[i+1] = fat_a2uni[*ip].uni2;
 642                                         if ((*ip >= 'a' && *ip <= 'z') ||
 643                                             (*ip >= 'A' && *ip <= 'Z')) {
 644                                                 ps_mask->name11_12[i] = 0xdf;
 645                                         } else {
 646                                                 ps_mask->name11_12[i] = 0xff;
 647                                         }
 648                                         ps_mask->name11_12[i+1] = 0xff;
 649                                         j++; ip++;
 650                                 }
 651                         }
 652                         PRINTK(("vfat_build_slots 6e\n"));
 653                         ds[0].id |= 0x40;
 654 
 655                         if (new_filename) {
 656                                 de = (struct msdos_dir_entry *) ps;
 657                                 de_mask = (struct msdos_dir_entry *) ps_mask;
 658 
 659                                 PRINTK(("vfat_build_slots 10\n"));
 660                                 strncpy(de->name, msdos_name, MSDOS_NAME);
 661                                 memset(de_mask->name, 0xff, MSDOS_NAME);
 662                         }
 663                 }
 664         }
 665         return 0;
 666 }
 667 
 668 /* Given a shortname offset, see if there is an associated longname.  Returns
 669  * the number of slots in the longname if one is found, else 0 */
 670 static int vfat_get_longname(struct inode *dir,loff_t short_offset,
     /* [previous][next][first][last][top][bottom][index][help] */
 671      unsigned char checksum, loff_t *pos_out)
 672 {
 673         struct super_block *sb = dir->i_sb;
 674         struct msdos_dir_slot *ps;
 675         struct msdos_dir_entry *de;
 676         struct buffer_head *bh;
 677         loff_t offset, temp;
 678         int id, res, slots;
 679 
 680         /* printk("Short offset: %d\n", short_offset); */
 681         if (short_offset == 0) {
 682                 return 0;
 683         }
 684 
 685         slots = 0;
 686         id = 1;
 687         bh = NULL;
 688         offset = short_offset - sizeof(struct msdos_dir_slot);
 689         while (offset > 0) {
 690                 temp = offset;
 691                 res = fat_get_entry(dir,&temp,&bh,&de);
 692                 if (res < 0) goto finish;
 693                 ps = (struct msdos_dir_slot *) de;
 694                 if (ps->alias_checksum != checksum) goto finish;
 695                 if ((ps->id &~ 0x40) != id) goto finish;
 696                 if (IS_FREE(de->name)) goto finish;
 697                 if (ps->id & 0x40) {
 698                         *pos_out = offset;
 699                         slots = ps->id &~ 0x40;
 700                         /* printk("Found a longname for the shortname: long_offset=%ld\n", offset); */
 701                         goto finish;
 702                 }
 703                 offset -= sizeof(struct msdos_dir_slot);
 704                 id++;
 705         }
 706  finish:
 707         if (bh) brelse(bh);
 708         return slots;
 709 }
 710 
 711 static int vfat_find(struct inode *dir,const char *name,int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 712     int find_long, int new_filename,int is_dir,struct slot_info *sinfo_out)
 713 {
 714         struct super_block *sb = dir->i_sb;
 715         const char *ip;
 716         char *op, *op_mask;
 717         int res;
 718         struct msdos_dir_slot ds[MSDOS_SLOTS], ds_mask[MSDOS_SLOTS];
 719         struct msdos_dir_slot *ps;
 720         struct msdos_dir_entry *de, *de_mask;
 721         struct buffer_head *bh;
 722         int i, slot, slots;
 723         loff_t offset, start;
 724         int match;
 725         int is_long;
 726         unsigned char alias_checksum = 0;
 727 
 728         PRINTK(("vfat_find 1: name=%s, len=%d\n",name,len));
 729 
 730         res = vfat_build_slots(dir, name, len, find_long, new_filename,
 731                                 ds, ds_mask, &slots, &is_long);
 732         if (res < 0) return res;
 733 
 734         de = (struct msdos_dir_entry *) ds;
 735         de_mask = (struct msdos_dir_entry *) ds_mask;
 736 
 737         PRINTK(("vfat_find 7\n"));
 738         offset = start = 0;
 739         bh = NULL;
 740         sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de);
 741         while (sinfo_out->ino > -1 && slots > 0) {
 742                 match = 1;
 743 
 744                 ps = (struct msdos_dir_slot *) de;
 745                 alias_checksum = ps->alias_checksum;
 746 
 747                 for (slot = 0; slot < slots; slot++) {
 748                         ip = (char *) de;
 749                         ps = (struct msdos_dir_slot *) de;
 750                         if (is_long && ps->alias_checksum != alias_checksum) {
 751                                 printk("Checksums don't match 1\n");
 752                                 match = 0;
 753                                 start = offset;
 754                                 break;
 755                         }
 756 
 757                         for (i = 0, ip = (char *) de, op = (char *) &ds[slot], op_mask = (char *) &ds_mask[slot];
 758                              i < sizeof(struct msdos_dir_entry);
 759                              i++, ip++, op++, op_mask++)
 760                         {
 761 #if 0
 762                                 if (is_long && de->attr == ATTR_EXT)
 763                                         printk("%02x?%02x ",
 764                                                (unsigned char) *ip,
 765                                                (unsigned char) *op);
 766 #endif
 767                                 if ((*ip & *op_mask) != (*op & *op_mask)) {
 768                                         start = offset;
 769                                         match = 0;
 770                                         break;
 771                                 }
 772                         }
 773 #if 0
 774                         if (is_long && de->attr == ATTR_EXT) printk("\n");
 775 #endif
 776                         if ((!is_long && !match) ||
 777                             (de->attr == ATTR_VOLUME) ||
 778                             (is_long && (match || slot == 0)))
 779                         {
 780                                 sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de);
 781                                 /* if (ino >=0 && de->attr == ATTR_EXT) dump_de(de); */
 782                         }
 783                         if (!match) {
 784                                 break;
 785                         }
 786                         if (sinfo_out->ino == -1) {
 787                                 match = 0;
 788                                 goto breakout;
 789                         }
 790                 }
 791                 if (match) {
 792                         unsigned char sum;
 793 
 794                         for (sum = i = 0; i < 11; i++) {
 795                                 sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
 796                         }
 797 
 798                         if (is_long) {
 799                                 if (sum != alias_checksum) {
 800                                         PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum));
 801                                         match = 0;
 802                                 }
 803                         } else {
 804                                 int long_slots;
 805                                 long_slots = vfat_get_longname(dir, offset - sizeof(struct msdos_dir_entry), sum, &start);
 806                                 if (long_slots > 0) {
 807                                         slots = long_slots;
 808                                         is_long = 1;
 809                                 }
 810                         }
 811 
 812                                 
 813                         if (match) {
 814                                 PRINTK(("name: %s, alias: %c%c%c%c%c%c%c%c%c%c%c\n",
 815                                         name,
 816                                         de->name[0], de->name[1], de->name[2],
 817                                         de->name[3], de->name[4], de->name[5],
 818                                         de->name[6], de->name[7], de->name[8],
 819                                         de->name[9], de->name[10]));
 820                                 PRINTK(("vfat_find 10\n"));
 821                                 res = CF_LE_W(de->start);
 822 
 823                                 sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot);
 824                                 sinfo_out->longname_offset = start;
 825                                 sinfo_out->is_long = is_long;
 826                                 if (is_long) {
 827                                         sinfo_out->long_slots = slots;
 828                                         slots++;
 829                                 } else {
 830                                         sinfo_out->long_slots = 0;
 831                                 }
 832 
 833                                 sinfo_out->total_slots = slots;
 834                                 if (new_filename) {
 835                                         if (bh) brelse(bh);
 836                                         return -EEXIST;
 837                                 }
 838                                 if (bh) brelse(bh);
 839                                 return res;
 840                         }
 841                 }
 842         }
 843  breakout:
 844         PRINTK(("breakout\n"));
 845 
 846         if (bh) brelse(bh);
 847         if (new_filename) {
 848                 PRINTK(("vfat_find: create file 1\n"));
 849                 if (is_long) slots++;
 850                 offset = vfat_find_free_slots(dir, slots);
 851                 if (offset < 0) {
 852                         return offset;
 853                 }
 854 
 855                 PRINTK(("vfat_find: create file 2\n"));
 856                 /* Now create the new entry */
 857                 bh = NULL;
 858                 for (slot = 0, ps = ds; slot < slots; slot++, ps++) {
 859                         PRINTK(("vfat_find: create file 3, slot=%d\n",slot));
 860                         sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de);
 861                         if (sinfo_out->ino < 0) {
 862                                 PRINTK(("vfat_find: problem\n"));
 863                                 return sinfo_out->ino;
 864                         }
 865                         memcpy(de, ps, sizeof(struct msdos_dir_slot));
 866                         mark_buffer_dirty(bh, 1);
 867                 }
 868 
 869                 PRINTK(("vfat_find: create file 4\n"));
 870                 dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
 871                 dir->i_dirt = 1;
 872 
 873                 PRINTK(("vfat_find: create file 5\n"));
 874 
 875                 memset(de->unused, 0, sizeof(de->unused));
 876                 fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
 877                 de->ctime_ms = 0;
 878                 de->ctime = de->time;
 879                 de->adate = de->cdate = de->date;
 880                 de->start = 0;
 881                 de->size = 0;
 882                 de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
 883                 de->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT;
 884 
 885 
 886                 mark_buffer_dirty(bh, 1);
 887                 brelse(bh);
 888 
 889                 sinfo_out->is_long = (slots > 1) ? 1 : 0;
 890                 if (sinfo_out->is_long) {
 891                         sinfo_out->long_slots = slots - 1;
 892                 } else {
 893                         sinfo_out->long_slots = 0;
 894                 }
 895                 sinfo_out->total_slots = slots;
 896                 sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot);
 897                 sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
 898                 return 0;
 899         }
 900 
 901         return -ENOENT;
 902 }
 903 
 904 int vfat_lookup(struct inode *dir,const char *name,int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 905     struct inode **result)
 906 {
 907         int res, ino;
 908         struct inode *next;
 909         struct slot_info sinfo;
 910         
 911         PRINTK (("vfat_lookup: name=%s, len=%d\n", name, len));
 912 
 913         *result = NULL;
 914         if (!dir) return -ENOENT;
 915         if (!S_ISDIR(dir->i_mode)) {
 916                 iput(dir);
 917                 return -ENOENT;
 918         }
 919         PRINTK (("vfat_lookup 2\n"));
 920         if (len == 1 && name[0] == '.') {
 921                 *result = dir;
 922                 return 0;
 923         }
 924         if (len == 2 && name[0] == '.' && name[1] == '.') {
 925                 ino = fat_parent_ino(dir,0);
 926                 iput(dir);
 927                 if (ino < 0) return ino;
 928                 if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
 929                 return 0;
 930         }
 931         PRINTK (("vfat_lookup 3\n"));
 932         if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0) {
 933                 iput(dir);
 934                 return res;
 935         }
 936         PRINTK (("vfat_lookup 4.5\n"));
 937         if (!(*result = iget(dir->i_sb,sinfo.ino))) {
 938                 iput(dir);
 939                 return -EACCES;
 940         }
 941         PRINTK (("vfat_lookup 5\n"));
 942         if (!(*result)->i_sb ||
 943             ((*result)->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
 944                 /* crossed a mount point into a non-msdos fs */
 945                 iput(dir);
 946                 return 0;
 947         }
 948         if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */
 949                 iput(*result);
 950                 iput(dir);
 951                 return -ENOENT;
 952         }
 953         PRINTK (("vfat_lookup 6\n"));
 954         while (MSDOS_I(*result)->i_old) {
 955                 next = MSDOS_I(*result)->i_old;
 956                 iput(*result);
 957                 if (!(*result = iget(next->i_sb,next->i_ino))) {
 958                         fat_fs_panic(dir->i_sb,"vfat_lookup: Can't happen");
 959                         iput(dir);
 960                         return -ENOENT;
 961                 }
 962         }
 963         iput(dir);
 964         return 0;
 965 }
 966 
 967 
 968 static int vfat_create_entry(struct inode *dir,const char *name,int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 969     int is_dir, struct inode **result)
 970 {
 971         struct super_block *sb = dir->i_sb;
 972         int res,ino;
 973         loff_t offset;
 974         struct buffer_head *bh;
 975         struct msdos_dir_entry *de;
 976         struct slot_info sinfo;
 977 
 978         PRINTK(("vfat_create_entry 1\n"));
 979         res = vfat_find(dir, name, len, 1, 1, is_dir, &sinfo);
 980         if (res < 0) {
 981                 return res;
 982         }
 983 
 984         offset = sinfo.shortname_offset;
 985 
 986         PRINTK(("vfat_create_entry 2\n"));
 987         bh = NULL;
 988         ino = fat_get_entry(dir, &offset, &bh, &de);
 989         if (ino < 0) {
 990                 PRINTK(("vfat_mkdir problem\n"));
 991                 if (bh) brelse(bh);
 992                 return ino;
 993         }
 994         PRINTK(("vfat_create_entry 3\n"));
 995 
 996         if ((*result = iget(dir->i_sb,ino)) != NULL)
 997                 vfat_read_inode(*result);
 998         brelse(bh);
 999         if (!*result) return -EIO;
1000         (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
1001             CURRENT_TIME;
1002         (*result)->i_dirt = 1;
1003 
1004         return 0;
1005 }
1006 
1007 int vfat_create(struct inode *dir,const char *name,int len,int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
1008         struct inode **result)
1009 {
1010         int res;
1011 
1012         if (!dir) return -ENOENT;
1013 
1014         fat_lock_creation();
1015         if ((res = vfat_create_entry(dir,name,len,0,result)) < 0) {
1016                 printk("vfat_create: unable to get new entry\n");
1017                 fat_unlock_creation();
1018                 iput(dir);
1019                 return res;
1020         }
1021 
1022         fat_unlock_creation();
1023         iput(dir);
1024         return res;
1025 }
1026 
1027 static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent,
     /* [previous][next][first][last][top][bottom][index][help] */
1028      struct buffer_head *bh,
1029      struct msdos_dir_entry *de,int ino,const char *name, int isdot)
1030 {
1031         struct super_block *sb = dir->i_sb;
1032         struct inode *dot;
1033 
1034         PRINTK(("vfat_create_a_dotdir 1\n"));
1035 
1036         /*
1037          * XXX all times should be set by caller upon successful completion.
1038          */
1039         dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
1040         dir->i_dirt = 1;
1041         memcpy(de->name,name,MSDOS_NAME);
1042         memset(de->unused, 0, sizeof(de->unused));
1043         de->lcase = 0;
1044         de->attr = ATTR_DIR;
1045         de->start = 0;
1046         fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
1047         de->ctime_ms = 0;
1048         de->ctime = de->time;
1049         de->adate = de->cdate = de->date;
1050         de->size = 0;
1051         mark_buffer_dirty(bh, 1);
1052         if ((dot = iget(dir->i_sb,ino)) != NULL)
1053                 vfat_read_inode(dot);
1054         if (!dot) return -EIO;
1055         dot->i_mtime = dot->i_atime = CURRENT_TIME;
1056         dot->i_dirt = 1;
1057         if (isdot) {
1058                 dot->i_size = dir->i_size;
1059                 MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
1060                 dot->i_nlink = dir->i_nlink;
1061         } else {
1062                 dot->i_size = parent->i_size;
1063                 MSDOS_I(dot)->i_start = MSDOS_I(parent)->i_start;
1064                 dot->i_nlink = parent->i_nlink;
1065         }
1066 
1067         iput(dot);
1068 
1069         PRINTK(("vfat_create_a_dotdir 2\n"));
1070         return 0;
1071 }
1072 
1073 static int vfat_create_dotdirs(struct inode *dir, struct inode *parent)
     /* [previous][next][first][last][top][bottom][index][help] */
1074 {
1075         struct super_block *sb = dir->i_sb;
1076         int res;
1077         struct buffer_head *bh;
1078         struct msdos_dir_entry *de;
1079         loff_t offset;
1080 
1081         PRINTK(("vfat_create_dotdirs 1\n"));
1082         if ((res = fat_add_cluster(dir)) < 0) return res;
1083 
1084         PRINTK(("vfat_create_dotdirs 2\n"));
1085         offset = 0;
1086         bh = NULL;
1087         if ((res = fat_get_entry(dir,&offset,&bh,&de)) < 0) return res;
1088         
1089         PRINTK(("vfat_create_dotdirs 3\n"));
1090         res = vfat_create_a_dotdir(dir, parent, bh, de, res, MSDOS_DOT, 1);
1091         PRINTK(("vfat_create_dotdirs 4\n"));
1092         if (res < 0) {
1093                 brelse(bh);
1094                 return res;
1095         }
1096         PRINTK(("vfat_create_dotdirs 5\n"));
1097 
1098         if ((res = fat_get_entry(dir,&offset,&bh,&de)) < 0) {
1099                 brelse(bh);
1100                 return res;
1101         }
1102         PRINTK(("vfat_create_dotdirs 6\n"));
1103 
1104         res = vfat_create_a_dotdir(dir, parent, bh, de, res, MSDOS_DOTDOT, 0);
1105         PRINTK(("vfat_create_dotdirs 7\n"));
1106         brelse(bh);
1107 
1108         return res;
1109 }
1110 
1111 /***** See if directory is empty */
1112 static int vfat_empty(struct inode *dir)
     /* [previous][next][first][last][top][bottom][index][help] */
1113 {
1114         struct super_block *sb = dir->i_sb;
1115         loff_t pos;
1116         struct buffer_head *bh;
1117         struct msdos_dir_entry *de;
1118 
1119         if (dir->i_count > 1)
1120                 return -EBUSY;
1121         if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
1122                 pos = 0;
1123                 bh = NULL;
1124                 while (fat_get_entry(dir,&pos,&bh,&de) > -1)
1125                         /* Skip extended filename entries */
1126                         if (de->attr == ATTR_EXT) continue;
1127 
1128                         if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
1129                             MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
1130                             MSDOS_NAME)) {
1131                                 brelse(bh);
1132                                 return -ENOTEMPTY;
1133                         }
1134                 if (bh)
1135                         brelse(bh);
1136         }
1137         return 0;
1138 }
1139 
1140 static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh,
     /* [previous][next][first][last][top][bottom][index][help] */
1141      struct msdos_dir_entry *de,int ino)
1142 {
1143         struct super_block *sb = dir->i_sb;
1144         struct inode *inode;
1145         int res;
1146 
1147         if (ino < 0) return -EINVAL;
1148         if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
1149         if (!S_ISDIR(inode->i_mode)) {
1150                 iput(inode);
1151                 return -ENOTDIR;
1152         }
1153         if (dir->i_dev != inode->i_dev || dir == inode) {
1154                 iput(inode);
1155                 return -EBUSY;
1156         }
1157         res = vfat_empty(inode);
1158         if (res) {
1159                 iput(inode);
1160                 return res;
1161         }
1162         inode->i_nlink = 0;
1163         inode->i_mtime = dir->i_mtime = CURRENT_TIME;
1164         inode->i_atime = dir->i_atime = CURRENT_TIME;
1165         dir->i_nlink--;
1166         inode->i_dirt = dir->i_dirt = 1;
1167         de->name[0] = DELETED_FLAG;
1168         mark_buffer_dirty(bh, 1);
1169         iput(inode);
1170 
1171         return 0;
1172 }
1173 
1174 static int vfat_unlink_free_ino(struct inode *dir,struct buffer_head *bh,
     /* [previous][next][first][last][top][bottom][index][help] */
1175      struct msdos_dir_entry *de,int ino,int nospc)
1176 {
1177         struct super_block *sb = dir->i_sb;
1178         struct inode *inode;
1179         if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
1180         if (!S_ISREG(inode->i_mode) && nospc) {
1181                 iput(inode);
1182                 return -EPERM;
1183         }
1184         if (IS_IMMUTABLE(inode)){
1185                 iput(inode);
1186                 return -EPERM;
1187         }
1188         inode->i_nlink = 0;
1189         inode->i_mtime = dir->i_mtime = CURRENT_TIME;
1190         inode->i_atime = dir->i_atime = CURRENT_TIME;
1191         MSDOS_I(inode)->i_busy = 1;
1192         inode->i_dirt = dir->i_dirt = 1;
1193         de->name[0] = DELETED_FLAG;
1194         mark_buffer_dirty(bh, 1);
1195 
1196         iput(inode);
1197         return 0;
1198 }
1199 
1200 static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo,
     /* [previous][next][first][last][top][bottom][index][help] */
1201      struct buffer_head **bh,struct msdos_dir_entry **de,
1202      int is_dir,int nospc)
1203 {
1204         struct super_block *sb = dir->i_sb;
1205         loff_t offset;
1206         int res, i;
1207 
1208         /* remove the shortname */
1209         offset = sinfo->shortname_offset;
1210         res = fat_get_entry(dir, &offset, bh, de);
1211         if (res < 0) return res;
1212         if (is_dir) {
1213                 res = vfat_rmdir_free_ino(dir,*bh,*de,res);
1214         } else {
1215                 res = vfat_unlink_free_ino(dir,*bh,*de,res,nospc);
1216         }
1217         if (res < 0) return res;
1218                 
1219         /* remove the longname */
1220         offset = sinfo->longname_offset;
1221         for (i = sinfo->long_slots; i > 0; --i) {
1222                 res = fat_get_entry(dir, &offset, bh, de);
1223                 if (res < 0) {
1224                         printk("vfat_remove_entry: problem 1\n");
1225                         continue;
1226                 }
1227                 (*de)->name[0] = DELETED_FLAG;
1228                 (*de)->attr = 0;
1229                 mark_buffer_dirty(*bh, 1);
1230         }
1231         return 0;
1232 }
1233 
1234 
1235 static int vfat_rmdirx(struct inode *dir,const char *name,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1236 {
1237         struct super_block *sb = dir->i_sb;
1238         int res;
1239         struct buffer_head *bh;
1240         struct msdos_dir_entry *de;
1241         struct slot_info sinfo;
1242 
1243         bh = NULL;
1244         res = -EPERM;
1245         if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
1246                 goto rmdir_done;
1247         res = vfat_find(dir,name,len,1,0,0,&sinfo);
1248 
1249         if (res >= 0 && sinfo.total_slots > 0) {
1250                 res = vfat_remove_entry(dir,&sinfo,&bh,&de,1,0);
1251                 if (res > 0) {
1252                         res = 0;
1253                 }
1254         } else {
1255                 printk("Problem in vfat_rmdirx\n");
1256         }
1257 
1258 rmdir_done:
1259         brelse(bh);
1260         return res;
1261 }
1262 
1263 /***** Remove a directory */
1264 int vfat_rmdir(struct inode *dir,const char *name,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1265 {
1266         int res;
1267 
1268         res = vfat_rmdirx(dir, name, len);
1269         iput(dir);
1270         return res;
1271 }
1272 
1273 static int vfat_unlinkx(
     /* [previous][next][first][last][top][bottom][index][help] */
1274         struct inode *dir,
1275         const char *name,
1276         int len,
1277         int nospc)      /* Flag special file ? */
1278 {
1279         struct super_block *sb = dir->i_sb;
1280         int res;
1281         struct buffer_head *bh;
1282         struct msdos_dir_entry *de;
1283         struct slot_info sinfo;
1284 
1285         bh = NULL;
1286         if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0)
1287                 goto unlink_done;
1288 
1289         if (res >= 0 && sinfo.total_slots > 0) {
1290                 res = vfat_remove_entry(dir,&sinfo,&bh,&de,0,nospc);
1291                 if (res > 0) {
1292                         res = 0;
1293                 }
1294         } else {
1295                 printk("Problem in vfat_unlinkx: res=%d, total_slots=%d\n",res, sinfo.total_slots);
1296         }
1297 
1298 unlink_done:
1299         brelse(bh);
1300         return res;
1301 }
1302 
1303 
1304 int vfat_mkdir(struct inode *dir,const char *name,int len,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
1305 {
1306         struct inode *inode;
1307         int res;
1308 
1309         fat_lock_creation();
1310         if ((res = vfat_create_entry(dir,name,len,1,&inode)) < 0) {
1311                 fat_unlock_creation();
1312                 iput(dir);
1313                 return res;
1314         }
1315 
1316         dir->i_nlink++;
1317         inode->i_nlink = 2; /* no need to mark them dirty */
1318         MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
1319 
1320         res = vfat_create_dotdirs(inode, dir);
1321         fat_unlock_creation();
1322         MSDOS_I(inode)->i_busy = 0;
1323         iput(inode);
1324         iput(dir);
1325         if (res < 0) {
1326                 if (vfat_rmdir(dir,name,len) < 0)
1327                         fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
1328         }
1329         return res;
1330 }
1331 
1332 /***** Unlink, as called for msdosfs */
1333 int vfat_unlink(struct inode *dir,const char *name,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1334 {
1335         int res;
1336 
1337         res = vfat_unlinkx (dir,name,len,1);
1338         iput(dir);
1339         return res;
1340 }
1341 
1342 
1343 int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
1344         struct inode *new_dir,const char *new_name,int new_len)
1345 {
1346         struct super_block *sb = old_dir->i_sb;
1347         struct buffer_head *old_bh,*new_bh,*dotdot_bh;
1348         struct msdos_dir_entry *old_de,*new_de,*dotdot_de;
1349         loff_t old_offset,new_offset,old_longname_offset;
1350         int old_slots,old_ino,new_ino,dotdot_ino,ino;
1351         struct inode *old_inode, *new_inode, *dotdot_inode, *walk;
1352         int res, is_dir, i;
1353         int locked = 0;
1354         struct slot_info sinfo;
1355 
1356         PRINTK(("vfat_rename 1\n"));
1357         if (old_dir == new_dir && old_len == new_len &&
1358             strncmp(old_name, new_name, old_len) == 0)
1359                 return 0;
1360 
1361         old_bh = new_bh = NULL;
1362         old_inode = new_inode = NULL;
1363         res = vfat_find(old_dir,old_name,old_len,1,0,0,&sinfo);
1364         PRINTK(("vfat_rename 2\n"));
1365         if (res < 0) goto rename_done;
1366 
1367         old_slots = sinfo.total_slots;
1368         old_longname_offset = sinfo.longname_offset;
1369         old_offset = sinfo.shortname_offset;
1370         old_ino = sinfo.ino;
1371         res = fat_get_entry(old_dir, &old_offset, &old_bh, &old_de);
1372         PRINTK(("vfat_rename 3\n"));
1373         if (res < 0) goto rename_done;
1374 
1375         if (!(old_inode = iget(old_dir->i_sb,old_ino))) goto rename_done;
1376         is_dir = S_ISDIR(old_inode->i_mode);
1377         if (is_dir) {
1378                 if ((old_dir->i_dev != new_dir->i_dev) ||
1379                     (old_ino == new_dir->i_ino)) {
1380                         res = -EINVAL;
1381                         goto rename_done;
1382                 }
1383                 if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
1384                 /* prevent moving directory below itself */
1385                 while (walk->i_ino != MSDOS_ROOT_INO) {
1386                         ino = fat_parent_ino(walk,1);
1387                         iput(walk);
1388                         if (ino < 0) return ino;
1389                         if (ino == old_ino) return -EINVAL;
1390                         if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
1391                 }
1392                 iput(walk);
1393         }
1394 
1395         res = vfat_find(new_dir,new_name,new_len,1,0,is_dir,&sinfo);
1396 
1397         PRINTK(("vfat_rename 4\n"));
1398         if (res > -1) {
1399                 int new_is_dir;
1400 
1401                 PRINTK(("vfat_rename 5\n"));
1402                 /* Filename currently exists.  Need to delete it */
1403                 new_offset = sinfo.shortname_offset;
1404                 res = fat_get_entry(new_dir, &new_offset, &new_bh, &new_de);
1405                 PRINTK(("vfat_rename 6\n"));
1406                 if (res < 0) goto rename_done;
1407 
1408                 if (!(new_inode = iget(new_dir->i_sb,res)))
1409                         goto rename_done;
1410                 new_is_dir = S_ISDIR(new_inode->i_mode);
1411                 iput(new_inode);
1412                 if (new_is_dir) {
1413                         PRINTK(("vfat_rename 7\n"));
1414                         res = vfat_rmdirx(new_dir,new_name,new_len);
1415                         PRINTK(("vfat_rename 8\n"));
1416                         if (res < 0) goto rename_done;
1417                 } else {
1418                         PRINTK(("vfat_rename 9\n"));
1419                         res = vfat_unlinkx(new_dir,new_name,new_len,1);
1420                         PRINTK(("vfat_rename 10\n"));
1421                         if (res < 0) goto rename_done;
1422                 }
1423         }
1424 
1425         PRINTK(("vfat_rename 11\n"));
1426         fat_lock_creation(); locked = 1;
1427         res = vfat_find(new_dir,new_name,new_len,1,1,is_dir,&sinfo);
1428 
1429         PRINTK(("vfat_rename 12\n"));
1430         if (res < 0) goto rename_done;
1431 
1432         new_offset = sinfo.shortname_offset;
1433         new_ino = sinfo.ino;
1434         res = fat_get_entry(new_dir, &new_offset, &new_bh, &new_de);
1435         PRINTK(("vfat_rename 13\n"));
1436         if (res < 0) goto rename_done;
1437 
1438         new_de->attr = old_de->attr;
1439         new_de->time = old_de->time;
1440         new_de->date = old_de->date;
1441         new_de->ctime_ms = old_de->ctime_ms;
1442         new_de->cdate = old_de->cdate;
1443         new_de->adate = old_de->adate;
1444         new_de->start = old_de->start;
1445         new_de->size = old_de->size;
1446 
1447         if (!(new_inode = iget(new_dir->i_sb,new_ino))) goto rename_done;
1448         PRINTK(("vfat_rename 14\n"));
1449 
1450         /* At this point, we have the inodes of the old file and the
1451          * new file.  We need to transfer all information from the old
1452          * inode to the new inode and then delete the slots of the old
1453          * entry
1454          */
1455 
1456         vfat_read_inode(new_inode);
1457         MSDOS_I(old_inode)->i_busy = 1;
1458         fat_cache_inval_inode(old_inode);
1459         PRINTK(("vfat_rename 15: old_slots=%d\n",old_slots));
1460         old_inode->i_dirt = 1;
1461 
1462         /* remove the old entry */
1463         for (i = old_slots; i > 0; --i) {
1464                 res = fat_get_entry(old_dir, &old_longname_offset, &old_bh, &old_de);
1465                 if (res < 0) {
1466                         printk("vfat_unlinkx: problem 1\n");
1467                         continue;
1468                 }
1469                 old_de->name[0] = DELETED_FLAG;
1470                 old_de->attr = 0;
1471                 mark_buffer_dirty(old_bh, 1);
1472         }
1473         PRINTK(("vfat_rename 15b\n"));
1474 
1475         mark_buffer_dirty(new_bh, 1);
1476         iput(new_inode);
1477         /* XXX: There is some code in the original MSDOS rename that
1478          * is not duplicated here and it might cause a problem in
1479          * certain circumstances.
1480          */
1481         
1482         if (S_ISDIR(old_inode->i_mode)) {
1483                 if ((res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
1484                     &dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done;
1485                 if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
1486                         brelse(dotdot_bh);
1487                         res = -EIO;
1488                         goto rename_done;
1489                 }
1490                 dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
1491                     MSDOS_I(new_dir)->i_start;
1492                 dotdot_inode->i_dirt = 1;
1493                 mark_buffer_dirty(dotdot_bh, 1);
1494                 old_dir->i_nlink--;
1495                 new_dir->i_nlink++;
1496                 /* no need to mark them dirty */
1497                 dotdot_inode->i_nlink = new_dir->i_nlink;
1498                 iput(dotdot_inode);
1499                 brelse(dotdot_bh);
1500         }
1501 
1502         if (res > 0) res = 0;
1503 
1504 rename_done:
1505         if (locked) fat_unlock_creation();
1506         if (old_bh) brelse(old_bh);
1507         if (new_bh) brelse(new_bh);
1508         if (old_inode) iput(old_inode);
1509         iput(old_dir);
1510         iput(new_dir);
1511         return res;
1512 }
1513 
1514 
1515 
1516 /* Public inode operations for the VFAT fs */
1517 struct inode_operations vfat_dir_inode_operations = {
1518         &fat_dir_operations,    /* default directory file-ops */
1519         vfat_create,            /* create */
1520         vfat_lookup,            /* lookup */
1521         NULL,                   /* link */
1522         vfat_unlink,            /* unlink */
1523         NULL,                   /* symlink */
1524         vfat_mkdir,             /* mkdir */
1525         vfat_rmdir,             /* rmdir */
1526         NULL,                   /* mknod */
1527         vfat_rename,            /* rename */
1528         NULL,                   /* readlink */
1529         NULL,                   /* follow_link */
1530         NULL,                   /* readpage */
1531         NULL,                   /* writepage */
1532         fat_bmap,               /* bmap */
1533         NULL,                   /* truncate */
1534         NULL                    /* permission */
1535 };
1536 
1537 
1538 void vfat_read_inode(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
1539 {
1540         fat_read_inode(inode, &vfat_dir_inode_operations);
1541 }
1542 
1543 
1544 
1545 
1546 static struct file_system_type vfat_fs_type = {
1547         vfat_read_super, "vfat", 1, NULL
1548 };
1549 
1550 int init_vfat_fs(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1551 {
1552         int status;
1553 
1554         if ((status = register_filesystem(&vfat_fs_type)) == 0)
1555                 status = register_symtab(0);
1556         return status;
1557 }
1558 
1559 #ifdef MODULE
1560 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1561 {
1562         return init_vfat_fs();
1563 }
1564 
1565 
1566 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1567 {
1568         unregister_filesystem(&vfat_fs_type);
1569 }
1570 
1571 #endif /* ifdef MODULE */
1572 
1573 
1574 
1575 /*
1576  * Overrides for Emacs so that we follow Linus's tabbing style.
1577  * Emacs will notice this stuff at the end of the file and automatically
1578  * adjust the settings for this buffer only.  This must remain at the end
1579  * of the file.
1580  * ---------------------------------------------------------------------------
1581  * Local variables:
1582  * c-indent-level: 8
1583  * c-brace-imaginary-offset: 0
1584  * c-brace-offset: -8
1585  * c-argdecl-indent: 8
1586  * c-label-offset: -8
1587  * c-continued-statement-offset: 8
1588  * c-continued-brace-offset: 0
1589  * End:
1590  */

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