Package org.jnode.fs.fat

Source Code of org.jnode.fs.fat.AbstractDirectory$DirIterator

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

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Vector;
import org.jnode.fs.FSDirectory;
import org.jnode.fs.FSDirectoryId;
import org.jnode.fs.FSEntry;
import org.jnode.fs.ReadOnlyFileSystemException;

/**
* @author epr
*/
public abstract class AbstractDirectory extends FatObject implements FSDirectory, FSDirectoryId {

    protected Vector<FatBasicDirEntry> entries = new Vector<FatBasicDirEntry>();
    private boolean _dirty;
    protected FatFile file;

    // for root
    protected AbstractDirectory(FatFileSystem fs, int nrEntries) {
        super(fs);
        entries.setSize(nrEntries);
        _dirty = false;
    }

    protected AbstractDirectory(FatFileSystem fs, int nrEntries, FatFile file) {
        this(fs, nrEntries);
        this.file = file;
    }

    protected AbstractDirectory(FatFileSystem fs, FatFile myFile) {
        this(fs, (int) myFile.getLength() / FatConstants.DIR_ENTRY_SIZE, myFile);
    }

    @Override
    public String getDirectoryId() {
        return Long.toString(file.getStartCluster());
    }

    /**
     * Gets an iterator to iterate over all entries. The iterated objects are
     * all instance DirEntry.
     *
     * @return Iterator
     */
    public Iterator<FSEntry> iterator() {
        return new DirIterator();
    }

    /**
     * Add a directory entry.
     *
     * @param nameExt
     * @throws IOException
     */
    protected synchronized FatDirEntry addFatFile(String nameExt) throws IOException {
        if (getFileSystem().isReadOnly()) {
            throw new ReadOnlyFileSystemException("addFile in readonly filesystem");
        }

        if (getFatEntry(nameExt) != null) {
            throw new IOException("File already exists" + nameExt);
        }
        final FatDirEntry newEntry = new FatDirEntry(this, splitName(nameExt), splitExt(nameExt));
        int size = entries.size();
        for (int i = 0; i < size; i++) {
            FatBasicDirEntry e = entries.get(i);
            if (e == null) {
                entries.set(i, newEntry);
                setDirty();
                flush();
                return newEntry;
            }
        }
        int newSize = size + 512 / FatConstants.DIR_ENTRY_SIZE;
        if (canChangeSize(newSize)) {
            entries.ensureCapacity(newSize);
            setDirty();
            flush();
            return newEntry;
        }
        throw new IOException("Directory is full");
    }

    /**
     * Add a new file with a given name to this directory.
     *
     * @param name
     * @throws IOException
     */
    public FSEntry addFile(String name) throws IOException {
        return addFatFile(name);
    }

    /**
     * Add a directory entry of the type directory.
     *
     * @param nameExt
     * @param parentCluster
     * @throws IOException
     */
    protected synchronized FatDirEntry addFatDirectory(String nameExt, long parentCluster) throws IOException {
        final FatDirEntry entry = addFatFile(nameExt);
        final int clusterSize = getFatFileSystem().getClusterSize();
        entry.setFlags(FatConstants.F_DIRECTORY);
        final FatFile file = entry.getFatFile();
        file.setLength(clusterSize);

        //TODO optimize it also to use ByteBuffer at lower level       
        //final byte[] buf = new byte[clusterSize];
        final ByteBuffer buf = ByteBuffer.allocate(clusterSize);

        // Clean the contents of this cluster to avoid reading strange data
        // in the directory.
        //file.write(0, buf, 0, buf.length);
        file.write(0, buf);

        file.getDirectory().initialize(file.getStartCluster(), parentCluster);
        flush();
        return entry;
    }

    /**
     * Add a new (sub-)directory with a given name to this directory.
     *
     * @param name
     * @throws IOException
     */
    public FSEntry addDirectory(String name) throws IOException {
        if (getFileSystem().isReadOnly()) {
            throw new ReadOnlyFileSystemException("addDirectory in readonly filesystem");
        }

        final long parentCluster;
        if (file == null) {
            parentCluster = 0;
        } else {
            parentCluster = file.getStartCluster();
        }
        return addFatDirectory(name, parentCluster);
    }

    /**
     * Gets the number of directory entries in this directory
     *
     * @return int
     */
    public int getSize() {
        return entries.size();
    }

    /**
     * Search for an entry with a given name.ext
     *
     * @param nameExt
     * @return FatDirEntry null == not found
     */
    protected FatDirEntry getFatEntry(String nameExt) {

        final String name = splitName(nameExt);
        final String ext = splitExt(nameExt);
        int size = entries.size();
        for (int i = 0; i < size; i++) {
            final FatBasicDirEntry entry = entries.get(i);
            if (entry != null && entry instanceof FatDirEntry) {
                FatDirEntry fde = (FatDirEntry) entry;
                if (name.equalsIgnoreCase(fde.getNameOnly()) && ext.equalsIgnoreCase(fde.getExt())) {
                    return fde;
                }
            }
        }
        return null;
    }

    /**
     * Gets the entry with the given name.
     *
     * @param name
     * @throws IOException
     */
    public FSEntry getEntry(String name) throws IOException {
        final FatDirEntry entry = getFatEntry(name);
        if (entry == null) {
            throw new FileNotFoundException(name);
        } else {
            return entry;
        }
    }

