/* * $Id$ * * Copyright (C) 2003-2014 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.test.fs.hfsplus; import java.io.File; import java.io.IOException; import org.jnode.driver.Device; import org.jnode.driver.block.FileDevice; import org.jnode.fs.hfsplus.HFSPlusParams; import org.jnode.fs.hfsplus.HfsPlusFileSystem; import org.jnode.fs.hfsplus.HfsPlusFileSystemType; import org.jnode.fs.hfsplus.SuperBlock; import org.jnode.test.fs.DataStructureAsserts; import org.jnode.fs.FSDirectory; import org.jnode.test.fs.FileSystemTestUtils; import org.jnode.fs.service.FileSystemService; import org.jnode.test.support.TestUtils; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class HfsPlusFileSystemTest { private Device device; private FileSystemService fss; @Before public void setUp() throws Exception { // create test device. device = createTestDisk(false); // create file system service. fss = FileSystemTestUtils.createFSService(HfsPlusFileSystemType.class.getName()); } @Test public void testReadSmallDisk() throws Exception { device = new FileDevice(FileSystemTestUtils.getTestFile("test/fs/hfsplus/test.hfsplus"), "r"); HfsPlusFileSystemType type = fss.getFileSystemType(HfsPlusFileSystemType.ID); HfsPlusFileSystem fs = type.create(device, true); String expectedStructure = "type: HFS+ vol:Kenny total:67108864 free:66035712\n" + " /; \n" + " southpark.jpeg; 6420; 5a2ec290089ee04a470135f3bda29f94\n" + " test.txt; 1141; 48b97c1f1defb52c77ce75d55a4b066c\n" + " \u0000\u0000\u0000\u0000HFS+ Private Data; \n"; DataStructureAsserts.assertStructure(fs, expectedStructure); } @Test public void testReadDiskWithDirectoryHardLinks() throws Exception { device = new FileDevice(FileSystemTestUtils.getTestFile("test/fs/hfsplus/hard-linked-directories.dmg"), "r"); HfsPlusFileSystemType type = fss.getFileSystemType(HfsPlusFileSystemType.ID); HfsPlusFileSystem fs = type.create(device, true); String expectedStructure = "type: HFS+ vol:Hard linked directories total:40960000 free:39428096\n" + " /; \n" + " .DS_Store; 6148; cbdca44c18b8de8671b413b2023ef664\n" + " .fseventsd; \n" + " 00000000214ea109; 231; 11618d6f301d3672e498609838d23a8c\n" + " 00000000214ea10a; 72; 6f20b722869a82510ca98e99071c4aca\n" + " fseventsd-uuid; 36; 2b95938d530cb32e96dfc01671095522\n" + " .HFS+ Private Directory Data\r; \n" + " dir_25; \n" + " file.txt; 38; 23c1bd7263b9abbdbb879e6267d84ff8\n" + " .journal; 524288; 7c1d0a50a9738dd88572a9cee56c0270\n" + " .journal_info_block; 4096; 469270564228a832e83d2ad16e6d8edc\n" + " .Trashes; \n" + " dir1; \n" + " clone; \n" + " file.txt; 38; 23c1bd7263b9abbdbb879e6267d84ff8\n" + " dir2; \n" + " clone; \n" + " file.txt; 38; 23c1bd7263b9abbdbb879e6267d84ff8\n" + " \u0000\u0000\u0000\u0000HFS+ Private Data; \n"; DataStructureAsserts.assertStructure(fs, expectedStructure); } @Test public void testReadDiskWithFileHardLinks() throws Exception { device = new FileDevice(FileSystemTestUtils.getTestFile("test/fs/hfsplus/hard-linked-files.dmg"), "r"); HfsPlusFileSystemType type = fss.getFileSystemType(HfsPlusFileSystemType.ID); HfsPlusFileSystem fs = type.create(device, true); String expectedStructure = "type: HFS+ vol:hard-links total:40960000 free:39436288\n" + " /; \n" + " .DS_Store; 6148; b5ae7323596898677123c65fcce1be07\n" + " .fseventsd; \n" + " 00000000214eb5f7; 121; 45f770b87c4fb7773466ed4ea7333248\n" + " 00000000214eb5f8; 72; 261dba091a629e61f127ed183b42ae01\n" + " fseventsd-uuid; 36; f4f9aca6866b93ba4ab04768132dbbf6\n" + " .HFS+ Private Directory Data\r; \n" + " .journal; 524288; 7d69775e76f5a59e0f8687f792df23dc\n" + " .journal_info_block; 4096; 469270564228a832e83d2ad16e6d8edc\n" + " .Trashes; \n" + " arrest.txt; 1933; bedea6f1277f61a924388fbb58281e4a\n" + " diapers.txt; 1933; bedea6f1277f61a924388fbb58281e4a\n" + " \u0000\u0000\u0000\u0000HFS+ Private Data; \n" + " iNode27; 1933; bedea6f1277f61a924388fbb58281e4a\n"; DataStructureAsserts.assertStructure(fs, expectedStructure); } @Test public void testReadDiskWithCompressedFiles() throws Exception { device = new FileDevice(FileSystemTestUtils.getTestFile("test/fs/hfsplus/compressed.dd"), "r"); HfsPlusFileSystemType type = fss.getFileSystemType(HfsPlusFileSystemType.ID); HfsPlusFileSystem fs = type.create(device, true); String expectedStructure = "type: HFS+ vol:Disk Image total:102379520 free:99401728\n" + " /; \n" + " .DS_Store; 6148; 98cf7ff1fd8e81ba4839043e208fb63e\n" + " .fseventsd; \n" + " 00000000219733ae; 158; f512a16c903a637e27f3e81a10f224a2\n" + " 00000000219733af; 72; fa4d4f58441685c90841126fb5ea35e5\n" + " fseventsd-uuid; 36; 3495348c1edb3f39b3cd4222024723c0\n" + " .HFS+ Private Directory Data\r; \n" + " .journal; 524288; ba95a916b83c8478fb22c180893cffff\n" + " .journal_info_block; 4096; 469270564228a832e83d2ad16e6d8edc\n" + " .Trashes; \n" + " compression.html; 81757; 64ae4e5007fdec27518d9073c72a1714\n" + " compression.html:rsrc; 21007; 6727899de0b20d7dcb92c68ecaa8bfe2\n" + " small.txt; 6; d15dbfcb847653913855e21370d83af1\n" + " zlib.txt; 6211; e63c9b3344d96dbd6c5ddd0debde06f0\n" + " \u0000\u0000\u0000\u0000HFS+ Private Data; \n"; DataStructureAsserts.assertStructure(fs, expectedStructure); } @Test public void testDiskWithIncorrectCompressedFileOnFile() throws Exception { // This HFS+ image was created under Linux and it seems like the 'quote.txt' file has the UF_COMPRESSED // flag set on it incorrectly device = new FileDevice(FileSystemTestUtils.getTestFile("test/fs/hfsplus/wrong-compressed-flag.dd"), "r"); HfsPlusFileSystemType type = fss.getFileSystemType(HfsPlusFileSystemType.ID); HfsPlusFileSystem fs = type.create(device, true); String expectedStructure = "type: HFS+ vol:untitled total:2097152 free:1904640\n" + " /; \n" + " quote.txt; 165; 357d31c02f4b9161d14182b57769ef7a\n" + " steve-jobs-holding-iphone.jpg; 107795; 17baa8a85e36a790df697a68362c227d\n" + " \u0000\u0000\u0000\u0000HFS+ Private Data; \n"; DataStructureAsserts.assertStructure(fs, expectedStructure); } @Test public void testDiskCompressedHardlinks() throws Exception { device = new FileDevice(FileSystemTestUtils.getTestFile("test/fs/hfsplus/compressed-hardlinks.dd"), "r"); HfsPlusFileSystemType type = fss.getFileSystemType(HfsPlusFileSystemType.ID); HfsPlusFileSystem fs = type.create(device, true); String expectedStructure = "type: HFS+ vol:Will it work? total:40960000 free:39424000\n" + " /; \n" + " .fseventsd; \n" + " 0000000021b70ddc; 134; c4bd63b946eb863f50b189f2cb253c8c\n" + " 0000000021b70ddd; 72; 3bf09d08a28b8988cec8f4e3c166ee96\n" + " fseventsd-uuid; 36; 518c962c5c2852fd354b18650e198372\n" + " .HFS+ Private Directory Data\r; \n" + " .journal; 524288; b324e1aae290bc30297418b2c39cefa3\n" + " .journal_info_block; 4096; 469270564228a832e83d2ad16e6d8edc\n" + " .Trashes; \n" + " coffee-again.txt; 2573; 3a66504af332c4e6d9997e52cce98002\n" + " coffee.txt; 2573; 3a66504af332c4e6d9997e52cce98002\n" + " i-own-you.jpg; 24085; a1a91dfb9c2c0db6bec2f55b12a2e97f\n" + " \u0000\u0000\u0000\u0000HFS+ Private Data; \n" + " iNode24; 2573; 3a66504af332c4e6d9997e52cce98002\n"; DataStructureAsserts.assertStructure(fs, expectedStructure); } @Test public void testDiskWithLargeCompressedFile() throws Exception { device = new FileDevice(FileSystemTestUtils.getTestFile("test/fs/hfsplus/large-compressed.dmg"), "r"); HfsPlusFileSystemType type = fss.getFileSystemType(HfsPlusFileSystemType.ID); HfsPlusFileSystem fs = type.create(device, true); String expectedStructure = "type: HFS+ vol:large compressed file total:40960000 free:39411712\n" + " /; \n" + " .fseventsd; \n" + " 00000000220a3c77; 96; 52a732bebb5103be73aa89617d42a747\n" + " 00000000220a3c78; 72; 54d11397f6d87faf48a42c82aa2df57d\n" + " fseventsd-uuid; 36; 81d67b0f96aea5c2a1567a28dfa32fb7\n" + " .HFS+ Private Directory Data\r; \n" + " .journal; 524288; 43c347a01dd468234a75c8f5f126858e\n" + " .journal_info_block; 4096; 469270564228a832e83d2ad16e6d8edc\n" + " .Trashes; \n" + " large-useless-text.txt; 122818; e33db0ee58f4f5413c721b3d99311215\n" + " large-useless-text.txt:rsrc; 36771; fba9ba66e57abb9e691a6fb62fcd7c17\n" + " \u0000\u0000\u0000\u0000HFS+ Private Data; \n"; DataStructureAsserts.assertStructure(fs, expectedStructure); } @Test public void testDiskWithLzvnCompression() throws Exception { device = new FileDevice(FileSystemTestUtils.getTestFile("test/fs/hfsplus/rle-compression.dmg"), "r"); HfsPlusFileSystemType type = fss.getFileSystemType(HfsPlusFileSystemType.ID); HfsPlusFileSystem fs = type.create(device, true); String expectedStructure = "type: HFS+ vol:rle-compression total:40960000 free:39092224\n" + " /; \n" + " .fseventsd; \n" + " 000000000039ce79; 109; 151712afa50c634d4e796e06025b6779\n" + " 000000000039ce7a; 71; e659b5b401cb15e01fb9b5dd65b733ef\n" + " fseventsd-uuid; 36; c2c77c331f977e1b274da06abc7c778a\n" + " .HFS+ Private Directory Data\r; \n" + " .journal; 524288; b7106768943c0ae7b09e84b5bf75e62f\n" + " .journal_info_block; 4096; 469270564228a832e83d2ad16e6d8edc\n" + " .Trashes; \n" + " bash; 628640; f81cce1751382506604e244039bf4724\n" + " bash:rsrc; 352797; 699818770c06dc378bb2dd13ca159b33\n" + " \u0000\u0000\u0000\u0000HFS+ Private Data; \n"; DataStructureAsserts.assertStructure(fs, expectedStructure); } @Test public void testCreate() throws Exception { HfsPlusFileSystemType type = fss.getFileSystemType(HfsPlusFileSystemType.ID); HfsPlusFileSystem fs = new HfsPlusFileSystem(device, false, type); HFSPlusParams params = new HFSPlusParams(); params.setVolumeName("testdrive"); params.setBlockSize(HFSPlusParams.OPTIMAL_BLOCK_SIZE); params.setJournaled(false); params.setJournalSize(HFSPlusParams.DEFAULT_JOURNAL_SIZE); fs.create(params); SuperBlock vh = fs.getVolumeHeader(); Assert.assertEquals(SuperBlock.HFSPLUS_SUPER_MAGIC, vh.getMagic()); Assert.assertEquals(4096, vh.getBlockSize()); } @Test public void testRead() throws Exception { HfsPlusFileSystemType type = fss.getFileSystemType(HfsPlusFileSystemType.ID); HfsPlusFileSystem fs = new HfsPlusFileSystem(device, false, type); HFSPlusParams params = new HFSPlusParams(); params.setVolumeName("testdrive"); params.setBlockSize(HFSPlusParams.OPTIMAL_BLOCK_SIZE); params.setJournaled(false); params.setJournalSize(HFSPlusParams.DEFAULT_JOURNAL_SIZE); fs.create(params); fs.close(); fs = new HfsPlusFileSystemType().create(device, false); fs.read(); fs.createRootEntry(); FSDirectory root = fs.getRootEntry().getDirectory(); Assert.assertFalse("Must be empty", root.iterator().hasNext()); root.addDirectory("test"); fs.flush(); fs.close(); fs = new HfsPlusFileSystemType().create(device, false); fs.read(); Assert.assertEquals(1, fs.getVolumeHeader().getFolderCount()); fs.createRootEntry(); root = fs.getRootEntry().getDirectory(); Assert.assertTrue("Must contains one directory", root.iterator().hasNext()); } private Device createTestDisk(boolean formatted) throws IOException { File file = TestUtils.makeTempFile("hfsDevice", "10M"); Device device = new FileDevice(file, "rw"); return device; } }