aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fat/dir.c131
1 files changed, 67 insertions, 64 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index b57c4b1db636..a4410740627f 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -123,10 +123,11 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos,
123 * but ignore that right now. 123 * but ignore that right now.
124 * Ahem... Stack smashing in ring 0 isn't fun. Fixed. 124 * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
125 */ 125 */
126static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len, 126static int uni16_to_x8(unsigned char *ascii, const wchar_t *uni, int len,
127 int uni_xlate, struct nls_table *nls) 127 int uni_xlate, struct nls_table *nls)
128{ 128{
129 wchar_t *ip, ec; 129 const wchar_t *ip;
130 wchar_t ec;
130 unsigned char *op, nc; 131 unsigned char *op, nc;
131 int charlen; 132 int charlen;
132 int k; 133 int k;
@@ -166,6 +167,16 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len,
166 return (op - ascii); 167 return (op - ascii);
167} 168}
168 169
170static inline int fat_uni_to_x8(struct msdos_sb_info *sbi, const wchar_t *uni,
171 unsigned char *buf, int size)
172{
173 if (sbi->options.utf8)
174 return utf8_wcstombs(buf, uni, size);
175 else
176 return uni16_to_x8(buf, uni, size, sbi->options.unicode_xlate,
177 sbi->nls_io);
178}
179
169static inline int 180static inline int
170fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) 181fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni)
171{ 182{
@@ -226,6 +237,19 @@ fat_shortname2uni(struct nls_table *nls, unsigned char *buf, int buf_size,
226 return len; 237 return len;
227} 238}
228 239
240static inline int fat_name_match(struct msdos_sb_info *sbi,
241 const unsigned char *a, int a_len,
242 const unsigned char *b, int b_len)
243{
244 if (a_len != b_len)
245 return 0;
246
247 if (sbi->options.name_check != 's')
248 return !nls_strnicmp(sbi->nls_io, a, b, a_len);
249 else
250 return !memcmp(a, b, a_len);
251}
252
229enum { PARSE_INVALID = 1, PARSE_NOT_LONGNAME, PARSE_EOF, }; 253enum { PARSE_INVALID = 1, PARSE_NOT_LONGNAME, PARSE_EOF, };
230 254
231/** 255/**
@@ -311,29 +335,24 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
311 struct msdos_sb_info *sbi = MSDOS_SB(sb); 335 struct msdos_sb_info *sbi = MSDOS_SB(sb);
312 struct buffer_head *bh = NULL; 336 struct buffer_head *bh = NULL;
313 struct msdos_dir_entry *de; 337 struct msdos_dir_entry *de;
314 struct nls_table *nls_io = sbi->nls_io;
315 struct nls_table *nls_disk = sbi->nls_disk; 338 struct nls_table *nls_disk = sbi->nls_disk;
316 wchar_t bufuname[14];
317 unsigned char nr_slots; 339 unsigned char nr_slots;
318 int xlate_len; 340 wchar_t bufuname[14];
319 wchar_t *unicode = NULL; 341 wchar_t *unicode = NULL;
320 unsigned char work[MSDOS_NAME]; 342 unsigned char work[MSDOS_NAME];
321 unsigned char *bufname = NULL; 343 unsigned char *bufname = NULL;
322 int uni_xlate = sbi->options.unicode_xlate;
323 int utf8 = sbi->options.utf8;
324 int anycase = (sbi->options.name_check != 's');
325 unsigned short opt_shortname = sbi->options.shortname; 344 unsigned short opt_shortname = sbi->options.shortname;
326 loff_t cpos = 0; 345 loff_t cpos = 0;
327 int chl, i, j, last_u, err; 346 int chl, i, j, last_u, err, len;
328 347
329 bufname = __getname(); 348 bufname = __getname();
330 if (!bufname) 349 if (!bufname)
331 return -ENOMEM; 350 return -ENOMEM;
332 351
333 err = -ENOENT; 352 err = -ENOENT;
334 while(1) { 353 while (1) {
335 if (fat_get_entry(inode, &cpos, &bh, &de) == -1) 354 if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
336 goto EODir; 355 goto end_of_dir;
337parse_record: 356parse_record:
338 nr_slots = 0; 357 nr_slots = 0;
339 if (de->name[0] == DELETED_FLAG) 358 if (de->name[0] == DELETED_FLAG)
@@ -352,7 +371,7 @@ parse_record:
352 else if (status == PARSE_NOT_LONGNAME) 371 else if (status == PARSE_NOT_LONGNAME)
353 goto parse_record; 372 goto parse_record;
354 else if (status == PARSE_EOF) 373 else if (status == PARSE_EOF)
355 goto EODir; 374 goto end_of_dir;
356 } 375 }
357 376
358 memcpy(work, de->name, sizeof(de->name)); 377 memcpy(work, de->name, sizeof(de->name));
@@ -393,30 +412,21 @@ parse_record:
393 if (!last_u) 412 if (!last_u)
394 continue; 413 continue;
395 414
415 /* Compare shortname */
396 bufuname[last_u] = 0x0000; 416 bufuname[last_u] = 0x0000;
397 xlate_len = utf8 417 len = fat_uni_to_x8(sbi, bufuname, bufname, PATH_MAX);
398 ?utf8_wcstombs(bufname, bufuname, PATH_MAX) 418 if (fat_name_match(sbi, name, name_len, bufname, len))
399 :uni16_to_x8(bufname, bufuname, PATH_MAX, uni_xlate, nls_io); 419 goto found;
400 if (xlate_len == name_len)
401 if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
402 (anycase && !nls_strnicmp(nls_io, name, bufname,
403 xlate_len)))
404 goto Found;
405 420
406 if (nr_slots) { 421 if (nr_slots) {
407 xlate_len = utf8 422 /* Compare longname */
408 ?utf8_wcstombs(bufname, unicode, PATH_MAX) 423 len = fat_uni_to_x8(sbi, unicode, bufname, PATH_MAX);
409 :uni16_to_x8(bufname, unicode, PATH_MAX, uni_xlate, nls_io); 424 if (fat_name_match(sbi, name, name_len, bufname, len))
410 if (xlate_len != name_len) 425 goto found;
411 continue;
412 if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
413 (anycase && !nls_strnicmp(nls_io, name, bufname,
414 xlate_len)))
415 goto Found;
416 } 426 }
417 } 427 }
418 428
419Found: 429found:
420 nr_slots++; /* include the de */ 430 nr_slots++; /* include the de */
421 sinfo->slot_off = cpos - nr_slots * sizeof(*de); 431 sinfo->slot_off = cpos - nr_slots * sizeof(*de);
422 sinfo->nr_slots = nr_slots; 432 sinfo->nr_slots = nr_slots;
@@ -424,7 +434,7 @@ Found:
424 sinfo->bh = bh; 434 sinfo->bh = bh;
425 sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); 435 sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
426 err = 0; 436 err = 0;
427EODir: 437end_of_dir:
428 if (bufname) 438 if (bufname)
429 __putname(bufname); 439 __putname(bufname);
430 if (unicode) 440 if (unicode)
@@ -452,23 +462,19 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
452 struct msdos_sb_info *sbi = MSDOS_SB(sb); 462 struct msdos_sb_info *sbi = MSDOS_SB(sb);
453 struct buffer_head *bh; 463 struct buffer_head *bh;
454 struct msdos_dir_entry *de; 464 struct msdos_dir_entry *de;
455 struct nls_table *nls_io = sbi->nls_io;
456 struct nls_table *nls_disk = sbi->nls_disk; 465 struct nls_table *nls_disk = sbi->nls_disk;
457 unsigned char long_slots; 466 unsigned char nr_slots;
458 const char *fill_name;
459 int fill_len;
460 wchar_t bufuname[14]; 467 wchar_t bufuname[14];
461 wchar_t *unicode = NULL; 468 wchar_t *unicode = NULL;
462 unsigned char c, work[MSDOS_NAME], bufname[56], *ptname = bufname; 469 unsigned char c, work[MSDOS_NAME], bufname[56], *ptname = bufname;
463 unsigned long lpos, dummy, *furrfu = &lpos; 470 unsigned short opt_shortname = sbi->options.shortname;
464 int uni_xlate = sbi->options.unicode_xlate;
465 int isvfat = sbi->options.isvfat; 471 int isvfat = sbi->options.isvfat;
466 int utf8 = sbi->options.utf8;
467 int nocase = sbi->options.nocase; 472 int nocase = sbi->options.nocase;
468 unsigned short opt_shortname = sbi->options.shortname; 473 const char *fill_name;
469 unsigned long inum; 474 unsigned long inum;
470 int chi, chl, i, i2, j, last, last_u, dotoffset = 0; 475 unsigned long lpos, dummy, *furrfu = &lpos;
471 loff_t cpos; 476 loff_t cpos;
477 int chi, chl, i, i2, j, last, last_u, dotoffset = 0, fill_len;
472 int ret = 0; 478 int ret = 0;
473 479
474 lock_super(sb); 480 lock_super(sb);
@@ -488,43 +494,43 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
488 cpos = 0; 494 cpos = 0;
489 } 495 }
490 } 496 }
491 if (cpos & (sizeof(struct msdos_dir_entry)-1)) { 497 if (cpos & (sizeof(struct msdos_dir_entry) - 1)) {
492 ret = -ENOENT; 498 ret = -ENOENT;
493 goto out; 499 goto out;
494 } 500 }
495 501
496 bh = NULL; 502 bh = NULL;
497GetNew: 503get_new:
498 if (fat_get_entry(inode, &cpos, &bh, &de) == -1) 504 if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
499 goto EODir; 505 goto end_of_dir;
500parse_record: 506parse_record:
501 long_slots = 0; 507 nr_slots = 0;
502 /* Check for long filename entry */ 508 /* Check for long filename entry */
503 if (isvfat) { 509 if (isvfat) {
504 if (de->name[0] == DELETED_FLAG) 510 if (de->name[0] == DELETED_FLAG)
505 goto RecEnd; 511 goto record_end;
506 if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) 512 if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
507 goto RecEnd; 513 goto record_end;
508 if (de->attr != ATTR_EXT && IS_FREE(de->name)) 514 if (de->attr != ATTR_EXT && IS_FREE(de->name))
509 goto RecEnd; 515 goto record_end;
510 } else { 516 } else {
511 if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) 517 if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name))
512 goto RecEnd; 518 goto record_end;
513 } 519 }
514 520
515 if (isvfat && de->attr == ATTR_EXT) { 521 if (isvfat && de->attr == ATTR_EXT) {
516 int status = fat_parse_long(inode, &cpos, &bh, &de, 522 int status = fat_parse_long(inode, &cpos, &bh, &de,
517 &unicode, &long_slots); 523 &unicode, &nr_slots);
518 if (status < 0) { 524 if (status < 0) {
519 filp->f_pos = cpos; 525 filp->f_pos = cpos;
520 ret = status; 526 ret = status;
521 goto out; 527 goto out;
522 } else if (status == PARSE_INVALID) 528 } else if (status == PARSE_INVALID)
523 goto RecEnd; 529 goto record_end;
524 else if (status == PARSE_NOT_LONGNAME) 530 else if (status == PARSE_NOT_LONGNAME)
525 goto parse_record; 531 goto parse_record;
526 else if (status == PARSE_EOF) 532 else if (status == PARSE_EOF)
527 goto EODir; 533 goto end_of_dir;
528 } 534 }
529 535
530 if (sbi->options.dotsOK) { 536 if (sbi->options.dotsOK) {
@@ -586,12 +592,12 @@ parse_record:
586 } 592 }
587 } 593 }
588 if (!last) 594 if (!last)
589 goto RecEnd; 595 goto record_end;
590 596
591 i = last + dotoffset; 597 i = last + dotoffset;
592 j = last_u; 598 j = last_u;
593 599
594 lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry); 600 lpos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
595 if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) 601 if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))
596 inum = inode->i_ino; 602 inum = inode->i_ino;
597 else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { 603 else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
@@ -608,20 +614,17 @@ parse_record:
608 614
609 if (isvfat) { 615 if (isvfat) {
610 bufuname[j] = 0x0000; 616 bufuname[j] = 0x0000;
611 i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) 617 i = fat_uni_to_x8(sbi, bufuname, bufname, sizeof(bufname));
612 : uni16_to_x8(bufname, bufuname, sizeof(bufname), uni_xlate, nls_io);
613 } 618 }
614 619
615 fill_name = bufname; 620 fill_name = bufname;
616 fill_len = i; 621 fill_len = i;
617 if (!short_only && long_slots) { 622 if (!short_only && nr_slots) {
618 /* convert the unicode long name. 261 is maximum size 623 /* convert the unicode long name. 261 is maximum size
619 * of unicode buffer. (13 * slots + nul) */ 624 * of unicode buffer. (13 * slots + nul) */
620 void *longname = unicode + 261; 625 void *longname = unicode + 261;
621 int buf_size = PATH_MAX - (261 * sizeof(unicode[0])); 626 int buf_size = PATH_MAX - (261 * sizeof(unicode[0]));
622 int long_len = utf8 627 int long_len = fat_uni_to_x8(sbi, unicode, longname, buf_size);
623 ? utf8_wcstombs(longname, unicode, buf_size)
624 : uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io);
625 628
626 if (!both) { 629 if (!both) {
627 fill_name = longname; 630 fill_name = longname;
@@ -640,15 +643,15 @@ parse_record:
640 } 643 }
641 if (filldir(dirent, fill_name, fill_len, *furrfu, inum, 644 if (filldir(dirent, fill_name, fill_len, *furrfu, inum,
642 (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) 645 (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
643 goto FillFailed; 646 goto fill_failed;
644 647
645RecEnd: 648record_end:
646 furrfu = &lpos; 649 furrfu = &lpos;
647 filp->f_pos = cpos; 650 filp->f_pos = cpos;
648 goto GetNew; 651 goto get_new;
649EODir: 652end_of_dir:
650 filp->f_pos = cpos; 653 filp->f_pos = cpos;
651FillFailed: 654fill_failed:
652 brelse(bh); 655 brelse(bh);
653 if (unicode) 656 if (unicode)
654 __putname(unicode); 657 __putname(unicode);