    /**
     * Remove a file or directory with a given name
     *
     * @param nameExt
     */
    public synchronized void remove(String nameExt) throws IOException {
        FatDirEntry entry = getFatEntry(nameExt);
        if (entry == null) {
            throw new FileNotFoundException(nameExt);
        }
        for (int i = 0; i < entries.size(); i++) {
            if (entries.get(i) == entry) {
                entries.set(i, null);
                setDirty();
                flush();
                return;
            }
        }
    }

    /**
     * Print the contents of this directory to the given writer. Used for
     * debugging purposes.
     *
     * @param out
     */
    public void printTo(PrintWriter out) {
        int freeCount = 0;
        int size = entries.size();
        for (int i = 0; i < size; i++) {
            FatBasicDirEntry entry = entries.get(i);
            if (entry != null) {
                out.println("0x" + Integer.toHexString(i) + " " + entries.get(i));
            } else {
                freeCount++;
            }
        }
        out.println("Unused entries " + freeCount);
    }

    class DirIterator implements Iterator<FSEntry> {

        private int offset = 0;

        /**
         * @see java.util.Iterator#hasNext()
         */
        public boolean hasNext() {
            int size = entries.size();
            while (offset < size) {
                FatBasicDirEntry e = entries.get(offset);
                if ((e != null) && e instanceof FatDirEntry && !((FatDirEntry) e).isDeleted()) {
                    return true;
                } else {
                    offset++;
                }
            }
            return false;
        }

        /**
         * @see java.util.Iterator#next()
         */
        public FSEntry next() {
            int size = entries.size();
            while (offset < size) {
                FatBasicDirEntry e = entries.get(offset);
                if ((e != null) && (e instanceof FatDirEntry) && !((FatDirEntry) e).isDeleted()) {
                    offset++;
                    return (FSEntry) e;
                } else {
                    offset++;
                }
            }
            throw new NoSuchElementException();
        }

        /**
         * @see java.util.Iterator#remove()
         */
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }

    /**
     * Returns the dirty.
     *
     * @return boolean
     */
    public boolean isDirty() {
        if (_dirty) {
            return true;
        }
        int size = entries.size();
        for (int i = 0; i < size; i++) {
            FatBasicDirEntry entry = entries.get(i);
            if ((entry != null) && (entry instanceof FatDirEntry)) {
                if (((FatDirEntry) entry).isDirty()) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Mark this directory as dirty.
     */
    protected final void setDirty() {
        this._dirty = true;
    }

    /**
     * Mark this directory as not dirty.
     */
    protected final void resetDirty() {
        this._dirty = false;
    }

    /**
     * Can this directory change size of <code>newSize</code> directory
     * entries?
     *
     * @param newSize
     * @return boolean
     */
    protected abstract boolean canChangeSize(int newSize);

    protected String splitName(String nameExt) {
        int i = nameExt.indexOf('.');
        if (i < 0) {
            return nameExt;
        } else {
            return nameExt.substring(0, i);
        }
    }

    protected String splitExt(String nameExt) {
        int i = nameExt.indexOf('.');
        if (i < 0) {
            return "";
        } else {
            return nameExt.substring(i + 1);
        }
    }

    /**
     * Sets the first two entries '.' and '..' in the directory
     *
     * @param parentCluster
     */
    protected void initialize(long myCluster, long parentCluster) {
        FatDirEntry e = new FatDirEntry(this, ".", "");
        entries.set(0, e);
        e.setFlags(FatConstants.F_DIRECTORY);
        e.setStartCluster((int) myCluster);
        e = new FatDirEntry(this, "..", "");
        entries.set(1, e);
        e.setFlags(FatConstants.F_DIRECTORY);
        e.setStartCluster((int) parentCluster);
    }

    /**
     * Flush the contents of this directory to the persistent storage
     */
    public abstract void flush() throws IOException;

    /**
     * Read the contents of this directory from the given byte array
     *
     * @param src
     */
    protected synchronized void read(byte[] src) {
        int size = entries.size();
        for (int i = 0; i < size; i++) {
            int index = i * FatConstants.DIR_ENTRY_SIZE;
            if (src[index] == 0) {
                entries.set(i, null);
            } else {
                FatBasicDirEntry entry = FatDirEntry.fatDirEntryFactory(this, src, index);
                entries.set(i, entry);
            }
        }
    }

    /**
     * Write the contents of this directory to the given device at the given
     * offset.
     *
     * @param dest
     */
    protected synchronized void write(byte[] dest) {
        int size = entries.size();
        byte[] empty = new byte[FatConstants.DIR_ENTRY_SIZE];
        for (int i = 0; i < size; i++) {
            FatBasicDirEntry entry = entries.get(i);
            if (entry != null) {
                entry.write(dest, i * FatConstants.DIR_ENTRY_SIZE);
            } else {
                System.arraycopy(empty, 0, dest, i * FatConstants.DIR_ENTRY_SIZE, empty.length);
            }
        }
    }

}
TOP

Related Classes of org.jnode.fs.fat.AbstractDirectory$DirIterator

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.