"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/lfn.c" between
dosfstools-4.1.tar.gz and dosfstools-4.2.tar.gz

About: dosfstools are utilities to create, check and label (MS-DOS) FAT filesystems.

lfn.c  (dosfstools-4.1):lfn.c  (dosfstools-4.2)
skipping to change at line 77 skipping to change at line 77
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z', '+', '-' 'u', 'v', 'w', 'x', 'y', 'z', '+', '-'
}; };
/* This defines which unicode chars are directly convertable to ISO-8859-1 */ /* This defines which unicode chars are directly convertable to ISO-8859-1 */
#define UNICODE_CONVERTABLE(cl,ch) (ch == 0 && (cl < 0x80 || cl >= 0xa0)) #define UNICODE_CONVERTABLE(cl,ch) (ch == 0 && (cl < 0x80 || cl >= 0xa0))
/* for maxlen param */ /* for maxlen param */
#define UNTIL_0 INT_MAX #define UNTIL_0 INT_MAX
/* Convert name part in 'lfn' from unicode to ASCII */
#define CNV_THIS_PART(lfn) \
({ \
unsigned char __part_uni[CHARS_PER_LFN*2]; \
copy_lfn_part( __part_uni, lfn ); \
cnv_unicode( __part_uni, CHARS_PER_LFN, 0 ); \
})
/* Convert name parts collected so far (from previous slots) from unicode to /* Convert name parts collected so far (from previous slots) from unicode to
* ASCII */ * ASCII */
#define CNV_PARTS_SO_FAR() \ #define CNV_PARTS_SO_FAR() \
(cnv_unicode( lfn_unicode+(lfn_slot*CHARS_PER_LFN*2), \ (cnv_unicode( lfn_unicode+(lfn_slot*CHARS_PER_LFN*2), \
lfn_parts*CHARS_PER_LFN, 0 )) lfn_parts*CHARS_PER_LFN, 0 ))
#define BYTES_TO_WCHAR(cl,ch) ((wchar_t)((unsigned)(cl) + ((unsigned)(ch) << 8)) ) #define BYTES_TO_WCHAR(cl,ch) ((wchar_t)((unsigned)(cl) + ((unsigned)(ch) << 8)) )
static size_t mbslen(wchar_t x) static size_t mbslen(wchar_t x)
{ {
wchar_t wstr[] = { x, 0 }; wchar_t wstr[] = { x, 0 };
skipping to change at line 158 skipping to change at line 150
return (char *)out; return (char *)out;
} }
static void copy_lfn_part(unsigned char *dst, LFN_ENT * lfn) static void copy_lfn_part(unsigned char *dst, LFN_ENT * lfn)
{ {
memcpy(dst, lfn->name0_4, 10); memcpy(dst, lfn->name0_4, 10);
memcpy(dst + 10, lfn->name5_10, 12); memcpy(dst + 10, lfn->name5_10, 12);
memcpy(dst + 22, lfn->name11_12, 4); memcpy(dst + 22, lfn->name11_12, 4);
} }
/* Convert name part in 'lfn' from unicode to ASCII */
static inline char *cnv_this_part(LFN_ENT *lfn)
{
unsigned char part_uni[CHARS_PER_LFN * 2];
copy_lfn_part(part_uni, lfn);
return cnv_unicode(part_uni, CHARS_PER_LFN, 0);
}
static void clear_lfn_slots(int start, int end) static void clear_lfn_slots(int start, int end)
{ {
int i; int i;
LFN_ENT empty; LFN_ENT empty;
/* New dir entry is zeroed except first byte, which is set to 0xe5. /* New dir entry is zeroed except first byte, which is set to 0xe5.
* This is to avoid that some FAT-reading OSes (not Linux! ;) stop reading * This is to avoid that some FAT-reading OSes (not Linux! ;) stop reading
* a directory at the first zero entry... * a directory at the first zero entry...
*/ */
memset(&empty, 0, sizeof(empty)); memset(&empty, 0, sizeof(empty));
skipping to change at line 225 skipping to change at line 225
/* There is already a LFN "in progess", so it is an error that a /* There is already a LFN "in progess", so it is an error that a
* new start entry is here. */ * new start entry is here. */
/* Causes: 1) if slot# == expected: start bit set mysteriously, 2) /* Causes: 1) if slot# == expected: start bit set mysteriously, 2)
* old LFN overwritten by new one */ * old LFN overwritten by new one */
/* Fixes: 1) delete previous LFN 2) if slot# == expected and /* Fixes: 1) delete previous LFN 2) if slot# == expected and
* checksum ok: clear start bit */ * checksum ok: clear start bit */
/* XXX: Should delay that until next LFN known (then can better /* XXX: Should delay that until next LFN known (then can better
* display the name) */ * display the name) */
printf("A new long file name starts within an old one.\n"); printf("A new long file name starts within an old one.\n");
if (slot == lfn_slot && lfn->alias_checksum == lfn_checksum) { if (slot == lfn_slot && lfn->alias_checksum == lfn_checksum) {
char *part1 = CNV_THIS_PART(lfn); char *part1 = cnv_this_part(lfn);
char *part2 = CNV_PARTS_SO_FAR(); char *part2 = CNV_PARTS_SO_FAR();
printf(" It could be that the LFN start bit is wrong here\n" printf(" It could be that the LFN start bit is wrong here\n"
" if \"%s\" seems to match \"%s\".\n", part1, part2); " if \"%s\" seems to match \"%s\".\n", part1, part2);
free(part1); free(part1);
free(part2); free(part2);
can_clear = 1; can_clear = 1;
} }
if (interactive) { switch (get_choice(2, " Not auto-correcting this.",
printf("1: Delete previous LFN\n2: Leave it as it is.\n"); can_clear ? 3 : 2,
if (can_clear) 1, "Delete previous LFN",
printf("3: Clear start bit and concatenate LFNs\n"); 2, "Leave it as it is",
} else 3, "Clear start bit and concatenate LFNs")) {
printf(" Not auto-correcting this.\n"); case 1:
if (interactive) { clear_lfn_slots(0, lfn_parts - 1);
switch (get_key(can_clear ? "123" : "12", "?")) { lfn_reset();
case '1': break;
clear_lfn_slots(0, lfn_parts - 1); case 2:
lfn_reset(); break;
break; case 3:
case '2': lfn->id &= ~LFN_ID_START;
break; fs_write(dir_offset + offsetof(LFN_ENT, id),
case '3': sizeof(lfn->id), &lfn->id);
lfn->id &= ~LFN_ID_START; break;
fs_write(dir_offset + offsetof(LFN_ENT, id),
sizeof(lfn->id), &lfn->id);
break;
}
} }
} }
lfn_slot = slot; lfn_slot = slot;
lfn_checksum = lfn->alias_checksum; lfn_checksum = lfn->alias_checksum;
lfn_unicode = alloc((lfn_slot * CHARS_PER_LFN + 1) * 2); lfn_unicode = alloc((lfn_slot * CHARS_PER_LFN + 1) * 2);
lfn_offsets = alloc(lfn_slot * sizeof(off_t)); lfn_offsets = alloc(lfn_slot * sizeof(off_t));
lfn_parts = 0; lfn_parts = 0;
} else if (lfn_slot == -1 && slot != 0) { } else if (lfn_slot == -1 && slot != 0) {
/* No LFN in progress, but slot found; start bit missing */ /* No LFN in progress, but slot found; start bit missing */
/* Causes: 1) start bit got lost, 2) Previous slot with start bit got /* Causes: 1) start bit got lost, 2) Previous slot with start bit got
* lost */ * lost */
/* Fixes: 1) delete LFN, 2) set start bit */ /* Fixes: 1) delete LFN, 2) set start bit */
char *part = CNV_THIS_PART(lfn); char *part = cnv_this_part(lfn);
printf("Long filename fragment \"%s\" found outside a LFN " printf("Long filename fragment \"%s\" found outside a LFN "
"sequence.\n (Maybe the start bit is missing on the " "sequence.\n (Maybe the start bit is missing on the "
"last fragment)\n", part); "last fragment)\n", part);
free(part); free(part);
if (interactive) { switch (get_choice(2, " Not auto-correcting this.",
printf("1: Delete fragment\n2: Leave it as it is.\n" 3,
"3: Set start bit\n"); 1, "Delete fragment",
} else 2, "Leave it as it is",
printf(" Not auto-correcting this.\n"); 3, "Set start bit")) {
switch (interactive ? get_key("123", "?") : '2') { case 1:
case '1':
if (!lfn_offsets) if (!lfn_offsets)
lfn_offsets = alloc(sizeof(off_t)); lfn_offsets = alloc(sizeof(off_t));
lfn_offsets[0] = dir_offset; lfn_offsets[0] = dir_offset;
clear_lfn_slots(0, 0); clear_lfn_slots(0, 0);
lfn_reset(); lfn_reset();
return; return;
case '2': case 2:
lfn_reset(); lfn_reset();
return; return;
case '3': case 3:
lfn->id |= LFN_ID_START; lfn->id |= LFN_ID_START;
fs_write(dir_offset + offsetof(LFN_ENT, id), fs_write(dir_offset + offsetof(LFN_ENT, id),
sizeof(lfn->id), &lfn->id); sizeof(lfn->id), &lfn->id);
lfn_slot = slot; lfn_slot = slot;
lfn_checksum = lfn->alias_checksum; lfn_checksum = lfn->alias_checksum;
lfn_unicode = alloc((lfn_slot * CHARS_PER_LFN + 1) * 2); lfn_unicode = alloc((lfn_slot * CHARS_PER_LFN + 1) * 2);
lfn_offsets = alloc(lfn_slot * sizeof(off_t)); lfn_offsets = alloc(lfn_slot * sizeof(off_t));
lfn_parts = 0; lfn_parts = 0;
break; break;
} }
} else if (slot != lfn_slot) { } else if (slot != lfn_slot) {
/* wrong sequence number */ /* wrong sequence number */
/* Causes: 1) seq-no destroyed */ /* Causes: 1) seq-no destroyed */
/* Fixes: 1) delete LFN, 2) fix number (maybe only if following parts /* Fixes: 1) delete LFN, 2) fix number (maybe only if following parts
* are ok?, maybe only if checksum is ok?) (Attention: space * are ok?, maybe only if checksum is ok?) (Attention: space
* for name was allocated before!) */ * for name was allocated before!) */
int can_fix = 0; int can_fix = 0;
printf("Unexpected long filename sequence number " printf("Unexpected long filename sequence number "
"(%d vs. expected %d).\n", slot, lfn_slot); "(%d vs. expected %d).\n", slot, lfn_slot);
if (lfn->alias_checksum == lfn_checksum && lfn_slot > 0) { if (lfn->alias_checksum == lfn_checksum && lfn_slot > 0) {
char *part1 = CNV_THIS_PART(lfn); char *part1 = cnv_this_part(lfn);
char *part2 = CNV_PARTS_SO_FAR(); char *part2 = CNV_PARTS_SO_FAR();
printf(" It could be that just the number is wrong\n" printf(" It could be that just the number is wrong\n"
" if \"%s\" seems to match \"%s\".\n", part1, part2); " if \"%s\" seems to match \"%s\".\n", part1, part2);
free(part1); free(part1);
free(part2); free(part2);
can_fix = 1; can_fix = 1;
} }
if (interactive) { switch (get_choice(2, " Not auto-correcting this.",
printf can_fix ? 3 : 2,
("1: Delete LFN\n2: Leave it as it is (and ignore LFN so far)\n") 1, "Delete LFN",
; 2, "Leave it as it is (and ignore LFN so far)",
if (can_fix) 3, "Correct sequence number")) {
printf("3: Correct sequence number\n"); case 1:
} else
printf(" Not auto-correcting this.\n");
switch (interactive ? get_key(can_fix ? "123" : "12", "?") : '2') {
case '1':
if (!lfn_offsets) { if (!lfn_offsets) {
lfn_offsets = alloc(sizeof(off_t)); lfn_offsets = alloc(sizeof(off_t));
lfn_parts = 0; lfn_parts = 0;
} }
lfn_offsets[lfn_parts++] = dir_offset; lfn_offsets[lfn_parts++] = dir_offset;
clear_lfn_slots(0, lfn_parts - 1); clear_lfn_slots(0, lfn_parts - 1);
lfn_reset(); lfn_reset();
return; return;
case '2': case 2:
lfn_reset(); lfn_reset();
return; return;
case '3': case 3:
lfn->id = (lfn->id & ~LFN_ID_SLOTMASK) | lfn_slot; lfn->id = (lfn->id & ~LFN_ID_SLOTMASK) | lfn_slot;
fs_write(dir_offset + offsetof(LFN_ENT, id), fs_write(dir_offset + offsetof(LFN_ENT, id),
sizeof(lfn->id), &lfn->id); sizeof(lfn->id), &lfn->id);
break; break;
} }
} }
if (lfn->alias_checksum != lfn_checksum) { if (lfn->alias_checksum != lfn_checksum) {
/* checksum mismatch */ /* checksum mismatch */
/* Causes: 1) checksum field here destroyed */ /* Causes: 1) checksum field here destroyed */
/* Fixes: 1) delete LFN, 2) fix checksum */ /* Fixes: 1) delete LFN, 2) fix checksum */
printf("Checksum in long filename part wrong " printf("Checksum in long filename part wrong "
"(%02x vs. expected %02x).\n", "(%02x vs. expected %02x).\n",
lfn->alias_checksum, lfn_checksum); lfn->alias_checksum, lfn_checksum);
if (interactive) { switch (get_choice(2, " Not auto-correcting this.",
printf("1: Delete LFN\n2: Leave it as it is.\n" 3,
"3: Correct checksum\n"); 1, "Delete LFN",
} else 2, "Leave it as it is",
printf(" Not auto-correcting this.\n"); 3, "Correct checksum")) {
if (interactive) { case 1:
switch (get_key("123", "?")) { lfn_offsets[lfn_parts++] = dir_offset;
case '1': clear_lfn_slots(0, lfn_parts - 1);
lfn_offsets[lfn_parts++] = dir_offset; lfn_reset();
clear_lfn_slots(0, lfn_parts - 1); return;
lfn_reset(); case 2:
return; break;
case '2': case 3:
break; lfn->alias_checksum = lfn_checksum;
case '3': fs_write(dir_offset + offsetof(LFN_ENT, alias_checksum),
lfn->alias_checksum = lfn_checksum; sizeof(lfn->alias_checksum), &lfn->alias_checksum);
fs_write(dir_offset + offsetof(LFN_ENT, alias_checksum), break;
sizeof(lfn->alias_checksum), &lfn->alias_checksum);
break;
}
} }
} }
if (lfn_slot != -1) { if (lfn_slot != -1) {
lfn_slot--; lfn_slot--;
offset = lfn_slot * CHARS_PER_LFN * 2; offset = lfn_slot * CHARS_PER_LFN * 2;
copy_lfn_part(lfn_unicode + offset, lfn); copy_lfn_part(lfn_unicode + offset, lfn);
if (lfn->id & LFN_ID_START) if (lfn->id & LFN_ID_START)
lfn_unicode[offset + 26] = lfn_unicode[offset + 27] = 0; lfn_unicode[offset + 26] = lfn_unicode[offset + 27] = 0;
lfn_offsets[lfn_parts++] = dir_offset; lfn_offsets[lfn_parts++] = dir_offset;
} }
if (lfn->reserved != 0) { if (lfn->reserved != 0) {
printf("Reserved field in VFAT long filename slot is not 0 " printf("Reserved field in VFAT long filename slot is not 0 "
"(but 0x%02x).\n", lfn->reserved); "(but 0x%02x).\n", lfn->reserved);
if (interactive) if (get_choice(1, "Auto-setting to 0.",
printf("1: Fix.\n2: Leave it.\n"); 2,
else 1, "Fix",
printf("Auto-setting to 0.\n"); 2, "Leave it") == 1) {
if (!interactive || get_key("12", "?") == '1') {
lfn->reserved = 0; lfn->reserved = 0;
fs_write(dir_offset + offsetof(LFN_ENT, reserved), fs_write(dir_offset + offsetof(LFN_ENT, reserved),
sizeof(lfn->reserved), &lfn->reserved); sizeof(lfn->reserved), &lfn->reserved);
} }
} }
if (lfn->start != htole16(0)) { if (lfn->start != htole16(0)) {
printf("Start cluster field in VFAT long filename slot is not 0 " printf("Start cluster field in VFAT long filename slot is not 0 "
"(but 0x%04x).\n", lfn->start); "(but 0x%04x).\n", lfn->start);
if (interactive) if (get_choice(1, "Auto-setting to 0.",
printf("1: Fix.\n2: Leave it.\n"); 2,
else 1, "Fix",
printf("Auto-setting to 0.\n"); 2, "Leave it") == 1) {
if (!interactive || get_key("12", "?") == '1') {
lfn->start = htole16(0); lfn->start = htole16(0);
fs_write(dir_offset + offsetof(LFN_ENT, start), fs_write(dir_offset + offsetof(LFN_ENT, start),
sizeof(lfn->start), &lfn->start); sizeof(lfn->start), &lfn->start);
} }
} }
} }
/* This function is always called when de->attr != VFAT_LN_ATTR is found, to /* This function is always called when de->attr != VFAT_LN_ATTR is found, to
* retrieve the previously constructed LFN. */ * retrieve the previously constructed LFN. */
char *lfn_get(DIR_ENT * de, off_t * lfn_offset) char *lfn_get(DIR_ENT * de, off_t * lfn_offset)
skipping to change at line 439 skipping to change at line 426
return NULL; return NULL;
if (lfn_slot != 0) { if (lfn_slot != 0) {
/* The long name isn't finished yet. */ /* The long name isn't finished yet. */
/* Causes: 1) LFN slot overwritten by non-VFAT aware tool */ /* Causes: 1) LFN slot overwritten by non-VFAT aware tool */
/* Fixes: 1) delete LFN 2) move overwriting entry to somewhere else /* Fixes: 1) delete LFN 2) move overwriting entry to somewhere else
* and let user enter missing part of LFN (hard to do :-() * and let user enter missing part of LFN (hard to do :-()
* 3) renumber entries and truncate name */ * 3) renumber entries and truncate name */
char *long_name = CNV_PARTS_SO_FAR(); char *long_name = CNV_PARTS_SO_FAR();
char *short_name = file_name(de->name); char *short_name = file_name(de->name);
char *fix_num_string;
int choice;
printf("Unfinished long file name \"%s\".\n" printf("Unfinished long file name \"%s\".\n"
" (Start may have been overwritten by %s)\n", " (Start may have been overwritten by %s)\n",
long_name, short_name); long_name, short_name);
free(long_name); free(long_name);
if (interactive) {
printf("1: Delete LFN\n2: Leave it as it is.\n" xasprintf(&fix_num_string,
"3: Fix numbering (truncates long name and attaches " "Fix numbering (truncates long name and attaches "
"it to short name %s)\n", short_name); "it to short name %s)", short_name);
} else choice = get_choice(2, " Not auto-correcting this.",
printf(" Not auto-correcting this.\n"); 3,
switch (interactive ? get_key("123", "?") : '2') { 1, "Delete LFN",
case '1': 2, "Leave it as it is",
3, fix_num_string);
free(fix_num_string);
switch (choice) {
case 1:
clear_lfn_slots(0, lfn_parts - 1); clear_lfn_slots(0, lfn_parts - 1);
lfn_reset(); lfn_reset();
return NULL; return NULL;
case '2': case 2:
lfn_reset(); lfn_reset();
return NULL; return NULL;
case '3': case 3:
for (i = 0; i < lfn_parts; ++i) { for (i = 0; i < lfn_parts; ++i) {
uint8_t id = (lfn_parts - i) | (i == 0 ? LFN_ID_START : 0); uint8_t id = (lfn_parts - i) | (i == 0 ? LFN_ID_START : 0);
fs_write(lfn_offsets[i] + offsetof(LFN_ENT, id), fs_write(lfn_offsets[i] + offsetof(LFN_ENT, id),
sizeof(id), &id); sizeof(id), &id);
} }
memmove(lfn_unicode, lfn_unicode + lfn_slot * CHARS_PER_LFN * 2, memmove(lfn_unicode, lfn_unicode + lfn_slot * CHARS_PER_LFN * 2,
lfn_parts * CHARS_PER_LFN * 2); lfn_parts * CHARS_PER_LFN * 2);
break; break;
} }
} }
for (sum = 0, i = 0; i < MSDOS_NAME; i++) for (sum = 0, i = 0; i < MSDOS_NAME; i++)
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + de->name[i]; sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + de->name[i];
if (sum != lfn_checksum) { if (sum != lfn_checksum) {
/* checksum doesn't match, long name doesn't apply to this alias */ /* checksum doesn't match, long name doesn't apply to this alias */
/* Causes: 1) alias renamed */ /* Causes: 1) alias renamed */
/* Fixes: 1) Fix checksum in LFN entries */ /* Fixes: 1) Fix checksum in LFN entries */
char *long_name = CNV_PARTS_SO_FAR(); char *long_name = CNV_PARTS_SO_FAR();
char *short_name = file_name(de->name); char *short_name = file_name(de->name);
char *fix_check_string;
int choice;
printf("Wrong checksum for long file name \"%s\".\n" printf("Wrong checksum for long file name \"%s\".\n"
" (Short name %s may have changed without updating the long name) \n", " (Short name %s may have changed without updating the long name) \n",
long_name, short_name); long_name, short_name);
free(long_name); free(long_name);
if (interactive) {
printf("1: Delete LFN\n2: Leave it as it is.\n" xasprintf(&fix_check_string,
"3: Fix checksum (attaches to short name %s)\n", short_name); "Fix checksum (attaches to short name %s)", short_name);
} else choice = get_choice(9, " Not auto-correcting this.",
printf(" Not auto-correcting this.\n"); 3,
if (interactive) { 1, "Delete LFN",
switch (get_key("123", "?")) { 2, "Leave it as it is",
case '1': 3, fix_check_string);
clear_lfn_slots(0, lfn_parts - 1); free(fix_check_string);
lfn_reset();
return NULL; switch (choice) {
case '2': case 1:
lfn_reset(); clear_lfn_slots(0, lfn_parts - 1);
return NULL; lfn_reset();
case '3': return NULL;
for (i = 0; i < lfn_parts; ++i) { case 2:
fs_write(lfn_offsets[i] + offsetof(LFN_ENT, alias_checksum), lfn_reset();
sizeof(sum), &sum); return NULL;
} case 3:
break; for (i = 0; i < lfn_parts; ++i) {
fs_write(lfn_offsets[i] + offsetof(LFN_ENT, alias_checksum),
sizeof(sum), &sum);
} }
break;
} }
} }
*lfn_offset = lfn_offsets[0]; *lfn_offset = lfn_offsets[0];
lfn = cnv_unicode(lfn_unicode, UNTIL_0, 1); lfn = cnv_unicode(lfn_unicode, UNTIL_0, 1);
lfn_reset(); lfn_reset();
return (lfn); return (lfn);
} }
void lfn_check_orphaned(void) void lfn_check_orphaned(void)
{ {
char *long_name; char *long_name;
if (lfn_slot == -1) if (lfn_slot == -1)
return; return;
long_name = CNV_PARTS_SO_FAR(); long_name = CNV_PARTS_SO_FAR();
printf("Orphaned long file name part \"%s\"\n", long_name); printf("Orphaned long file name part \"%s\"\n", long_name);
free(long_name); free(long_name);
if (interactive) if (get_choice(1, " Auto-deleting.",
printf("1: Delete.\n2: Leave it.\n"); 2,
else 1, "Delete",
printf(" Auto-deleting.\n"); 2, "Leave it") == 1) {
if (!interactive || get_key("12", "?") == '1') {
clear_lfn_slots(0, lfn_parts - 1); clear_lfn_slots(0, lfn_parts - 1);
} }
lfn_reset(); lfn_reset();
} }
 End of changes. 23 change blocks. 
117 lines changed or deleted 116 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)