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

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