From: "Hervé Poussineau" <hpoussin@reactos.org>
To: qemu-devel@nongnu.org
Cc: "Kevin Wolf" <kwolf@redhat.com>, "Max Reitz" <mreitz@redhat.com>,
qemu-block@nongnu.org, "Hervé Poussineau" <hpoussin@reactos.org>
Subject: [Qemu-devel] [PATCH v2 09/13] vvfat: correctly create base short names for non-ASCII filenames
Date: Mon, 22 May 2017 23:12:01 +0200 [thread overview]
Message-ID: <20170522211205.14265-10-hpoussin@reactos.org> (raw)
In-Reply-To: <20170522211205.14265-1-hpoussin@reactos.org>
More specifically, create short name from filename and change blacklist of
invalid chars to whitelist of valid chars.
Windows 9x also now correctly see long file names of filenames containing a space,
but Scandisk still complains about mismatch between SFN and LFN.
Specification: "FAT: General overview of on-disk format" v1.03, pages 30-31
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
---
block/vvfat.c | 105 ++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 77 insertions(+), 28 deletions(-)
diff --git a/block/vvfat.c b/block/vvfat.c
index d34241da17..3cb65493cd 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -516,6 +516,81 @@ static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
}
+static uint8_t to_valid_short_char(gunichar c)
+{
+ c = g_unichar_toupper(c);
+ if ((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') ||
+ strchr("$%'-_@~`!(){}^#&", c) != 0) {
+ return c;
+ } else {
+ return 0;
+ }
+}
+
+static direntry_t *create_short_filename(BDRVVVFATState *s,
+ const char *filename)
+{
+ int i, j = 0;
+ direntry_t *entry = array_get_next(&(s->directory));
+ const gchar *p, *last_dot = NULL;
+ gunichar c;
+ bool lossy_conversion = false;
+ char tail[11];
+
+ if (!entry) {
+ return NULL;
+ }
+ memset(entry->name, 0x20, sizeof(entry->name));
+
+ /* copy filename and search last dot */
+ for (p = filename; ; p = g_utf8_next_char(p)) {
+ c = g_utf8_get_char(p);
+ if (c == '\0') {
+ break;
+ } else if (c == '.') {
+ if (j == 0) {
+ /* '.' at start of filename */
+ lossy_conversion = true;
+ } else {
+ if (last_dot) {
+ lossy_conversion = true;
+ }
+ last_dot = p;
+ }
+ } else if (!last_dot) {
+ /* first part of the name; copy it */
+ uint8_t v = to_valid_short_char(c);
+ if (j < 8 && v) {
+ entry->name[j++] = v;
+ } else {
+ lossy_conversion = true;
+ }
+ }
+ }
+
+ /* copy extension (if any) */
+ if (last_dot) {
+ j = 0;
+ for (p = g_utf8_next_char(last_dot); ; p = g_utf8_next_char(p)) {
+ c = g_utf8_get_char(p);
+ if (c == '\0') {
+ break;
+ } else {
+ /* extension; copy it */
+ uint8_t v = to_valid_short_char(c);
+ if (j < 3 && v) {
+ entry->name[8 + (j++)] = v;
+ } else {
+ lossy_conversion = true;
+ }
+ }
+ }
+ }
+ (void)lossy_conversion;
+ return entry;
+}
+
/* fat functions */
static inline uint8_t fat_chksum(const direntry_t* entry)
@@ -614,7 +689,7 @@ static inline void init_fat(BDRVVVFATState* s)
static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
unsigned int directory_start, const char* filename, int is_dot)
{
- int i,j,long_index=s->directory.next;
+ int long_index = s->directory.next;
direntry_t* entry = NULL;
direntry_t* entry_long = NULL;
@@ -626,33 +701,7 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
}
entry_long=create_long_filename(s,filename);
-
- i = strlen(filename);
- for(j = i - 1; j>0 && filename[j]!='.';j--);
- if (j > 0)
- i = (j > 8 ? 8 : j);
- else if (i > 8)
- i = 8;
-
- entry=array_get_next(&(s->directory));
- memset(entry->name, 0x20, sizeof(entry->name));
- memcpy(entry->name, filename, i);
-
- if (j > 0) {
- for (i = 0; i < 3 && filename[j + 1 + i]; i++) {
- entry->name[8 + i] = filename[j + 1 + i];
- }
- }
-
- /* upcase & remove unwanted characters */
- for(i=10;i>=0;i--) {
- if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
- if(entry->name[i]<=' ' || entry->name[i]>0x7f
- || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
- entry->name[i]='_';
- else if(entry->name[i]>='a' && entry->name[i]<='z')
- entry->name[i]+='A'-'a';
- }
+ entry = create_short_filename(s, filename);
/* mangle duplicates */
while(1) {
--
2.11.0
next prev parent reply other threads:[~2017-05-22 21:12 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-05-22 21:11 [Qemu-devel] [PATCH v2 00/13] vvfat: misc fixes for read-only mode Hervé Poussineau
2017-05-22 21:11 ` [Qemu-devel] [PATCH v2 01/13] vvfat: fix qemu-img map and qemu-img convert Hervé Poussineau
2017-05-22 21:17 ` [Qemu-devel] [Qemu-block] " Eric Blake
2017-05-22 21:11 ` [Qemu-devel] [PATCH v2 02/13] vvfat: replace tabs by 8 spaces Hervé Poussineau
2017-05-22 21:11 ` [Qemu-devel] [PATCH v2 03/13] vvfat: fix typos Hervé Poussineau
2017-05-22 21:11 ` [Qemu-devel] [PATCH v2 04/13] vvfat: rename useless enumeration values Hervé Poussineau
2017-05-22 21:11 ` [Qemu-devel] [PATCH v2 05/13] vvfat: introduce offset_to_bootsector, offset_to_fat and offset_to_root_dir Hervé Poussineau
2017-05-24 4:10 ` Philippe Mathieu-Daudé
2017-05-24 13:34 ` Eric Blake
2017-05-22 21:11 ` [Qemu-devel] [PATCH v2 06/13] vvfat: fix field names in FAT12/FAT16 and FAT32 boot sectors Hervé Poussineau
2017-05-22 21:11 ` [Qemu-devel] [PATCH v2 07/13] vvfat: always create . and .. entries at first and in that order Hervé Poussineau
2017-05-22 21:12 ` [Qemu-devel] [PATCH v2 08/13] vvfat: correctly create long names for non-ASCII filenames Hervé Poussineau
2017-05-22 21:12 ` Hervé Poussineau [this message]
2017-05-24 4:17 ` [Qemu-devel] [PATCH v2 09/13] vvfat: correctly create base short " Philippe Mathieu-Daudé
2017-05-24 5:43 ` Hervé Poussineau
2017-05-22 21:12 ` [Qemu-devel] [PATCH v2 10/13] vvfat: correctly generate numeric-tail of short file names Hervé Poussineau
2017-08-05 18:52 ` Pranith Kumar
2017-08-07 11:07 ` Eric Blake
2017-08-08 23:31 ` Pranith Kumar
2017-05-22 21:12 ` [Qemu-devel] [PATCH v2 11/13] vvfat: limit number of entries in root directory in FAT12/FAT16 Hervé Poussineau
2017-05-22 21:12 ` [Qemu-devel] [PATCH v2 12/13] vvfat: handle KANJI lead byte 0xe5 Hervé Poussineau
2017-05-24 4:20 ` Philippe Mathieu-Daudé
2017-05-22 21:12 ` [Qemu-devel] [PATCH v2 13/13] vvfat: change OEM name to 'MSWIN4.1' Hervé Poussineau
2017-05-23 4:23 ` Philippe Mathieu-Daudé
2017-05-23 19:41 ` Hervé Poussineau
2017-05-24 4:27 ` Philippe Mathieu-Daudé
2017-05-22 22:38 ` [Qemu-devel] [PATCH v2 00/13] vvfat: misc fixes for read-only mode no-reply
2017-07-03 16:50 ` Kevin Wolf
2017-07-06 5:27 ` Hervé Poussineau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170522211205.14265-10-hpoussin@reactos.org \
--to=hpoussin@reactos.org \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).