New Upstream Release - fatsort

Ready changes

Summary

Merged new upstream version: 1.6.5.640 (was: 1.6.4.625).

Resulting package

Built on 2023-06-08T00:05 (took 4m34s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases fatsort

Lintian Result

Diff

diff --git a/CHANGES.md b/CHANGES.md
index b7db2e7..1e105d1 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## v1.6.5 (March, 12th, 2023)
+* refactored character conversion and fixed bugs related to multi-byte characters
+* added checks for overly long filenames
+* added test cases for long file names
+
 ## v1.6.4 (September 20th, 2021)
 * fixed randomization for fatXX. Thanks go to Zoltán Döme for reporting the bug!
 * added test cases for randomization option
diff --git a/debian/changelog b/debian/changelog
index b564c9d..1862f7a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-fatsort (1.6.4.625-1) UNRELEASED; urgency=medium
+fatsort (1.6.5.640-1) UNRELEASED; urgency=medium
 
   [ Debian Janitor ]
   * Use secure URI in Homepage field.
@@ -6,7 +6,10 @@ fatsort (1.6.4.625-1) UNRELEASED; urgency=medium
   [ Alex Muntada ]
   * Take over maintenance (Closes: #1032432).
 
- -- Alex Muntada <alexm@debian.org>  Mon, 13 Mar 2023 08:57:37 +0100
+  [ Debian Janitor ]
+  * New upstream release.
+
+ -- Alex Muntada <alexm@debian.org>  Thu, 08 Jun 2023 00:01:55 -0000
 
 fatsort (1.6.4.625-0.1) unstable; urgency=medium
 
diff --git a/debian/patches/use-cppflags.patch b/debian/patches/use-cppflags.patch
index a901df5..904669d 100644
--- a/debian/patches/use-cppflags.patch
+++ b/debian/patches/use-cppflags.patch
@@ -2,9 +2,11 @@ Description: Use CPPFLAGS to enable FORTIFY_SOURCE
 Author: Alex Muntada <alexm@debian.org>
 Forwarded: no
 
---- a/src/Makefile
-+++ b/src/Makefile
-@@ -69,6 +69,9 @@
+Index: fatsort.git/src/Makefile
+===================================================================
+--- fatsort.git.orig/src/Makefile
++++ fatsort.git/src/Makefile
+@@ -69,6 +69,9 @@ endif
  
  OBJ=fatsort.o FAT_fs.o deviceio.o endianness.o sig.o entrylist.o errors.o options.o clusterchain.o sort.o misc.o natstrcmp.o stringlist.o regexlist.o
  
diff --git a/docker_tests/docker_tests_amd64/Makefile b/docker_tests/docker_tests_amd64/Makefile
index 943d2df..ed0ba47 100644
--- a/docker_tests/docker_tests_amd64/Makefile
+++ b/docker_tests/docker_tests_amd64/Makefile
@@ -4,7 +4,7 @@ WGET=$(shell which wget)
 TAR=$(shell which tar)
 
 all: build_image
-	$(DOCKER) run --rm --privileged -v ${CURDIR}:/home/tester/artifacts --tmpfs /tmp:rw,noexec,nosuid,size=2G -it fatsort-test-amd64
+	$(DOCKER) run --rm --privileged --group-add keep-groups -v ${CURDIR}:/home/tester/artifacts --tmpfs /tmp:rw,noexec,nosuid,size=2G -it fatsort-test-amd64
 
 build_image: Dockerfile do_tests.sh
 	$(DOCKER) build -t fatsort-test-amd64  .
diff --git a/docker_tests/docker_tests_i386/Makefile b/docker_tests/docker_tests_i386/Makefile
index 8ed8b71..483615b 100644
--- a/docker_tests/docker_tests_i386/Makefile
+++ b/docker_tests/docker_tests_i386/Makefile
@@ -4,7 +4,7 @@ WGET=$(shell which wget)
 TAR=$(shell which tar)
 
 all: build_image
-	$(DOCKER) run --rm --privileged -v ${CURDIR}:/home/tester/artifacts --tmpfs /tmp:rw,noexec,nosuid,size=2G -it fatsort-test-i386
+	$(DOCKER) run --rm --privileged --group-add keep-groups -v ${CURDIR}:/home/tester/artifacts --tmpfs /tmp:rw,noexec,nosuid,size=2G -it fatsort-test-i386
 
 build_image: Dockerfile do_tests.sh
 	$(DOCKER) build -t fatsort-test-i386  .
diff --git a/docker_tests/docker_tests_ppc/Makefile b/docker_tests/docker_tests_ppc/Makefile
index cf4c16e..0b2d3f6 100644
--- a/docker_tests/docker_tests_ppc/Makefile
+++ b/docker_tests/docker_tests_ppc/Makefile
@@ -4,7 +4,7 @@ WGET=$(shell which wget)
 TAR=$(shell which tar)
 
 all: build_image
-	$(DOCKER) run --rm --privileged -v ${CURDIR}:/home/tester/artifacts --tmpfs /tmp:rw,noexec,nosuid,size=2G -v ${CURDIR}/qemu-ppc-static:/usr/bin/qemu-ppc-static -it fatsort-test-ppc
+	$(DOCKER) run --rm --privileged --group-add keep-groups -v ${CURDIR}:/home/tester/artifacts --tmpfs /tmp:rw,noexec,nosuid,size=2G -v ${CURDIR}/qemu-ppc-static:/usr/bin/qemu-ppc-static -it fatsort-test-ppc
 
 build_image: Dockerfile qemu-ppc-static
 	$(DOCKER) build -t fatsort-test-ppc -v ${CURDIR}/qemu-ppc-static:/usr/bin/qemu-ppc-static  .
@@ -15,7 +15,7 @@ qemu-ppc-static:
 	$(TAR) xvfz qemu-ppc-static.tar.gz
 
 /proc/sys/fs/binfmt_misc/ppc:
-	$(DOCKER) run --rm --privileged multiarch/qemu-user-static:register
+	$(DOCKER) run --rm --privileged --group-add keep-groups multiarch/qemu-user-static:register
 
 clean:
 	rm -f *.log
diff --git a/docker_tests/docker_tests_s390x/Makefile b/docker_tests/docker_tests_s390x/Makefile
index 109bb60..6cfe96a 100644
--- a/docker_tests/docker_tests_s390x/Makefile
+++ b/docker_tests/docker_tests_s390x/Makefile
@@ -4,7 +4,7 @@ WGET=$(shell which wget)
 TAR=$(shell which tar)
 
 all: build_image
-	$(DOCKER) run --rm --privileged -v ${CURDIR}:/home/tester/artifacts --tmpfs /tmp:rw,noexec,nosuid,size=2G -v ${CURDIR}/qemu-s390x-static:/usr/bin/qemu-s390x-static -it fatsort-test-s390x
+	$(DOCKER) run --rm --privileged --group-add keep-groups -v ${CURDIR}:/home/tester/artifacts --tmpfs /tmp:rw,noexec,nosuid,size=2G -v ${CURDIR}/qemu-s390x-static:/usr/bin/qemu-s390x-static -it fatsort-test-s390x
 
 build_image: Dockerfile qemu-s390x-static do_tests.sh
 	$(DOCKER) build -t fatsort-test-s390x -v ${CURDIR}/qemu-s390x-static:/usr/bin/qemu-s390x-static  .
@@ -15,7 +15,7 @@ qemu-s390x-static:
 	$(TAR) xvfz qemu-s390x-static.tar.gz
 
 /proc/sys/fs/binfmt_misc/s390x:
-	$(DOCKER) run --rm --privileged multiarch/qemu-user-static:register
+	$(DOCKER) run --rm --privileged --group-add keep-groups multiarch/qemu-user-static:register
 
 clean:
 	rm -f *.log
diff --git a/man/fatsort.1 b/man/fatsort.1
index 9c03f5b..1a84743 100644
--- a/man/fatsort.1
+++ b/man/fatsort.1
@@ -1,5 +1,5 @@
-.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.48.3.
-.TH FATSORT "1" "September 2021" "fatsort 1.6.4" "User Commands"
+.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.49.3.
+.TH FATSORT "1" "M�rz 2023" "fatsort 1.6.5" "User Commands"
 .SH NAME
 fatsort \- FAT sorting tool
 .SH SYNOPSIS
@@ -111,7 +111,7 @@ Written by Boris Leidner.
 .SH "REPORTING BUGS"
 Report bugs to <fatsort@formenos.de>.
 .SH COPYRIGHT
-Copyright \(co 2004\-2021 Boris Leidner.
+Copyright \(co 2004\-2023 Boris Leidner.
 License GPLv2: GNU GPL version 2 (see LICENSE.txt)
 .br
 This is free software: you are free to change and redistribute it.
diff --git a/src/FAT_fs.h b/src/FAT_fs.h
index d7e35f3..6516558 100644
--- a/src/FAT_fs.h
+++ b/src/FAT_fs.h
@@ -61,8 +61,8 @@
 // maximum path len on FAT file systems (above specification)
 #define MAX_PATH_LEN 512
 
-// maximum filename length on exFAT
-#define MAX_EXFAT_FILENAME_LEN 255
+// maximum filename length
+#define MAX_FILENAME_LEN (uint32_t) 255
 
 // maximum file len
 // (specification: file < 4GB which is
diff --git a/src/Makefile b/src/Makefile
index 4057a67..a70d812 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -9,7 +9,7 @@ LDFLAGS += -s
 endif
 
 CFLAGS += -Wall -Wextra
-override CFLAGS+= -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
+override CFLAGS+= -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE ${CPPFLAGS}
 
 INSTALL_FLAGS=-m 0755 -p -D
 
diff --git a/src/fatsort.c b/src/fatsort.c
index abf30e6..606808a 100644
--- a/src/fatsort.c
+++ b/src/fatsort.c
@@ -45,9 +45,9 @@
 
 // program information
 #define INFO_PROGRAM		"fatsort"
-#define INFO_VERSION		"1.6.4"
+#define INFO_VERSION		"1.6.5"
 #define INFO_AUTHOR		"Written by Boris Leidner.\n"
-#define INFO_COPYRIGHT		"Copyright (C) 2004-2021 Boris Leidner.\n"
+#define INFO_COPYRIGHT		"Copyright (C) 2004-2023 Boris Leidner.\n"
 #define INFO_LICENSE		"License GPLv2: GNU GPL version 2 (see LICENSE.txt)\n" \
 				"This is free software: you are free to change and redistribute it.\n" \
 				"There is NO WARRANTY, to the extent permitted by law.\n"
diff --git a/src/regexlist.c b/src/regexlist.c
index 874990e..7d86ea1 100644
--- a/src/regexlist.c
+++ b/src/regexlist.c
@@ -98,7 +98,7 @@ int32_t matchesRegExList(struct sRegExList *regExList, const char *str) {
 	assert(regExList->regex == NULL);
 	assert(str != NULL);
 
-	regmatch_t pmatch[0];
+	regmatch_t pmatch[1];
 
 	regExList=regExList->next;
 	while (regExList != NULL) {
diff --git a/src/sort.c b/src/sort.c
index e94b9d3..f3d3286 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -60,7 +60,7 @@ char *getCharSet(void) {
 	return NULL;
 }
 
-int32_t parseLongFilenamePart(struct sLongDirEntry *lde, char *str, iconv_t cd) {
+int32_t parseLongFilenamePart(struct sLongDirEntry *lde, char *utf16lestr) {
 /*
 	retrieves a part of a long filename from a
 	directory entry
@@ -68,64 +68,12 @@ int32_t parseLongFilenamePart(struct sLongDirEntry *lde, char *str, iconv_t cd)
 */
 
 	assert(lde != NULL);
-	assert(str != NULL);
-
-	size_t incount;
-	size_t outcount;
-	char utf16str[28];
-
-	str[0]='\0';
-
-	memcpy(utf16str, (&lde->LDIR_Ord+1), 10);
-	memcpy(utf16str+10, (&lde->LDIR_Ord+14), 12);
-	memcpy(utf16str+22, (&lde->LDIR_Ord+28), 4);
-	memset(utf16str+26, 0, 2);
-
-	incount=26;
-	outcount=MAX_PATH_LEN;
-
-	int i;
-	for (i=0;i<12; i++) {
-		if ((utf16str[i*2] == '\0') && (utf16str[i*2+1] == '\0')) {
-			incount=i*2;
-			break;
-		}
-	}
+	assert(utf16lestr != NULL);
 
-
-	//printf("Incount: %u\n", incount);
-
-#ifdef __WIN32__
-
-	if (WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)utf16str, (int) incount, str, (int) outcount, NULL, NULL) == 0) {
-		stderror();
-		return -1;
-	}
-
-#else // Linux et al
-
-	char *outptr = &(str[0]);
-	char *inptr = &(utf16str[0]);
-	size_t ret;
-	
-	while (incount != 0) {
-		if ((ret=iconv(cd, &inptr, &incount, &outptr, &outcount)) == (size_t)-1) {
-			if (errno == EILSEQ) {
-				outptr[0]='?';
-				outptr++;
-				incount+=2;
-				outcount++;
-				inptr+=2;
-			} else {
-				stderror();
-				myerror("WARNING: iconv failed!");
-				break;
-			}
-		}
-	}
-  	outptr[0]='\0';
-
-#endif
+	memcpy(utf16lestr, (&lde->LDIR_Ord+1), 10);
+	memcpy(utf16lestr+10, (&lde->LDIR_Ord+14), 12);
+	memcpy(utf16lestr+22, (&lde->LDIR_Ord+28), 4);
+	memset(utf16lestr+26, 0, 2);
 
 	return 0;
 }
@@ -285,15 +233,15 @@ int32_t parseExFATClusterChain(struct sFileSystem *fs, struct sClusterChain *cha
 	uint32_t entries=0;
 	uint32_t expected_entries=0;
 	uint32_t r;
+	uint32_t nameLength=0;
 
 	struct sExFATDirEntry de;
 	struct sExFATDirEntrySet *des;
 	struct sExFATDirEntryList *del=NULL;
 
-	char name[MAX_PATH_LEN+1];
-	char str[31];
+	char utf16_filename[MAX_FILENAME_LEN*2+1];
+	char utf8_filename[MAX_FILENAME_LEN*4+1];
 	char *outptr, *inptr;
-	uint8_t nameLength=0;
 
 	size_t outcount=30;
 	size_t incount, iret;
@@ -304,7 +252,6 @@ int32_t parseExFATClusterChain(struct sFileSystem *fs, struct sClusterChain *cha
 
 	*reordered=0;
 
-	name[0]='\0';
 	while (chain != NULL) {
 		device_seekset(fs->device, getClusterOffset(fs, chain->cluster));
 		// fprintf(stderr, "cluster=%x;clusterOffset=%x\n", chain->cluster, getClusterOffset(fs, chain->cluster));
@@ -352,6 +299,12 @@ int32_t parseExFATClusterChain(struct sFileSystem *fs, struct sClusterChain *cha
 						return -1;
 					}
 					nameLength=de.entry.streamExtDirEntry.nameLen;
+					if (nameLength > MAX_FILENAME_LEN) {
+						myerror("Specified File name length in STEAM EXTENSION ENTRY is longer than %lu bytes (%lu bytes)!",
+								MAX_FILENAME_LEN, nameLength);
+						return -1;
+					}
+					
 					entries++;
 				} else if (!expected_entries) {
 					myerror("Secondary directory entries are not expected here (%u)!", ret);
@@ -370,46 +323,56 @@ int32_t parseExFATClusterChain(struct sFileSystem *fs, struct sClusterChain *cha
 					}
 					entries++;
 
-					// copy filename part to filename
-					outptr = &(str[0]);
-					str[0]='\0';
-					inptr=&(de.entry.FileNameExtDirEntry.filename[0]);
-					if (entries == expected_entries) { // last entry, so file name part is shorter
-						incount = 2 * (nameLength - (entries - 3) * 15);
-					} else {
-						incount=30;
+					if ((entries - 3) * 15 > nameLength) {
+						myerror("%u FILE NAME EXTENSION entries lead to filename length of more than %ul which is greater than specified in FILE STREAM EXTENSION entry!",
+								entries - 2, nameLength);
+						return -1;
 					}
 
-					//printf("incount: %d, length: %d\n", incount, nameLength);
-					outcount=MAX_PATH_LEN;
+					// copy filename part to filename
+					memcpy(utf16_filename+(entries - 3)*30,de.entry.FileNameExtDirEntry.filename, 30);
 
-					/*printf("file name part: " \
+					/*
+					printf("file name part: " \
 						"%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx " \
 						"%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx " \
 						"%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
-						inptr[0], inptr[1], inptr[2], inptr[3], inptr[4],
-						inptr[5], inptr[6], inptr[7], inptr[8], inptr[9],
-						inptr[10], inptr[11], inptr[12], inptr[13], inptr[14],
-						inptr[15], inptr[16], inptr[17], inptr[18], inptr[19],
-						inptr[20], inptr[21], inptr[22], inptr[23], inptr[24],
-						inptr[25], inptr[26], inptr[27], inptr[28], inptr[29]
-					);*/
-
-					while (incount != 0) {
-				                if ((iret=iconv(fs->cd, &inptr, &incount, &outptr, &outcount)) == (size_t)-1) {
-							stderror();
-				                        myerror("iconv failed! %d", iret);
-							return -1;
-				                }
-				        }
-					outptr[0]='\0';
-
-					strncat(name, str, 31);
+						de.entry.FileNameExtDirEntry.filename[0], de.entry.FileNameExtDirEntry.filename[1],
+						de.entry.FileNameExtDirEntry.filename[2], de.entry.FileNameExtDirEntry.filename[3],
+						de.entry.FileNameExtDirEntry.filename[4], de.entry.FileNameExtDirEntry.filename[5],
+						de.entry.FileNameExtDirEntry.filename[6], de.entry.FileNameExtDirEntry.filename[7],
+						de.entry.FileNameExtDirEntry.filename[8], de.entry.FileNameExtDirEntry.filename[9],
+						de.entry.FileNameExtDirEntry.filename[10], de.entry.FileNameExtDirEntry.filename[11],
+						de.entry.FileNameExtDirEntry.filename[12], de.entry.FileNameExtDirEntry.filename[13],
+						de.entry.FileNameExtDirEntry.filename[14], de.entry.FileNameExtDirEntry.filename[15],
+						de.entry.FileNameExtDirEntry.filename[16], de.entry.FileNameExtDirEntry.filename[17],
+						de.entry.FileNameExtDirEntry.filename[18], de.entry.FileNameExtDirEntry.filename[19],
+						de.entry.FileNameExtDirEntry.filename[20], de.entry.FileNameExtDirEntry.filename[21],
+						de.entry.FileNameExtDirEntry.filename[22], de.entry.FileNameExtDirEntry.filename[23],
+						de.entry.FileNameExtDirEntry.filename[24], de.entry.FileNameExtDirEntry.filename[25],
+						de.entry.FileNameExtDirEntry.filename[26], de.entry.FileNameExtDirEntry.filename[27],
+						de.entry.FileNameExtDirEntry.filename[28], de.entry.FileNameExtDirEntry.filename[29]
+					);
+					*/
 
 					// we are done here
 					if (entries == expected_entries) {
 
-						des=newExFATDirEntrySet(name, del, entries);
+						// convert utf-16 string form FILE NAME EXTENSION entries to utf-18 string in current locale
+						incount = nameLength*2;
+						outcount = MAX_FILENAME_LEN*4;
+						inptr = &(utf16_filename[0]);
+						outptr = &(utf8_filename[0]);
+						while (incount != 0) {
+						        if ((iret=iconv(fs->cd, &inptr, &incount, &outptr, &outcount)) == (size_t)-1) {
+								stderror();
+						                myerror("iconv failed! %d", iret);
+								return -1;
+						        }
+						}
+						outptr[0]='\0';				
+												
+						des=newExFATDirEntrySet(utf8_filename, del, entries);
 						if (!des) {
 							myerror("Could not create exFAT directory entry set");
 							return -1;
@@ -433,7 +396,7 @@ int32_t parseExFATClusterChain(struct sFileSystem *fs, struct sClusterChain *cha
 
 						(*direntrysets)++;
 						entries=0;
-						name[0]='\0';
+
 					}
 				} else if (entries >= expected_entries) {
 					myerror("Too many file name extension directory entries!");
@@ -540,7 +503,8 @@ int32_t parseClusterChain(struct sFileSystem *fs, struct sClusterChain *chain, s
 	union sDirEntry de;
 	struct sDirEntryList *lnde;
 	struct sLongDirEntryList *llist;
-	char tmp[MAX_PATH_LEN+1], dummy[MAX_PATH_LEN+1], sname[MAX_PATH_LEN+1], lname[MAX_PATH_LEN+1];
+	char tmp[28], utf16le_lname[MAX_PATH_LEN*2+2], sname[MAX_PATH_LEN+1], lname[MAX_PATH_LEN*4+1], dummy[MAX_PATH_LEN*2+1];
+	size_t incount, outcount;
 
 	*direntries=0;
 
@@ -549,12 +513,21 @@ int32_t parseClusterChain(struct sFileSystem *fs, struct sClusterChain *chain, s
 	llist = NULL;
 	lname[0]='\0';
 	*reordered=0;
+	
+	utf16le_lname[MAX_PATH_LEN*4]='\0';
+	utf16le_lname[MAX_PATH_LEN*4+1]='\0';
+	
 	while (chain != NULL) {
 		device_seekset(fs->device, getClusterOffset(fs, chain->cluster));
 		for (j=0;j<fs->maxDirEntriesPerCluster;j++) {
 			entries++;
 			ret=parseEntry(fs, &de);
-
+			
+			/*
+			printf("entry: %u\n", ret);
+			printf("entries: %u\n", entries);
+			*/
+			
 			switch(ret) {
 			case -1:
 				myerror("Failed to parse directory entry!");
@@ -586,6 +559,47 @@ int32_t parseClusterChain(struct sFileSystem *fs, struct sClusterChain *chain, s
 					printf("!%s (#%s)\n", (lname[0] != '\0') ? lname : "n/a", sname+1);
 				}
 */
+
+				if (entries>1) { // we have a long filename
+					// count characters in long filename
+					uint32_t filenameLen=0;
+					char *p=utf16le_lname;
+					while((p[0] != '\0') || (p[1] != '\0')) {
+						p+=2;filenameLen++;
+					}
+					
+					if (filenameLen > MAX_FILENAME_LEN) {
+						myerror("Filename length exceeds %lu characters (%lu characters)!", MAX_FILENAME_LEN, filenameLen);
+						return -1;
+					}
+				}
+
+				// convert utf-16le long filename to utf-8 in current locale
+				lname[0]='\0';
+				char *outptr = &(lname[0]);
+				char *inptr = &(utf16le_lname[0]);
+				incount=(entries-1)*26;
+				outcount=MAX_PATH_LEN*4;
+
+				while (incount != 0) {
+					if ((iconv(fs->cd, &inptr, &incount, &outptr, &outcount)) == (size_t)-1) {
+						if (errno == EILSEQ) {
+							outptr[0]='?';
+							outptr++;
+							incount-=2;
+							outcount++;
+							inptr+=2;
+						} else {
+							stderror();
+							myerror("iconv failed (errno %u)!", errno);
+							return -1;
+						}
+					}
+				}
+			  	outptr[0]='\0';
+			  	
+			  	//printf("lname (sname): %s (%s)\n", lname, sname);
+
 				lnde=newDirEntry(sname, lname, &de.ShortDirEntry, llist, entries);
 				if (lnde == NULL) {
 					myerror("Failed to create DirEntry!");
@@ -602,10 +616,12 @@ int32_t parseClusterChain(struct sFileSystem *fs, struct sClusterChain *chain, s
 				(*direntries)++;
 				entries=0;
 				llist = NULL;
-				lname[0]='\0';
+				utf16le_lname[0]=L'\0';
+				sname[0]='\0';
 				break;
 			case 2: // long dir entry
-				if (parseLongFilenamePart(&de.LongDirEntry, tmp, fs->cd)) {
+			
+				if (parseLongFilenamePart(&de.LongDirEntry, tmp)) {
 					myerror("Failed to parse long filename part!");
 					return -1;
 				}
@@ -616,12 +632,17 @@ int32_t parseClusterChain(struct sFileSystem *fs, struct sClusterChain *chain, s
 					myerror("Failed to insert LongDirEntry!");
 					return -1;
 				}
-
-				strncpy(dummy, tmp, MAX_PATH_LEN);
-				dummy[MAX_PATH_LEN]='\0';
-				strncat(dummy, lname, MAX_PATH_LEN - strlen(dummy));
-				dummy[MAX_PATH_LEN]='\0';
-				strncpy(lname, dummy, MAX_PATH_LEN+1);
+				
+				/*printf("tmp: ");
+				for(int i=0;i<26;i++){
+					printf("%02hhx ", tmp[i]);
+				}
+				printf("\n");*/
+				
+				memcpy(dummy, tmp, 26);
+				memcpy(dummy+26, utf16le_lname, (entries -1)*26);
+				memcpy(utf16le_lname, dummy, entries*26);
+				memset(utf16le_lname+entries*26, 0, 2);
 
 				break;
 			default:
@@ -657,7 +678,8 @@ int32_t parseFat1xRootDirEntries(struct sFileSystem *fs, struct sDirEntryList *l
 	union sDirEntry de;
 	struct sDirEntryList *lnde;
 	struct sLongDirEntryList *llist;
-	char tmp[MAX_PATH_LEN+1], dummy[MAX_PATH_LEN+1], sname[MAX_PATH_LEN+1], lname[MAX_PATH_LEN+1];
+	char tmp[28], utf16le_lname[MAX_PATH_LEN*2+1], sname[MAX_PATH_LEN+1], lname[MAX_PATH_LEN*4+1], dummy[MAX_PATH_LEN*2+1];
+	size_t incount, outcount;
 
 	*direntries=0;
 
@@ -704,6 +726,47 @@ int32_t parseFat1xRootDirEntries(struct sFileSystem *fs, struct sDirEntryList *l
 				printf("!%s (#%s)\n", (lname[0] != '\0') ? lname : "n/a", sname+1);
 			}
 */
+
+			if (entries>1) { // we have a long filename
+				// count characters in long filename
+				uint32_t filenameLen=0;
+				char *p=utf16le_lname;
+				while((p[0] != '\0') || (p[1] != '\0')) {
+					p+=2;filenameLen++;
+				}
+				
+				if (filenameLen > MAX_FILENAME_LEN) {
+					myerror("Filename length exceeds %lu characters (%lu characters)!", MAX_FILENAME_LEN, filenameLen);
+					return -1;
+				}
+			}
+
+			// convert utf-16le long filename to utf-8 in current locale
+			lname[0]='\0';
+			char *outptr = &(lname[0]);
+			char *inptr = &(utf16le_lname[0]);
+			incount=(entries-1)*26;
+			outcount=MAX_PATH_LEN*4;
+
+			while (incount != 0) {
+				if ((iconv(fs->cd, &inptr, &incount, &outptr, &outcount)) == (size_t)-1) {
+					if (errno == EILSEQ) {
+						outptr[0]='?';
+						outptr++;
+						incount-=2;
+						outcount++;
+						inptr+=2;
+					} else {
+						stderror();
+						myerror("iconv failed (errno %u)!", errno);
+						return -1;
+					}
+				}
+			}
+		  	outptr[0]='\0';
+		  	
+		  	//printf("lname (sname): %s (%s)\n", lname, sname);
+
 			lnde=newDirEntry(sname, lname, &de.ShortDirEntry, llist, entries);
 			if (lnde == NULL) {
 				myerror("Failed to create DirEntry!");
@@ -720,10 +783,11 @@ int32_t parseFat1xRootDirEntries(struct sFileSystem *fs, struct sDirEntryList *l
 			(*direntries)++;
 			entries=0;
 			llist = NULL;
-			lname[0]='\0';
+			utf16le_lname[0]=L'\0';
+			sname[0]='\0';
 			break;
 		case 2: // long dir entry
-			if (parseLongFilenamePart(&de.LongDirEntry, tmp, fs->cd)) {
+			if (parseLongFilenamePart(&de.LongDirEntry, tmp)) {
 				myerror("Failed to parse long filename part!");
 				return -1;
 			}
@@ -735,12 +799,16 @@ int32_t parseFat1xRootDirEntries(struct sFileSystem *fs, struct sDirEntryList *l
 				return -1;
 			}
 
-			strncpy(dummy, tmp, MAX_PATH_LEN);
-			dummy[MAX_PATH_LEN]='\0';
-			strncat(dummy, lname, MAX_PATH_LEN - strlen(dummy));
-			dummy[MAX_PATH_LEN]='\0';
-			strncpy(lname, dummy, MAX_PATH_LEN+1);
-			//dummy[MAX_PATH_LEN]='\0';
+			/*printf("tmp: ");
+			for(int i=0;i<26;i++){
+				printf("%02hhx ", tmp[i]);
+			}
+			printf("\n");*/
+			
+			memcpy(dummy, tmp, 26);
+			memcpy(dummy+26, utf16le_lname, (entries -1)*26);
+			memcpy(utf16le_lname, dummy, entries*26);
+			memset(utf16le_lname+entries*26, 0, 2);
 			break;
 		default:
 			myerror("Unhandled return code!");
diff --git a/tests/images/exfat_bad_filename_too_long.img.xz b/tests/images/exfat_bad_filename_too_long.img.xz
new file mode 100644
index 0000000..ebb39c0
Binary files /dev/null and b/tests/images/exfat_bad_filename_too_long.img.xz differ
diff --git a/tests/images/exfat_good_japanese_filename.img.xz b/tests/images/exfat_good_japanese_filename.img.xz
new file mode 100644
index 0000000..69df9c5
Binary files /dev/null and b/tests/images/exfat_good_japanese_filename.img.xz differ
diff --git a/tests/images/fat16_bad_filename_too_long.img.xz b/tests/images/fat16_bad_filename_too_long.img.xz
new file mode 100644
index 0000000..5083e27
Binary files /dev/null and b/tests/images/fat16_bad_filename_too_long.img.xz differ
diff --git a/tests/images/fat16_good_japanese_filename.img.xz b/tests/images/fat16_good_japanese_filename.img.xz
new file mode 100644
index 0000000..7383487
Binary files /dev/null and b/tests/images/fat16_good_japanese_filename.img.xz differ
diff --git a/tests/images/fat32_bad_filename_too_long.img.xz b/tests/images/fat32_bad_filename_too_long.img.xz
new file mode 100644
index 0000000..0bf64b1
Binary files /dev/null and b/tests/images/fat32_bad_filename_too_long.img.xz differ
diff --git a/tests/images/fat32_good_japanese_filename.img.xz b/tests/images/fat32_good_japanese_filename.img.xz
new file mode 100644
index 0000000..2979a17
Binary files /dev/null and b/tests/images/fat32_good_japanese_filename.img.xz differ
diff --git a/tests/tc_check_consistent_version/Makefile b/tests/tc_check_consistent_version/Makefile
index 709dc1d..f600c45 100755
--- a/tests/tc_check_consistent_version/Makefile
+++ b/tests/tc_check_consistent_version/Makefile
@@ -4,9 +4,9 @@ all: passed
 
 execute:
 	manver=\
-	`head -2 ../../man/fatsort.1 | tail -1 | sed -e "s/^.*\"fatsort \([0-9.]\+\)\".*$$/\1/"`; \
-	progver=`../../src/fatsort --version | head -1 | sed -e "s/^fatsort \([0-9.]\+\).*$$/\1/"`; \
-	changesver=`head -3 ../../CHANGES.md | tail -1 | sed -e "s/^.*v\([0-9.]\+\).*$$/\1/"`; \
+	`head -2 ../../man/fatsort.1 | tail -1 | sed -e "s/^.*\"fatsort \([0-9\.]\+\)\".*/\1/"`; \
+	progver=`../../src/fatsort --version | head -1 | sed -e "s/^fatsort \([0-9.]\+\).*/\1/"`; \
+	changesver=`head -3 ../../CHANGES.md | tail -1 | sed -e "s/^.*v\([0-9.]\+\).*/\1/"`; \
 	echo "#$$manver#$$progver#$$changesver#"; \
 	[ "$$manver" = "$$progver" ]; \
 	[ "$$changesver" = "$$progver" ]
diff --git a/tests/tc_neg_filename_too_long_exfat/Makefile b/tests/tc_neg_filename_too_long_exfat/Makefile
new file mode 100755
index 0000000..be05db8
--- /dev/null
+++ b/tests/tc_neg_filename_too_long_exfat/Makefile
@@ -0,0 +1,40 @@
+include ../testconfig.mk
+
+TESTLOG=test.log
+
+STDOUT=stdout.log
+STDOUT_EXP=stdout_expected.txt
+STDERR=stderr.log
+STDERR_EXP=stderr_expected.txt
+REF_FS_XZ=${IMAGEDIR}/exfat_bad_filename_too_long.img.xz
+
+XZ=xz
+
+all: passed
+	if [ ${DEL_FS_ON_PASS} -eq 1 ]; then rm -f ${FS_IMG}; fi
+
+clean:
+	rm -f passed
+	rm -fr *.log *.tmp ${FS_IMG} ${TMPFILE} ${TMPDIR}
+
+$(FS_IMG): $(REF_FS_XZ)
+	# ++++++++++ Unpacking reference file systen ++++++++++
+	mkdir -p $(TMPDIR)
+	${XZ} -d -f --stdout ${REF_FS_XZ} >> ${FS_IMG}
+
+execute: $(FS_IMG)
+	# ++++++++++ Executing tests ++++++++++
+	${FATSORT} ${FS_IMG} > ${STDOUT} 2> ${STDERR}; [ $$? -ne 0 ]
+	diff ${STDOUT} ${STDOUT_EXP}
+	diff ${STDERR} ${STDERR_EXP}
+
+# check result
+fsck: execute
+	# ++++++++++ Checking file system ++++++++++
+	fsck.vfat -n ${FS_IMG}
+
+# test passed
+passed: execute
+	touch passed
+
+.PHONY: passed fsck execute clean
diff --git a/tests/tc_neg_filename_too_long_exfat/stderr_expected.txt b/tests/tc_neg_filename_too_long_exfat/stderr_expected.txt
new file mode 100644
index 0000000..08a1459
--- /dev/null
+++ b/tests/tc_neg_filename_too_long_exfat/stderr_expected.txt
@@ -0,0 +1,4 @@
+parseExFATClusterChain: Secondary count in exFAT file directory entry is too big (19)!
+sortExFATClusterChain: Failed to parse cluster chain!
+sortFileSystem: Failed to sort first cluster chain!
+main: Failed to sort file system!
diff --git a/tests/tc_neg_filename_too_long_exfat/stdout_expected.txt b/tests/tc_neg_filename_too_long_exfat/stdout_expected.txt
new file mode 100644
index 0000000..68d3e99
--- /dev/null
+++ b/tests/tc_neg_filename_too_long_exfat/stdout_expected.txt
@@ -0,0 +1,3 @@
+File system: exFAT.
+
+Sorting directory /
diff --git a/tests/tc_neg_filename_too_long_fat16/Makefile b/tests/tc_neg_filename_too_long_fat16/Makefile
new file mode 100755
index 0000000..fa2657a
--- /dev/null
+++ b/tests/tc_neg_filename_too_long_fat16/Makefile
@@ -0,0 +1,40 @@
+include ../testconfig.mk
+
+TESTLOG=test.log
+
+STDOUT=stdout.log
+STDOUT_EXP=stdout_expected.txt
+STDERR=stderr.log
+STDERR_EXP=stderr_expected.txt
+REF_FS_XZ=${IMAGEDIR}/fat16_bad_filename_too_long.img.xz
+
+XZ=xz
+
+all: passed
+	if [ ${DEL_FS_ON_PASS} -eq 1 ]; then rm -f ${FS_IMG}; fi
+
+clean:
+	rm -f passed
+	rm -fr *.log *.tmp ${FS_IMG} ${TMPFILE} ${TMPDIR}
+
+$(FS_IMG): $(REF_FS_XZ)
+	# ++++++++++ Unpacking reference file systen ++++++++++
+	mkdir -p $(TMPDIR)
+	${XZ} -d -f --stdout ${REF_FS_XZ} >> ${FS_IMG}
+
+execute: $(FS_IMG)
+	# ++++++++++ Executing tests ++++++++++
+	${FATSORT} ${FS_IMG} > ${STDOUT} 2> ${STDERR}; [ $$? -ne 0 ]
+	diff ${STDOUT} ${STDOUT_EXP}
+	diff ${STDERR} ${STDERR_EXP}
+
+# check result
+fsck: execute
+	# ++++++++++ Checking file system ++++++++++
+	fsck.vfat -n ${FS_IMG}
+
+# test passed
+passed: execute
+	touch passed
+
+.PHONY: passed fsck execute clean
diff --git a/tests/tc_neg_filename_too_long_fat16/stderr_expected.txt b/tests/tc_neg_filename_too_long_fat16/stderr_expected.txt
new file mode 100644
index 0000000..a2940d2
--- /dev/null
+++ b/tests/tc_neg_filename_too_long_fat16/stderr_expected.txt
@@ -0,0 +1,4 @@
+parseFat1xRootDirEntries: Filename length exceeds 255 characters (260 characters)!
+sortFat1xRootDirectory: Failed to parse root directory entries!
+sortFileSystem: Failed to sort FAT16 root directory!
+main: Failed to sort file system!
diff --git a/tests/tc_neg_filename_too_long_fat16/stdout_expected.txt b/tests/tc_neg_filename_too_long_fat16/stdout_expected.txt
new file mode 100644
index 0000000..d878a1b
--- /dev/null
+++ b/tests/tc_neg_filename_too_long_fat16/stdout_expected.txt
@@ -0,0 +1,3 @@
+File system: FAT16.
+
+Sorting directory /
diff --git a/tests/tc_neg_filename_too_long_fat32/Makefile b/tests/tc_neg_filename_too_long_fat32/Makefile
new file mode 100755
index 0000000..093dc9f
--- /dev/null
+++ b/tests/tc_neg_filename_too_long_fat32/Makefile
@@ -0,0 +1,40 @@
+include ../testconfig.mk
+
+TESTLOG=test.log
+
+STDOUT=stdout.log
+STDOUT_EXP=stdout_expected.txt
+STDERR=stderr.log
+STDERR_EXP=stderr_expected.txt
+REF_FS_XZ=${IMAGEDIR}/fat32_bad_filename_too_long.img.xz
+
+XZ=xz
+
+all: passed
+	if [ ${DEL_FS_ON_PASS} -eq 1 ]; then rm -f ${FS_IMG}; fi
+
+clean:
+	rm -f passed
+	rm -fr *.log *.tmp ${FS_IMG} ${TMPFILE} ${TMPDIR}
+
+$(FS_IMG): $(REF_FS_XZ)
+	# ++++++++++ Unpacking reference file systen ++++++++++
+	mkdir -p $(TMPDIR)
+	${XZ} -d -f --stdout ${REF_FS_XZ} >> ${FS_IMG}
+
+execute: $(FS_IMG)
+	# ++++++++++ Executing tests ++++++++++
+	${FATSORT} ${FS_IMG} > ${STDOUT} 2> ${STDERR}; [ $$? -ne 0 ]
+	diff ${STDOUT} ${STDOUT_EXP}
+	diff ${STDERR} ${STDERR_EXP}
+
+# check result
+fsck: execute
+	# ++++++++++ Checking file system ++++++++++
+	fsck.vfat -n ${FS_IMG}
+
+# test passed
+passed: execute
+	touch passed
+
+.PHONY: passed fsck execute clean
diff --git a/tests/tc_neg_filename_too_long_fat32/stderr_expected.txt b/tests/tc_neg_filename_too_long_fat32/stderr_expected.txt
new file mode 100644
index 0000000..2a7d2e5
--- /dev/null
+++ b/tests/tc_neg_filename_too_long_fat32/stderr_expected.txt
@@ -0,0 +1,4 @@
+parseClusterChain: Filename length exceeds 255 characters (260 characters)!
+sortClusterChain: Failed to parse cluster chain!
+sortFileSystem: Failed to sort first cluster chain!
+main: Failed to sort file system!
diff --git a/tests/tc_neg_filename_too_long_fat32/stdout_expected.txt b/tests/tc_neg_filename_too_long_fat32/stdout_expected.txt
new file mode 100644
index 0000000..14326ca
--- /dev/null
+++ b/tests/tc_neg_filename_too_long_fat32/stdout_expected.txt
@@ -0,0 +1,3 @@
+File system: FAT32.
+
+Sorting directory /
diff --git a/tests/tc_pos_japanese_4-byte_characters_exfat/Makefile b/tests/tc_pos_japanese_4-byte_characters_exfat/Makefile
new file mode 100755
index 0000000..0771ace
--- /dev/null
+++ b/tests/tc_pos_japanese_4-byte_characters_exfat/Makefile
@@ -0,0 +1,41 @@
+include ../testconfig.mk
+
+TESTLOG=test.log
+
+STDOUT=stdout.log
+STDOUT_EXP=stdout_expected.txt
+STDERR=stderr.log
+STDERR_EXP=stderr_expected.txt
+REF_FS_XZ=${IMAGEDIR}/exfat_good_japanese_filename.img.xz
+
+XZ=xz
+
+all: passed
+	if [ ${DEL_FS_ON_PASS} -eq 1 ]; then rm -f ${FS_IMG}; fi
+
+clean:
+	rm -f passed
+	rm -fr *.log *.tmp ${FS_IMG} ${TMPFILE} ${TMPDIR}
+
+$(FS_IMG): $(REF_FS_XZ)
+	# ++++++++++ Unpacking reference file systen ++++++++++
+	mkdir -p $(TMPDIR)
+	${XZ} -d -f --stdout ${REF_FS_XZ} >> ${FS_IMG}
+
+execute: $(FS_IMG)
+	# ++++++++++ Executing tests ++++++++++
+	${FATSORT} ${FS_IMG}
+	${FATSORT} -l ${FS_IMG} > ${STDOUT} 2> ${STDERR}
+	diff ${STDOUT} ${STDOUT_EXP}
+	diff ${STDERR} ${STDERR_EXP}
+
+# check result
+fsck: execute
+	# ++++++++++ Checking file system ++++++++++
+	fsck.vfat -n ${FS_IMG}
+
+# test passed
+passed: execute
+	touch passed
+
+.PHONY: passed fsck execute clean
diff --git a/tests/tc_pos_japanese_4-byte_characters_exfat/stderr_expected.txt b/tests/tc_pos_japanese_4-byte_characters_exfat/stderr_expected.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/tc_pos_japanese_4-byte_characters_exfat/stdout_expected.txt b/tests/tc_pos_japanese_4-byte_characters_exfat/stdout_expected.txt
new file mode 100644
index 0000000..75b172d
--- /dev/null
+++ b/tests/tc_pos_japanese_4-byte_characters_exfat/stdout_expected.txt
@@ -0,0 +1,11 @@
+File system: exFAT.
+
+/
+𩸽
+𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽
+𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽
+𩸽,
+07. 愛を伝えたいだとか.m4a
+𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽A
+か
+
diff --git a/tests/tc_pos_japanese_4-byte_characters_fat16/Makefile b/tests/tc_pos_japanese_4-byte_characters_fat16/Makefile
new file mode 100755
index 0000000..dac4ec9
--- /dev/null
+++ b/tests/tc_pos_japanese_4-byte_characters_fat16/Makefile
@@ -0,0 +1,41 @@
+include ../testconfig.mk
+
+TESTLOG=test.log
+
+STDOUT=stdout.log
+STDOUT_EXP=stdout_expected.txt
+STDERR=stderr.log
+STDERR_EXP=stderr_expected.txt
+REF_FS_XZ=${IMAGEDIR}/fat16_good_japanese_filename.img.xz
+
+XZ=xz
+
+all: passed
+	if [ ${DEL_FS_ON_PASS} -eq 1 ]; then rm -f ${FS_IMG}; fi
+
+clean:
+	rm -f passed
+	rm -fr *.log *.tmp ${FS_IMG} ${TMPFILE} ${TMPDIR}
+
+$(FS_IMG): $(REF_FS_XZ)
+	# ++++++++++ Unpacking reference file systen ++++++++++
+	mkdir -p $(TMPDIR)
+	${XZ} -d -f --stdout ${REF_FS_XZ} >> ${FS_IMG}
+
+execute: $(FS_IMG)
+	# ++++++++++ Executing tests ++++++++++
+	${FATSORT} ${FS_IMG}
+	${FATSORT} -l ${FS_IMG} > ${STDOUT} 2> ${STDERR}
+	diff ${STDOUT} ${STDOUT_EXP}
+	diff ${STDERR} ${STDERR_EXP}
+
+# check result
+fsck: execute
+	# ++++++++++ Checking file system ++++++++++
+	fsck.vfat -n ${FS_IMG}
+
+# test passed
+passed: execute
+	touch passed
+
+.PHONY: passed fsck execute clean
diff --git a/tests/tc_pos_japanese_4-byte_characters_fat16/stderr_expected.txt b/tests/tc_pos_japanese_4-byte_characters_fat16/stderr_expected.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/tc_pos_japanese_4-byte_characters_fat16/stdout_expected.txt b/tests/tc_pos_japanese_4-byte_characters_fat16/stdout_expected.txt
new file mode 100644
index 0000000..75e6044
--- /dev/null
+++ b/tests/tc_pos_japanese_4-byte_characters_fat16/stdout_expected.txt
@@ -0,0 +1,11 @@
+File system: FAT16.
+
+/
+𩸽
+𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽
+𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽
+𩸽,
+07. 愛を伝えたいだとか.m4a
+𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽A
+か
+
diff --git a/tests/tc_pos_japanese_4-byte_characters_fat32/Makefile b/tests/tc_pos_japanese_4-byte_characters_fat32/Makefile
new file mode 100755
index 0000000..90e0cf5
--- /dev/null
+++ b/tests/tc_pos_japanese_4-byte_characters_fat32/Makefile
@@ -0,0 +1,41 @@
+include ../testconfig.mk
+
+TESTLOG=test.log
+
+STDOUT=stdout.log
+STDOUT_EXP=stdout_expected.txt
+STDERR=stderr.log
+STDERR_EXP=stderr_expected.txt
+REF_FS_XZ=${IMAGEDIR}/fat32_good_japanese_filename.img.xz
+
+XZ=xz
+
+all: passed
+	if [ ${DEL_FS_ON_PASS} -eq 1 ]; then rm -f ${FS_IMG}; fi
+
+clean:
+	rm -f passed
+	rm -fr *.log *.tmp ${FS_IMG} ${TMPFILE} ${TMPDIR}
+
+$(FS_IMG): $(REF_FS_XZ)
+	# ++++++++++ Unpacking reference file systen ++++++++++
+	mkdir -p $(TMPDIR)
+	${XZ} -d -f --stdout ${REF_FS_XZ} >> ${FS_IMG}
+
+execute: $(FS_IMG)
+	# ++++++++++ Executing tests ++++++++++
+	${FATSORT} ${FS_IMG}
+	${FATSORT} -l ${FS_IMG} > ${STDOUT} 2> ${STDERR}
+	diff ${STDOUT} ${STDOUT_EXP}
+	diff ${STDERR} ${STDERR_EXP}
+
+# check result
+fsck: execute
+	# ++++++++++ Checking file system ++++++++++
+	fsck.vfat -n ${FS_IMG}
+
+# test passed
+passed: execute
+	touch passed
+
+.PHONY: passed fsck execute clean
diff --git a/tests/tc_pos_japanese_4-byte_characters_fat32/stderr_expected.txt b/tests/tc_pos_japanese_4-byte_characters_fat32/stderr_expected.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/tc_pos_japanese_4-byte_characters_fat32/stdout_expected.txt b/tests/tc_pos_japanese_4-byte_characters_fat32/stdout_expected.txt
new file mode 100644
index 0000000..10b5ef3
--- /dev/null
+++ b/tests/tc_pos_japanese_4-byte_characters_fat32/stdout_expected.txt
@@ -0,0 +1,11 @@
+File system: FAT32.
+
+/
+𩸽
+𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽
+𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽
+𩸽,
+07. 愛を伝えたいだとか.m4a
+𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽A
+か
+
diff --git a/tests/ts_all b/tests/ts_all
index 4cc1f7c..5ce4150 100644
--- a/tests/ts_all
+++ b/tests/ts_all
@@ -28,8 +28,14 @@ tc_neg_missing_sne_at_end_of_cluster_fat32
 tc_neg_missing_sne_at_end_of_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat32
+tc_neg_filename_too_long_fat16
+tc_neg_filename_too_long_fat32
+tc_neg_filename_too_long_exfat
 tc_pos_char_enc_C
 tc_pos_char_enc_iso8859-1
+tc_pos_japanese_4-byte_characters_exfat
+tc_pos_japanese_4-byte_characters_fat16
+tc_pos_japanese_4-byte_characters_fat32
 tc_pos_one_fat_fat12
 tc_pos_one_fat_fat16
 tc_pos_one_fat_fat32
diff --git a/tests/ts_amd64 b/tests/ts_amd64
index 4cc1f7c..5ce4150 100644
--- a/tests/ts_amd64
+++ b/tests/ts_amd64
@@ -28,8 +28,14 @@ tc_neg_missing_sne_at_end_of_cluster_fat32
 tc_neg_missing_sne_at_end_of_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat32
+tc_neg_filename_too_long_fat16
+tc_neg_filename_too_long_fat32
+tc_neg_filename_too_long_exfat
 tc_pos_char_enc_C
 tc_pos_char_enc_iso8859-1
+tc_pos_japanese_4-byte_characters_exfat
+tc_pos_japanese_4-byte_characters_fat16
+tc_pos_japanese_4-byte_characters_fat32
 tc_pos_one_fat_fat12
 tc_pos_one_fat_fat16
 tc_pos_one_fat_fat32
diff --git a/tests/ts_arm b/tests/ts_arm
index b4989ec..59b5589 100644
--- a/tests/ts_arm
+++ b/tests/ts_arm
@@ -28,8 +28,14 @@ tc_neg_missing_sne_at_end_of_cluster_fat32
 tc_neg_missing_sne_at_end_of_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat32
+tc_neg_filename_too_long_fat16
+tc_neg_filename_too_long_fat32
+tc_neg_filename_too_long_exfat
 tc_pos_char_enc_C
 tc_pos_char_enc_iso8859-1
+tc_pos_japanese_4-byte_characters_exfat
+tc_pos_japanese_4-byte_characters_fat16
+tc_pos_japanese_4-byte_characters_fat32
 tc_pos_one_fat_fat12
 tc_pos_one_fat_fat16
 tc_pos_one_fat_fat32
diff --git a/tests/ts_i386 b/tests/ts_i386
index 74b89dd..4a1e6f9 100644
--- a/tests/ts_i386
+++ b/tests/ts_i386
@@ -30,6 +30,9 @@ tc_neg_missing_sne_in_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat32
 tc_pos_char_enc_C
 tc_pos_char_enc_iso8859-1
+tc_pos_japanese_4-byte_characters_exfat
+tc_pos_japanese_4-byte_characters_fat16
+tc_pos_japanese_4-byte_characters_fat32
 tc_pos_one_fat_fat12
 tc_pos_one_fat_fat16
 tc_pos_one_fat_fat32
diff --git a/tests/ts_ppc b/tests/ts_ppc
index b4989ec..59b5589 100644
--- a/tests/ts_ppc
+++ b/tests/ts_ppc
@@ -28,8 +28,14 @@ tc_neg_missing_sne_at_end_of_cluster_fat32
 tc_neg_missing_sne_at_end_of_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat32
+tc_neg_filename_too_long_fat16
+tc_neg_filename_too_long_fat32
+tc_neg_filename_too_long_exfat
 tc_pos_char_enc_C
 tc_pos_char_enc_iso8859-1
+tc_pos_japanese_4-byte_characters_exfat
+tc_pos_japanese_4-byte_characters_fat16
+tc_pos_japanese_4-byte_characters_fat32
 tc_pos_one_fat_fat12
 tc_pos_one_fat_fat16
 tc_pos_one_fat_fat32
diff --git a/tests/ts_ppc64le b/tests/ts_ppc64le
index b4989ec..59b5589 100644
--- a/tests/ts_ppc64le
+++ b/tests/ts_ppc64le
@@ -28,8 +28,14 @@ tc_neg_missing_sne_at_end_of_cluster_fat32
 tc_neg_missing_sne_at_end_of_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat32
+tc_neg_filename_too_long_fat16
+tc_neg_filename_too_long_fat32
+tc_neg_filename_too_long_exfat
 tc_pos_char_enc_C
 tc_pos_char_enc_iso8859-1
+tc_pos_japanese_4-byte_characters_exfat
+tc_pos_japanese_4-byte_characters_fat16
+tc_pos_japanese_4-byte_characters_fat32
 tc_pos_one_fat_fat12
 tc_pos_one_fat_fat16
 tc_pos_one_fat_fat32
diff --git a/tests/ts_s390x b/tests/ts_s390x
index b4989ec..59b5589 100644
--- a/tests/ts_s390x
+++ b/tests/ts_s390x
@@ -28,8 +28,14 @@ tc_neg_missing_sne_at_end_of_cluster_fat32
 tc_neg_missing_sne_at_end_of_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat16
 tc_neg_missing_sne_in_root_dir_fat32
+tc_neg_filename_too_long_fat16
+tc_neg_filename_too_long_fat32
+tc_neg_filename_too_long_exfat
 tc_pos_char_enc_C
 tc_pos_char_enc_iso8859-1
+tc_pos_japanese_4-byte_characters_exfat
+tc_pos_japanese_4-byte_characters_fat16
+tc_pos_japanese_4-byte_characters_fat32
 tc_pos_one_fat_fat12
 tc_pos_one_fat_fat16
 tc_pos_one_fat_fat32

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

More details

Full run details