Package org.jnode.fs.hfsplus

Source Code of org.jnode.fs.hfsplus.HfsPlusDirectory

/*
* $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.fs.hfsplus;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import org.jnode.fs.FSDirectory;
import org.jnode.fs.FSDirectoryId;
import org.jnode.fs.FSEntry;
import org.jnode.fs.FileSystem;
import org.jnode.fs.ReadOnlyFileSystemException;
import org.jnode.fs.hfsplus.catalog.Catalog;
import org.jnode.fs.hfsplus.catalog.CatalogFile;
import org.jnode.fs.hfsplus.catalog.CatalogFolder;
import org.jnode.fs.hfsplus.catalog.CatalogKey;
import org.jnode.fs.hfsplus.catalog.CatalogLeafNode;
import org.jnode.fs.hfsplus.catalog.CatalogNodeId;
import org.jnode.fs.hfsplus.tree.LeafRecord;
import org.jnode.fs.spi.FSEntryTable;

public class HfsPlusDirectory implements FSDirectory, FSDirectoryId {

    private static final Logger log = Logger.getLogger(HfsPlusDirectory.class);

    /**
     * The directory entry
     */
    private HfsPlusEntry entry;

    /**
     * Table of entries of our parent
     */
    private FSEntryTable entries;

    /**
     * The catalog directory record
     */
    private CatalogFolder folder;

    public HfsPlusDirectory(HfsPlusEntry entry) {
        this.entry = entry;
        this.folder = new CatalogFolder(entry.getData());
        this.entries = FSEntryTable.EMPTY_TABLE;
    }

    @Override
    public FSEntry addDirectory(String name) throws IOException {
        if (getFileSystem().isReadOnly()) {
            throw new ReadOnlyFileSystemException();
        }

        if (getEntry(name) != null) {
            throw new IOException("File or Directory already exists : " + name);
        }
        FSEntry newEntry = createDirectoryEntry(name);
        setFreeEntry(newEntry);
        log.debug("Directory " + name + " added");
        return newEntry;
    }

    @Override
    public FSEntry addFile(String name) throws IOException {
        if (getFileSystem().isReadOnly()) {
            throw new ReadOnlyFileSystemException();
        }
        if (getEntry(name) != null) {
            throw new IOException("File or directory already exists: " + name);
        }
        FSEntry newEntry = createFileEntry(name);
        setFreeEntry(newEntry);

        return newEntry;
    }

    private FSEntry createFileEntry(final String name) throws IOException {
        //TODO implements this method.
        /*
         * if (fs.isReadOnly()) { throw new ReadOnlyFileSystemException(); }
         * Catalog catalog = fs.getCatalog(); SuperBlock volumeHeader =
         * ((HfsPlusFileSystem) getFileSystem()).getVolumeHeader(); LeafRecord
         * fileRecord = catalog.createNode(name, this.folder .getFolderId(), new
         * CatalogNodeId(volumeHeader.getNextCatalogId()),
         * CatalogFile.RECORD_TYPE_FILE);
         *
         * HFSPlusEntry newEntry = new HFSPlusFile(fs, this, name,
         * folderRecord); newEntry.setDirty();
         * volumeHeader.setFileCount(volumeHeader.getFileCount() + 1);
         * log.debug("New volume header :\n" + volumeHeader.toString());
         */

        return null;
    }

    @Override
    public void flush() throws IOException {
        if (getFileSystem().isReadOnly()) {
            throw new ReadOnlyFileSystemException();
        }
        boolean flushEntries = isEntriesLoaded() && entries.isDirty();
        if (entry.isDirty() || flushEntries) {
            writeEntries(entries);
            // entries.resetDirty();
            entry.resetDirty();
        }
        log.debug("Directory flushed.");
    }

    @Override
    public FSEntry getEntry(String name) throws IOException {
        checkEntriesLoaded();
        return entries.get(name);
    }

    @Override
    public FSEntry getEntryById(String id) throws IOException {
        checkEntriesLoaded();
        return entries.getById(id);
    }

    @Override
    public String getDirectoryId() {
        return Long.toString(folder.getFolderId().getId());
    }

    @Override
    public Iterator<? extends FSEntry> iterator() throws IOException {
        checkEntriesLoaded();
        return entries.iterator();
    }

    public int rename(String oldName, String newName) {
        return entries.rename(oldName, newName);
    }

    @Override
    public void remove(String name) throws IOException {
        if (getFileSystem().isReadOnly()) {
            throw new ReadOnlyFileSystemException();
        }
        if (entries.remove(name) >= 0) {
            entry.setDirty();
            flush();
        } else {
            throw new FileNotFoundException(name);
        }
    }

    // Helper methods

    /**
     * BE CAREFULL : don't call this method from the constructor of this class
     * because it call the method readEntries of the child classes that are not
     * yet initialized (constructed).
     */
    protected final void checkEntriesLoaded() {
        if (!isEntriesLoaded()) {
            log.debug("checkEntriesLoaded : loading");
            try {
                if (entry.getAccessRights().canRead()) {
                    entries = readEntries();
                    log.debug("Load " + entries.size() + " entrie(s).");
                } else {
                    // the next time, we will call checkEntriesLoaded()
                    // we will retry to load entries
                    entries = FSEntryTable.EMPTY_TABLE;
                    log.debug("checkEntriesLoaded : can't read, using EMPTY_TABLE");
                }
                entry.resetDirty();
            } catch (IOException e) {
                log.fatal("unable to read directory entries", e);
                // the next time, we will call checkEntriesLoaded()
                // we will retry to load entries
                entries = FSEntryTable.EMPTY_TABLE;
            }
        }
    }

    /**
     * Have we already loaded our entries from device ?
     *
     * @return if the entries are already loaded from the device
     */
    private boolean isEntriesLoaded() {
        return (entries != FSEntryTable.EMPTY_TABLE);
    }

    /**
     * @return read all entries link to the current directory in the file system.
     * @throws IOException
     */
    private FSEntryTable readEntries() throws IOException {
        List<FSEntry> pathList = new LinkedList<FSEntry>();
        HfsPlusFileSystem fs = (HfsPlusFileSystem) getFileSystem();
        if (fs.getVolumeHeader().getFolderCount() > 0) {
            LeafRecord[] records = fs.getCatalog().getRecords(folder.getFolderId());
            for (LeafRecord rec : records) {
                if (rec.getType() == CatalogFolder.RECORD_TYPE_FOLDER ||
                    rec.getType() == CatalogFile.RECORD_TYPE_FILE) {
                    String name = ((CatalogKey) rec.getKey()).getNodeName().getUnicodeString();
                    HfsPlusEntry e = new HfsPlusEntry(fs, this, name, rec);
                    pathList.add(e);
                }
            }
        }
        return new FSEntryTable(((HfsPlusFileSystem) getFileSystem()), pathList);
    }

    private void writeEntries(final FSEntryTable entries) throws IOException {
        // TODO Auto-generated method stub
    }

    /**
     * @param name The name of the entry.
     * @return Return the newly created entry.
     * @throws IOException if problem occurs during catalog node creation or if system is read-only.
     */
    private FSEntry createDirectoryEntry(final String name) throws IOException {
        if (getFileSystem().isReadOnly()) {
            throw new ReadOnlyFileSystemException();
        }
        Catalog catalog = ((HfsPlusFileSystem) getFileSystem()).getCatalog();
        SuperBlock volumeHeader = ((HfsPlusFileSystem) getFileSystem()).getVolumeHeader();
        CatalogLeafNode node =
            catalog.createNode(name, this.folder.getFolderId(),
                new CatalogNodeId(volumeHeader.getNextCatalogId()),
                CatalogFolder.RECORD_TYPE_FOLDER_THREAD);
        folder.incrementValence();

        HfsPlusEntry newEntry =
            new HfsPlusEntry((HfsPlusFileSystem) getFileSystem(), this, name, node.getNodeRecord(0));
        newEntry.setDirty();
        volumeHeader.incrementFolderCount();
        log.debug("New volume header :\n" + volumeHeader.toString());
        volumeHeader.update();

        return newEntry;
    }

    /**
     * Find a free entry and set it with the given entry
     *
     * @param newEntry
     * @throws IOException
     */
    private void setFreeEntry(FSEntry newEntry) throws IOException {
        checkEntriesLoaded();
        if (entries.setFreeEntry(newEntry) >= 0) {
            log.debug("setFreeEntry: free entry found !");
            entry.setDirty();
            flush();
        }
    }

    @Override
    public boolean isValid() {
        return entry.isValid();
    }

    @Override
    public FileSystem<?> getFileSystem() {
        return entry.getFileSystem();
    }
}
TOP

Related Classes of org.jnode.fs.hfsplus.HfsPlusDirectory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.