mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +00:00 
			
		
		
		
	Handle missing file metadata on zip files
- Return EPOCH if a zip entry's creation/modification/access time is missing. - If a BasicFileAttributes.*Time method returns null, use 0 as our time. This shouldn't happen, but is a good sanity check. Fixes #371
This commit is contained in:
		| @@ -23,6 +23,7 @@ import java.io.BufferedWriter; | |||||||
| import java.nio.channels.ReadableByteChannel; | import java.nio.channels.ReadableByteChannel; | ||||||
| import java.nio.channels.WritableByteChannel; | import java.nio.channels.WritableByteChannel; | ||||||
| import java.nio.file.attribute.BasicFileAttributes; | import java.nio.file.attribute.BasicFileAttributes; | ||||||
|  | import java.nio.file.attribute.FileTime; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.OptionalLong; | import java.util.OptionalLong; | ||||||
| @@ -359,8 +360,8 @@ public class FSAPI implements ILuaAPI | |||||||
|                 { |                 { | ||||||
|                     BasicFileAttributes attributes = m_fileSystem.getAttributes( path ); |                     BasicFileAttributes attributes = m_fileSystem.getAttributes( path ); | ||||||
|                     Map<String, Object> result = new HashMap<>(); |                     Map<String, Object> result = new HashMap<>(); | ||||||
|                     result.put( "modification", attributes.lastModifiedTime().toMillis() ); |                     result.put( "modification", getFileTime( attributes.lastModifiedTime() ) ); | ||||||
|                     result.put( "created", attributes.creationTime().toMillis() ); |                     result.put( "created", getFileTime( attributes.creationTime() ) ); | ||||||
|                     result.put( "size", attributes.isDirectory() ? 0 : attributes.size() ); |                     result.put( "size", attributes.isDirectory() ? 0 : attributes.size() ); | ||||||
|                     result.put( "isDir", attributes.isDirectory() ); |                     result.put( "isDir", attributes.isDirectory() ); | ||||||
|                     return new Object[] { result }; |                     return new Object[] { result }; | ||||||
| @@ -375,4 +376,9 @@ public class FSAPI implements ILuaAPI | |||||||
|                 return null; |                 return null; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private static long getFileTime( FileTime time ) | ||||||
|  |     { | ||||||
|  |         return time == null ? 0 : time.toMillis(); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ import java.nio.channels.Channels; | |||||||
| import java.nio.channels.ReadableByteChannel; | import java.nio.channels.ReadableByteChannel; | ||||||
| import java.nio.file.attribute.BasicFileAttributes; | import java.nio.file.attribute.BasicFileAttributes; | ||||||
| import java.nio.file.attribute.FileTime; | import java.nio.file.attribute.FileTime; | ||||||
|  | import java.time.Instant; | ||||||
| import java.util.Enumeration; | import java.util.Enumeration; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| @@ -290,19 +291,20 @@ public class JarMount implements IMount | |||||||
|         @Override |         @Override | ||||||
|         public FileTime lastModifiedTime() |         public FileTime lastModifiedTime() | ||||||
|         { |         { | ||||||
|             return entry.getLastModifiedTime(); |             return orEpoch( entry.getLastModifiedTime() ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         @Override |         @Override | ||||||
|         public FileTime lastAccessTime() |         public FileTime lastAccessTime() | ||||||
|         { |         { | ||||||
|             return entry.getLastAccessTime(); |             return orEpoch( entry.getLastAccessTime() ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         @Override |         @Override | ||||||
|         public FileTime creationTime() |         public FileTime creationTime() | ||||||
|         { |         { | ||||||
|             return entry.getCreationTime(); |             FileTime time = entry.getCreationTime(); | ||||||
|  |             return time == null ? lastModifiedTime() : time; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         @Override |         @Override | ||||||
| @@ -340,5 +342,12 @@ public class JarMount implements IMount | |||||||
|         { |         { | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         private static final FileTime EPOCH = FileTime.from( Instant.EPOCH ); | ||||||
|  |  | ||||||
|  |         private static FileTime orEpoch( FileTime time ) | ||||||
|  |         { | ||||||
|  |             return time == null ? EPOCH : time; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,20 +15,24 @@ import java.io.FileOutputStream; | |||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.InputStream; | import java.io.InputStream; | ||||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||||
|  | import java.nio.file.attribute.BasicFileAttributes; | ||||||
|  | import java.nio.file.attribute.FileTime; | ||||||
|  | import java.time.Instant; | ||||||
|  | import java.time.temporal.ChronoUnit; | ||||||
| import java.util.zip.ZipEntry; | import java.util.zip.ZipEntry; | ||||||
| import java.util.zip.ZipOutputStream; | import java.util.zip.ZipOutputStream; | ||||||
|  |  | ||||||
| import static org.junit.jupiter.api.Assertions.*; | import static org.junit.jupiter.api.Assertions.*; | ||||||
|  |  | ||||||
| @SuppressWarnings( "deprecation" ) |  | ||||||
| public class JarMountTest | public class JarMountTest | ||||||
| { | { | ||||||
|     private static final File ZIP_FILE = new File( "test-files/jar-mount.zip" ); |     private static final File ZIP_FILE = new File( "test-files/jar-mount.zip" ); | ||||||
|  |  | ||||||
|  |     private static final FileTime MODIFY_TIME = FileTime.from( Instant.EPOCH.plus( 2, ChronoUnit.DAYS ) ); | ||||||
|  |  | ||||||
|     @BeforeAll |     @BeforeAll | ||||||
|     public static void before() throws IOException |     public static void before() throws IOException | ||||||
|     { |     { | ||||||
|         if( ZIP_FILE.exists() ) return; |  | ||||||
|         ZIP_FILE.getParentFile().mkdirs(); |         ZIP_FILE.getParentFile().mkdirs(); | ||||||
|  |  | ||||||
|         try( ZipOutputStream stream = new ZipOutputStream( new FileOutputStream( ZIP_FILE ) ) ) |         try( ZipOutputStream stream = new ZipOutputStream( new FileOutputStream( ZIP_FILE ) ) ) | ||||||
| @@ -36,7 +40,7 @@ public class JarMountTest | |||||||
|             stream.putNextEntry( new ZipEntry( "dir/" ) ); |             stream.putNextEntry( new ZipEntry( "dir/" ) ); | ||||||
|             stream.closeEntry(); |             stream.closeEntry(); | ||||||
|  |  | ||||||
|             stream.putNextEntry( new ZipEntry( "dir/file.lua" ) ); |             stream.putNextEntry( new ZipEntry( "dir/file.lua" ).setLastModifiedTime( MODIFY_TIME ) ); | ||||||
|             stream.write( "print('testing')".getBytes( StandardCharsets.UTF_8 ) ); |             stream.write( "print('testing')".getBytes( StandardCharsets.UTF_8 ) ); | ||||||
|             stream.closeEntry(); |             stream.closeEntry(); | ||||||
|         } |         } | ||||||
| @@ -63,7 +67,7 @@ public class JarMountTest | |||||||
|     { |     { | ||||||
|         IMount mount = new JarMount( ZIP_FILE, "dir/file.lua" ); |         IMount mount = new JarMount( ZIP_FILE, "dir/file.lua" ); | ||||||
|         byte[] contents; |         byte[] contents; | ||||||
|         try( InputStream stream = mount.openForRead( "" ) ) |         try( @SuppressWarnings( "deprecation" ) InputStream stream = mount.openForRead( "" ) ) | ||||||
|         { |         { | ||||||
|             contents = ByteStreams.toByteArray( stream ); |             contents = ByteStreams.toByteArray( stream ); | ||||||
|         } |         } | ||||||
| @@ -76,11 +80,28 @@ public class JarMountTest | |||||||
|     { |     { | ||||||
|         IMount mount = new JarMount( ZIP_FILE, "dir" ); |         IMount mount = new JarMount( ZIP_FILE, "dir" ); | ||||||
|         byte[] contents; |         byte[] contents; | ||||||
|         try( InputStream stream = mount.openForRead( "file.lua" ) ) |         try( @SuppressWarnings( "deprecation" ) InputStream stream = mount.openForRead( "file.lua" ) ) | ||||||
|         { |         { | ||||||
|             contents = ByteStreams.toByteArray( stream ); |             contents = ByteStreams.toByteArray( stream ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         assertEquals( new String( contents, StandardCharsets.UTF_8 ), "print('testing')" ); |         assertEquals( new String( contents, StandardCharsets.UTF_8 ), "print('testing')" ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void fileAttributes() throws IOException | ||||||
|  |     { | ||||||
|  |         BasicFileAttributes attributes = new JarMount( ZIP_FILE, "dir" ).getAttributes( "file.lua" ); | ||||||
|  |         assertFalse( attributes.isDirectory() ); | ||||||
|  |         assertEquals( "print('testing')".length(), attributes.size() ); | ||||||
|  |         assertEquals( MODIFY_TIME, attributes.lastModifiedTime() ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void directoryAttributes() throws IOException | ||||||
|  |     { | ||||||
|  |         BasicFileAttributes attributes = new JarMount( ZIP_FILE, "dir" ).getAttributes( "" ); | ||||||
|  |         assertTrue( attributes.isDirectory() ); | ||||||
|  |         assertEquals( 0, attributes.size() ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 SquidDev
					SquidDev