/* * $Id$ * * Copyright (C) 2003-2015 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.fs.ntfs; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * An entry in the USN journal file ($Extend\$UsnJrnl). * * @author Luke Quinane */ public class UsnJournalEntry extends NTFSStructure { /** * Creates a new journal entry at the given offset. * * @param buffer the buffer containing the journal data. * @param offset the offset in the buffer to read from. */ public UsnJournalEntry(byte[] buffer, int offset) { super(buffer, offset); } /** * Gets the size of this entry. * * @return the size. */ public long getSize() { return getUInt32(0x0); } /** * Gets the major version number. * * @return the major version number. */ public int getMajorVersion() { return getUInt16(0x4); } /** * Gets the minor version number. * * @return the minor version number. */ public int getMinorVersion() { return getUInt16(0x6); } /** * Gets the MFT reference. * * @return the MFT reference. */ public long getMftReference() { return getInt48(0x8); } /** * Gets the parent MFT reference. * * @return the parent MFT reference. */ public long getParentMtfReference() { return getInt48(0x10); } /** * Gets the timestamp for this entry. * * @return the timestamp. */ public long getTimestamp() { return NTFSUTIL.filetimeToMillis(getInt64(0x20)); } /** * Gets the reason for the entry. * * @return the reason. */ public long getReason() { return getUInt32(0x28); } /** * Gets the source info. * * @return the source info. */ public int getSourceInfo() { return getInt32(0x2b); } public int getSecurityId() { return getInt32(0x30); } public int getFileAttributes() { return getInt32(0x34); } /** * Gets the size of the file name stored in this entry. * * @return the size of the file name text. */ public int getFileNameSize() { return getInt16(0x38); } /** * Gets the file name stored in this entry. * * @return the file name. */ public String getFileName() { byte[] buffer = new byte[getFileNameSize()]; getData(0x3c, buffer, 0, buffer.length); try { return new String(buffer, "UTF-16LE"); } catch (UnsupportedEncodingException e) { throw new IllegalStateException("UTF-16LE charset missing from JRE", e); } } @Override public String toString() { return String.format("MFT: 0x%x parent MFT: 0x%x, %s version: %d.%d, size: %d source: 0x%x security: 0x%x " + "attributes: %s time: %s, name:%s", getMftReference(), getParentMtfReference(), Reason.lookupReasons(getReason()), getMajorVersion(), getMinorVersion(), getSize(), getSourceInfo(), getSecurityId(), FileAttribute.lookupAttributes(getFileAttributes()), new Date(getTimestamp()), getFileName()); } /** * File attribute constants */ public static class FileAttribute { /** * The lookup map for file attributes. */ private static final Map<Long, String> attributeMap = new LinkedHashMap<Long, String>(); /** * Registers a value in the map. * * @param value the value to register. * @param name the name. * @return the value. */ private static long register(long value, String name) { attributeMap.put(value, name); return value; } /** * Looks up the attributes for the given value. * * @param value the value to lookup. * @return the attributes or "unknown-xXYZ" if the value is not known. */ public static List<String> lookupAttributes(long value) { List<String> reasons = new ArrayList<String>(); for (Map.Entry<Long, String> entry : attributeMap.entrySet()) { if ((value & entry.getKey()) != 0) { reasons.add(entry.getValue()); value -= entry.getKey(); } } if (value != 0) { reasons.add("unknown-x" + Long.toHexString(value)); } return reasons; } public static final long READONLY = register(0x1, "read-only"); public static final long HIDDEN = register(0x2, "hidden"); public static final long SYSTEM = register(0x4, "system"); public static final long DIRECTORY = register(0x10, "directory"); public static final long ARCHIVE = register(0x20, "archive"); public static final long DEVICE = register(0x40, "device"); public static final long NORMAL = register(0x80, "normal"); public static final long TEMPORARY = register(0x100, "temporary"); public static final long SPARSE = register(0x200, "sparse"); public static final long REPARSE_POINT = register(0x400, "reparse-point"); public static final long COMPRESSED = register(0x800, "compressed"); public static final long OFFLINE = register(0x1000, "offline"); public static final long NOT_INDEXED = register(0x2000, "not-indexed"); public static final long VIRTUAL = register(0x10000, "virtual"); public static final long ENCRYPTED = register(0x3FFF, "encrypted"); } /** * Reason constants */ public static class Reason { /** * The lookup map for reasons. */ private static final Map<Long, String> reasonMap = new HashMap<Long, String>(); /** * Registers a value in the map. * * @param value the value to register. * @param name the name. * @return the value. */ private static long register(long value, String name) { reasonMap.put(value, name); return value; } /** * Looks up the reasons for the given value. * * @param value the value to lookup. * @return the reasons or "unknown-xXYZ" if the value is not known. */ public static List<String> lookupReasons(long value) { List<String> reasons = new ArrayList<String>(); for (Map.Entry<Long, String> entry : reasonMap.entrySet()) { if ((value & entry.getKey()) != 0) { reasons.add(entry.getValue()); value -= entry.getKey(); } } if (value != 0) { reasons.add("unknown-x" + Long.toHexString(value)); } return reasons; } /** * Data in one or more data streams was overwritten. */ public static final long DATA_WRITE = register(0x1, "data-write"); /** * File or directory added. */ public static final long FS_ENTRY_ADDED = register(0x2, "fs-entry-added"); /** * File or directory truncated. */ public static final long FS_ENTRY_TRUNCATED = register(0x4, "fs-entry-truncated"); /** * Data in one or more data streams was overwritten. Alternate value. */ public static final long DATA_WRITE_ALT = register(0x10, "data-write-alt"); /** * Data in one or more data streams was appended to. */ public static final long DATA_APPEND = register(0x20, "data-append"); /** * Data in one or more data streams was truncated. */ public static final long DATA_TRUNCATED = register(0x40, "data-truncated"); /** * File or directory created. */ public static final long FS_ENTRY_CREATED = register(0x100, "fs-entry-created"); /** * File or directory deleted. */ public static final long FS_ENTRY_DELETED = register(0x200, "fs-entry-deleted"); /** * User changed a file or directory's extended attributes. */ public static final long FS_ENTRY_EX_ATTR_CHANGED = register(0x400, "fs-entry-ex-attr-changed"); /** * File or directory access changes. */ public static final long FS_ENTRY_ACCESS_CHANGED = register(0x800, "fs-entry-access-changed"); /** * File or directory renamed. USN journal entry has the old name. */ public static final long FS_ENTRY_RENAMED_OLD = register(0x1000, "fs-entry-rename-old"); /** * File or directory renamed. USN journal entry has the new name. */ public static final long FS_ENTRY_RENAMED_NEW = register(0x2000, "fs-entry-rename-new"); /** * User changed whether the contents of a file was indexed or not. */ public static final long FS_ENTRY_INDEXING_CHANGED = register(0x4000, "fs-entry-indexing-changed"); /** * User changed a file or directories attributes or timestamps. */ public static final long FS_ENTRY_ATTR_CHANGED = register(0x8000, "fs-entry-attr-changed"); /** * A hard link was removed from a directory. */ public static final long HARD_LINK_REMOVED = register(0x10000, "hard-link-removed"); /** * User changed whether a file or directory is compressed. */ public static final long FS_ENTRY_COMPRESSION_CHANGED = register(0x20000, "fs-entry-compression-changed"); /** * User changed whether a file or directory is encrypted. */ public static final long FS_ENTRY_ENCRYPTION_CHANGED = register(0x40000, "fs-entry-encryption-changed"); /** * The user changed an object identifier for a file or directory. */ public static final long FS_ENTRY_OBJ_IDENTIFIER_CHANGED = register(0x80000, "fs-entry-obj-identifier-changed"); /** * A reparse point was altered, added or deleted in the directory. */ public static final long REPARSE_POINT_ALTERED = register(0x100000, "reparse-point-altered"); /** * A data stream for a file has been added, removed or renamed. */ public static final long DATA_STREAM_ALTERED = register(0x200000, "data-stream-altered"); /** * The file or directory was closed. */ public static final long FS_ENTRY_CLOSED = register(0x80000000L, "fs-entry-closed"); } /** * Source info constants */ public static class SourceInfo { /** * The file or directory was changed by the operating system. */ public static final int CHANGE_FROM_OS = 0x1; /** * Private stream data was added but the modifications did not change application data. */ public static final int CHANGE_FROM_AUX = 0x2; /** * The change was related to the replication service. */ public static final int REPLICATION = 0x4; } }