From 0f1f50d9c8fd9979eba6b88f1c6408bd15799403 Mon Sep 17 00:00:00 2001 From: nvt-se Date: Tue, 4 Aug 2009 10:36:53 +0000 Subject: [PATCH] Add a managment tool for Coffee file system images. --- tools/coffee-manager/LICENSE | 26 ++ tools/coffee-manager/MANIFEST.MF | 2 + tools/coffee-manager/README.TXT | 24 ++ tools/coffee-manager/build.sh | 2 + .../se/sics/coffee/CoffeeConfiguration.java | 83 ++++++ .../se/sics/coffee/CoffeeFS.java | 191 +++++++++++++ .../se/sics/coffee/CoffeeFile.java | 131 +++++++++ .../se/sics/coffee/CoffeeHeader.java | 259 ++++++++++++++++++ .../se/sics/coffee/CoffeeImage.java | 46 ++++ .../se/sics/coffee/CoffeeImageFile.java | 86 ++++++ .../se/sics/coffee/CoffeeManager.java | 200 ++++++++++++++ tools/coffee-manager/sky.properties | 8 + 12 files changed, 1058 insertions(+) create mode 100644 tools/coffee-manager/LICENSE create mode 100644 tools/coffee-manager/MANIFEST.MF create mode 100644 tools/coffee-manager/README.TXT create mode 100755 tools/coffee-manager/build.sh create mode 100644 tools/coffee-manager/se/sics/coffee/CoffeeConfiguration.java create mode 100644 tools/coffee-manager/se/sics/coffee/CoffeeFS.java create mode 100644 tools/coffee-manager/se/sics/coffee/CoffeeFile.java create mode 100644 tools/coffee-manager/se/sics/coffee/CoffeeHeader.java create mode 100644 tools/coffee-manager/se/sics/coffee/CoffeeImage.java create mode 100644 tools/coffee-manager/se/sics/coffee/CoffeeImageFile.java create mode 100644 tools/coffee-manager/se/sics/coffee/CoffeeManager.java create mode 100644 tools/coffee-manager/sky.properties diff --git a/tools/coffee-manager/LICENSE b/tools/coffee-manager/LICENSE new file mode 100644 index 000000000..0112b2155 --- /dev/null +++ b/tools/coffee-manager/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2009, Swedish Institute of Computer Science +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the Institute nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/tools/coffee-manager/MANIFEST.MF b/tools/coffee-manager/MANIFEST.MF new file mode 100644 index 000000000..85ad7042b --- /dev/null +++ b/tools/coffee-manager/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +Main-Class: se.sics.coffee.CoffeeManager diff --git a/tools/coffee-manager/README.TXT b/tools/coffee-manager/README.TXT new file mode 100644 index 000000000..0af184596 --- /dev/null +++ b/tools/coffee-manager/README.TXT @@ -0,0 +1,24 @@ +se.sics.coffee is a library for the Coffee File System. It is able to +generate file system images and to extract information from existing +images. + +Building: + +./build.sh + +Usage: + +java -jar coffee.jar [-i|e ] [-r ] + [-l|s] + +Options: + +-i Inserts a new file into the file system. +-e Extracts a file from the file system and saves it locally. +-r Removes a file from the file system. +-l Lists all files. +-s Prints file system statistics. + +Author: + +Nicols Tsiftes diff --git a/tools/coffee-manager/build.sh b/tools/coffee-manager/build.sh new file mode 100755 index 000000000..8ffd15efc --- /dev/null +++ b/tools/coffee-manager/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +(cd se/sics/coffee && javac *.java) && jar cvfm coffee.jar MANIFEST.MF se/ diff --git a/tools/coffee-manager/se/sics/coffee/CoffeeConfiguration.java b/tools/coffee-manager/se/sics/coffee/CoffeeConfiguration.java new file mode 100644 index 000000000..72dce6ab0 --- /dev/null +++ b/tools/coffee-manager/se/sics/coffee/CoffeeConfiguration.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: CoffeeConfiguration.java,v 1.1 2009/08/04 10:36:53 nvt-se Exp $ + * + * @author Nicolas Tsiftes + * + */ + +package se.sics.coffee; + +import java.io.*; +import java.util.Properties; + +public class CoffeeConfiguration { + public static final int FD_SET_SIZE = 256; + public static final int MAX_OPEN_FILES = 256; + public static final int LOG_TABLE_LIMIT = 256; + public static final int DIR_CACHE_ENTRIES = 256; + public static final int NAME_LENGTH = 16; + public static int fsSize, sectorSize, pageSize; + public static int startOffset, pageTypeSize; + public static int defaultFileSize, defaultLogSize; + public static int pagesPerSector; + public static boolean useMicroLogs; + + public CoffeeConfiguration(String filename) + throws CoffeeException, IOException { + String[] validParameters = {"use_micro_logs", "fs_size", + "page_size", "sector_size", + "start_offset", "default_file_size", + "default_log_size", "page_type_size"}; + String property; + Properties prop = new Properties(); + FileInputStream fstream = + new FileInputStream(filename); + + prop.load(fstream); + for(int i = 0; i < validParameters.length; i++) { + if(prop.getProperty(validParameters[i]) == null) { + throw new CoffeeException("missing the parameter \"" + validParameters[i] + "\" in the configuration file " + filename); + } + } + + useMicroLogs = new Boolean(prop.getProperty("use_micro_logs")).booleanValue(); + fsSize = new Integer(prop.getProperty("fs_size")).intValue(); + sectorSize = new Integer(prop.getProperty("sector_size")).intValue(); + pageSize = new Integer(prop.getProperty("page_size")).intValue(); + defaultFileSize = new Integer(prop.getProperty("default_file_size")).intValue(); + defaultLogSize = new Integer(prop.getProperty("default_log_size")).intValue(); + startOffset = new Integer(prop.getProperty("start_offset")).intValue(); + pageTypeSize = new Integer(prop.getProperty("page_type_size")).intValue(); + + pagesPerSector = sectorSize / pageSize; + } +} diff --git a/tools/coffee-manager/se/sics/coffee/CoffeeFS.java b/tools/coffee-manager/se/sics/coffee/CoffeeFS.java new file mode 100644 index 000000000..05ec06dac --- /dev/null +++ b/tools/coffee-manager/se/sics/coffee/CoffeeFS.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: CoffeeFS.java,v 1.1 2009/08/04 10:36:53 nvt-se Exp $ + * + * @author Nicolas Tsiftes + * + */ + +package se.sics.coffee; + +import java.io.*; +import java.util.Map; +import java.util.TreeMap; + +class CoffeeException extends RuntimeException { + public CoffeeException(String message) { + super("Coffee error: " + message); + } +} + +class CoffeeFileException extends RuntimeException { + public CoffeeFileException(String message) { + super("Coffee file error: " + message); + } +} + +public class CoffeeFS { + private CoffeeImage image; + private CoffeeConfiguration conf; + private int currentPage; + private Map files; + private static final int INVALID_PAGE = -1; + + public CoffeeFS(CoffeeImage image) throws IOException { + this.image = image; + conf = image.getConfiguration(); + currentPage = 0; + files = new TreeMap(); + + while(currentPage < (conf.fsSize / conf.pageSize)) { + CoffeeHeader header = readHeader(currentPage); + if(header.isActive()) { + CoffeeFile file = new CoffeeFile(this, header); + files.put(file.getName(), file); + } + currentPage = nextFile(header, currentPage); + } + } + + private int pageCount(long size) { + int headerSize = conf.NAME_LENGTH + conf.pageTypeSize * 2 + 6; + return (int)(size + headerSize + conf.pageSize - 1) / conf.pageSize; + } + + private int findFreeExtent(int pages) throws IOException { + CoffeeHeader header; + int currentPage = 0; + int start = INVALID_PAGE; + + while(currentPage < (conf.fsSize / conf.pageSize)) { + header = readHeader(currentPage); + if(header.isFree()) { + if(start == INVALID_PAGE) { + start = currentPage; + } + currentPage = nextFile(header, currentPage); + if(start + pages <= currentPage) { + return start; + } + } else { + start = INVALID_PAGE; + currentPage = nextFile(header, currentPage); + } + } + return INVALID_PAGE; + } + + public CoffeeImage getImage() { + return image; + } + + public CoffeeConfiguration getConfiguration() { + return conf; + } + + private CoffeeHeader readHeader(int page) throws IOException { + byte[] bytes = new byte[conf.NAME_LENGTH + conf.pageTypeSize * 2 + 6]; + int index = 0; + + image.read(bytes, bytes.length, page * conf.pageSize); + CoffeeHeader header = new CoffeeHeader(this, page, bytes); + + return header; + } + + private void writeHeader(CoffeeHeader header) throws IOException { + byte[] bytes = header.toRawHeader(); + + image.write(bytes, bytes.length, header.getPage() * conf.pageSize); + } + + private int nextFile(CoffeeHeader header, int page) { + if(header.isFree()) { + return page + conf.pagesPerSector & ~(conf.pagesPerSector - 1); + } else if(header.isIsolated()) { + return page + 1; + } + + return page + header.maxPages; + } + + public final Map getFiles() { + return files; + } + + public CoffeeFile insertFile(String filename) throws IOException { + CoffeeFile coffeeFile; + try { + File file = new File(filename); + FileInputStream input = new FileInputStream(file); +System.out.println("file length: " + file.length() + ", page count: " + pageCount(file.length())); + int allocatePages = pageCount(file.length()); + int start = findFreeExtent(allocatePages); + if(start == INVALID_PAGE) { + return null; + } + CoffeeHeader header = new CoffeeHeader(this, start); + header.setName(filename); + header.setReservedSize(allocatePages); + header.allocate(); + coffeeFile = new CoffeeFile(this, header); + writeHeader(header); + coffeeFile.insertContents(input); + input.close(); + return coffeeFile; + } catch (FileNotFoundException e) { + } + return null; + } + + public void removeFile(String filename) + throws CoffeeFileException, IOException { + CoffeeFile file = files.get(filename); + if(file == null) { + throw new CoffeeFileException("Coffee: attempt to remove inexistent file"); + } + + file.remove(); + writeHeader(file.getHeader()); + files.remove(file.getName()); + } + + public boolean extractFile(String inputFile, String outputFile) throws IOException { + CoffeeFile file = files.get(inputFile); + + if(file == null) { + return false; + } + + file.saveContents(outputFile); + return true; + } +} diff --git a/tools/coffee-manager/se/sics/coffee/CoffeeFile.java b/tools/coffee-manager/se/sics/coffee/CoffeeFile.java new file mode 100644 index 000000000..d94a355ee --- /dev/null +++ b/tools/coffee-manager/se/sics/coffee/CoffeeFile.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: CoffeeFile.java,v 1.1 2009/08/04 10:36:53 nvt-se Exp $ + * + * @author Nicolas Tsiftes + * + */ + +package se.sics.coffee; + +import java.io.*; + +public class CoffeeFile { + private CoffeeFS coffeeFS; + private CoffeeHeader header; + private String name; + private int length; + private int startPage; + private int reservedSize; + private CoffeeFile logFile; + private boolean knownLength; + + public CoffeeFile(CoffeeFS coffeeFS, CoffeeHeader header) { + this.coffeeFS = coffeeFS; + this.header = header; + name = header.name; + startPage = header.getPage(); + reservedSize = header.maxPages * coffeeFS.getConfiguration().pageSize; + } + + private int calculateLength() throws IOException { + byte[] bytes = new byte[1]; + int i; + + for(i = reservedSize; i >= header.rawLength(); i--) { + coffeeFS.getImage().read(bytes, 1, header.getPage() * coffeeFS.getConfiguration().pageSize + i); + if(bytes[0] != 0) { + return i - header.rawLength() + 1; + } + } + return 0; + } + + public void insertContents(FileInputStream input) throws IOException { + byte[] bytes = new byte[1]; + int ch; + int startOffset = header.getPage() * + coffeeFS.getConfiguration().pageSize + + header.rawLength(); + + length = 0; + knownLength = true; + + while((ch = input.read()) != -1) { + bytes[0] = (byte) ch; + + coffeeFS.getImage().write(bytes, 1, + startOffset + length); + length++; + } +System.out.println("inserted bytes: " + length); + } + + public void saveContents(String filename) throws IOException { + byte[] bytes = new byte[1]; + int startOffset = header.getPage() * + coffeeFS.getConfiguration().pageSize + + header.rawLength(); + int i; + + FileOutputStream fOut = new FileOutputStream(filename); + for(i = 0; i < getLength(); i++) { + coffeeFS.getImage().read(bytes, 1, startOffset + i); + fOut.write(bytes); + } + + fOut.close(); + } + + public void remove() { + header.makeObsolete(); + } + + public CoffeeHeader getHeader() { + return header; + } + + public int getLength() throws IOException { + if(!knownLength) { + length = calculateLength(); + knownLength = true; + } + return length; + } + + public String getName() { + return name; + } + + public int getReservedSize() { + return reservedSize; + } +} diff --git a/tools/coffee-manager/se/sics/coffee/CoffeeHeader.java b/tools/coffee-manager/se/sics/coffee/CoffeeHeader.java new file mode 100644 index 000000000..37cd5bebb --- /dev/null +++ b/tools/coffee-manager/se/sics/coffee/CoffeeHeader.java @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: CoffeeHeader.java,v 1.1 2009/08/04 10:36:53 nvt-se Exp $ + * + * @author Nicolas Tsiftes + * + */ + +package se.sics.coffee; + +class CoffeeHeader { + private CoffeeFS coffeeFS; + private CoffeeConfiguration conf; + private int page; + + private static final int HDR_FLAG_VALID = 0x1; + private static final int HDR_FLAG_ALLOCATED = 0x2; + private static final int HDR_FLAG_OBSOLETE = 0x4; + private static final int HDR_FLAG_MODIFIED = 0x8; + private static final int HDR_FLAG_LOG = 0x10; + private static final int HDR_FLAG_ISOLATED = 0x20; + + int logPage; + int logRecords; + int logRecordSize; + int maxPages; + String name; + + private boolean valid; + private boolean allocated; + private boolean obsolete; + private boolean modified; + private boolean log; + private boolean isolated; + + public CoffeeHeader(CoffeeFS coffeeFS, int page) { + this.coffeeFS = coffeeFS; + this.page = page; + conf = coffeeFS.getConfiguration(); + } + + public CoffeeHeader(CoffeeFS coffeeFS, int page, byte[] bytes) { + this.coffeeFS = coffeeFS; + this.page = page; + + processRawHeader(bytes); + } + + private void processRawHeader(byte[] bytes) { + int index = 0; + + logPage = getPageValue(bytes, 0); + index += conf.pageTypeSize; + + logRecords = bytes[index] + (bytes[index + 1] << 8); + index += 2; + + logRecordSize = bytes[index] + (bytes[index + 1] << 8); + index += 2; + + maxPages = getPageValue(bytes, index); + index += conf.pageTypeSize; + + index++; // Skip deprecated EOF hint field. + + processFlags((int)bytes[index]); + index++; + + name = new String(bytes).substring(index, + index + conf.NAME_LENGTH); + int nullCharOffset = name.indexOf(0); + if(nullCharOffset >= 0) { + name = name.substring(0, nullCharOffset); + } + } + + private byte composeFlags() { + byte flags = 0; + + if(valid) { + flags |= HDR_FLAG_VALID; + } + if(allocated) { + flags |= HDR_FLAG_ALLOCATED; + } + if(obsolete) { + flags |= HDR_FLAG_OBSOLETE; + } + if(modified) { + flags |= HDR_FLAG_MODIFIED; + } + if(log) { + flags |= HDR_FLAG_LOG; + } + + if(isolated) { + flags |= HDR_FLAG_ISOLATED; + } + + return flags; + } + + private void processFlags(int flags) { + if((flags & HDR_FLAG_VALID) != 0) { + valid = true; + } + if((flags & HDR_FLAG_ALLOCATED) != 0) { + allocated = true; + } + if((flags & HDR_FLAG_OBSOLETE) != 0) { + obsolete = true; + } + if((flags & HDR_FLAG_MODIFIED) != 0) { + modified = true; + } + if((flags & HDR_FLAG_LOG) != 0) { + log = true; + } + if((flags & HDR_FLAG_ISOLATED) != 0) { + isolated = true; + } + } + + private byte[] setPageValue(int page) { + byte[] bytes = new byte[conf.pageTypeSize]; + + for(int i = conf.pageTypeSize - 1; i >= 0; i--) { + bytes[i] = (byte) (page >> (8 * i)); + } + return bytes; + } + + private int getPageValue(byte[] bytes, int offset) { + int page = 0; + + for(int i = 0; i < conf.pageTypeSize; i++) { + page |= bytes[offset + i] << (8 * i); + } + return page; + } + + public byte[] toRawHeader() { + byte[] bytes = new byte[2 * conf.pageTypeSize + + conf.NAME_LENGTH + 6]; + int index = 0; + + System.arraycopy(setPageValue(logPage), 0, bytes, 0, + conf.pageTypeSize); + index += conf.pageTypeSize; + + bytes[index++] = (byte) (logRecords >> 8); + bytes[index++] = (byte) logRecords; + + bytes[index++] = (byte) (logRecordSize >> 8); + bytes[index++] = (byte) logRecordSize; + + System.arraycopy(setPageValue(maxPages), 0, bytes, index, + conf.pageTypeSize); + index += conf.pageTypeSize; + + bytes[index++] = 0; // Deprecated EOF hint field. + bytes[index++] = composeFlags(); + + byte[] nameBytes = name.getBytes(); + int copyLength = nameBytes.length > conf.NAME_LENGTH ? + conf.NAME_LENGTH : nameBytes.length; + System.arraycopy(nameBytes, 0, bytes, index, copyLength); + + return bytes; + } + + public int rawLength() { + return 2 * conf.pageTypeSize + conf.NAME_LENGTH + 6; + } + + public int getPage() { + return page; + } + + public boolean isValid() { + return valid; + } + + public boolean isAllocated() { + return allocated; + } + + public boolean isObsolete() { + return obsolete; + } + + public boolean isModified() { + return modified; + } + + public boolean isIsolated() { + return isolated; + } + + public boolean isLog() { + return log; + } + + public boolean isFree() { + return !isAllocated(); + } + + public boolean isActive() { + return isAllocated() && !isObsolete() && !isIsolated(); + } + + public void allocate() { + allocated = true; + } + + public void makeObsolete() { + obsolete = true; + } + + public void setName(String name) { + this.name = name; + } + + public void setReservedSize(int pages) { + maxPages = pages; + } + + public int getReservedSize() { + return maxPages; + } +} diff --git a/tools/coffee-manager/se/sics/coffee/CoffeeImage.java b/tools/coffee-manager/se/sics/coffee/CoffeeImage.java new file mode 100644 index 000000000..6fb2618eb --- /dev/null +++ b/tools/coffee-manager/se/sics/coffee/CoffeeImage.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: CoffeeImage.java,v 1.1 2009/08/04 10:36:53 nvt-se Exp $ + * + * @author Nicolas Tsiftes + * + */ + +package se.sics.coffee; + +import java.io.IOException; + +interface CoffeeImage { + CoffeeConfiguration getConfiguration(); + void read(byte[] bytes, int size, int offset) throws IOException; + void write(byte[] bytes, int size, int offset) throws IOException; + void erase(int size, int offset) throws IOException; +} diff --git a/tools/coffee-manager/se/sics/coffee/CoffeeImageFile.java b/tools/coffee-manager/se/sics/coffee/CoffeeImageFile.java new file mode 100644 index 000000000..8d814464d --- /dev/null +++ b/tools/coffee-manager/se/sics/coffee/CoffeeImageFile.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: CoffeeImageFile.java,v 1.1 2009/08/04 10:36:53 nvt-se Exp $ + * + * @author Nicolas Tsiftes + * + */ + +package se.sics.coffee; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; + +public class CoffeeImageFile implements CoffeeImage { + private String filename; + private RandomAccessFile imageFile; + private CoffeeConfiguration conf; + + public CoffeeImageFile(String filename, CoffeeConfiguration conf) throws IOException { + this.filename = filename; + this.conf = conf; + File file = new File(filename); + imageFile = new RandomAccessFile(file, "rw"); + if(imageFile.length() == 0) { + // Allocate a full file system image. + imageFile.setLength(conf.fsSize); + } + } + + public CoffeeConfiguration getConfiguration() { + return conf; + } + + public void read(byte[] bytes, int size, int offset) throws IOException { + imageFile.seek(conf.startOffset + offset); + imageFile.read(bytes, 0, size); + } + + public void write(byte[] bytes, int size, int offset) throws IOException { + imageFile.seek(conf.startOffset + offset); + imageFile.write(bytes, 0, size); + } + + public void erase(int size, int offset) throws IOException { + byte[] bytes = new byte[256]; + int chunkSize; + + while(size > 0) { + chunkSize = size > bytes.length ? bytes.length : size; + imageFile.seek(conf.startOffset + offset); + imageFile.write(bytes, 0, chunkSize); + size -= chunkSize; + offset += chunkSize; + } + } + +} diff --git a/tools/coffee-manager/se/sics/coffee/CoffeeManager.java b/tools/coffee-manager/se/sics/coffee/CoffeeManager.java new file mode 100644 index 000000000..581cb3f80 --- /dev/null +++ b/tools/coffee-manager/se/sics/coffee/CoffeeManager.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: CoffeeManager.java,v 1.1 2009/08/04 10:36:53 nvt-se Exp $ + * + * @author Nicolas Tsiftes + * + */ + +package se.sics.coffee; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CoffeeManager { + private static CoffeeFS coffeeFS; + private static final int COMMAND_NULL = 0; + private static final int COMMAND_INSERT = 1; + private static final int COMMAND_EXTRACT = 2; + private static final int COMMAND_REMOVE = 3; + private static final int COMMAND_LIST = 4; + private static final int COMMAND_STATS = 5; + + public static void main(String args[]) { + String platform = "sky"; + String usage = "Usage: java -jar coffee.jar "; + int command = COMMAND_NULL; + String coffeeFile = ""; + String localFile = ""; + String fsImage = ""; + + usage += "[-i|e ] "; + usage += "[-r ] "; + usage += "[-l|s] "; + usage += ""; + + if(args.length < 1) { + System.err.println(usage); + System.exit(1); + } + + if(args.length > 1) { + Pattern validArg = Pattern.compile("-(i|e|r|l|s)"); + Matcher m = validArg.matcher(args[0]); + if(!m.matches()) { + System.err.println(usage); + System.exit(1); + } + + if(args[0].equals("-i") || args[0].equals("-e")) { + if(args.length != 4) { + System.err.println(usage); + System.exit(1); + } + if(args[0].equals("-i")) { + command = COMMAND_INSERT; + } else { + command = COMMAND_EXTRACT; + } + coffeeFile = args[1]; + localFile = args[2]; + fsImage = args[3]; + } else if (args[0].equals("-r")) { + if(args.length != 3) { + System.err.println(usage); + System.exit(1); + } + command = COMMAND_REMOVE; + coffeeFile = args[1]; + fsImage = args[2]; + } else { + if(args.length != 2) { + System.err.println(usage); + System.exit(1); + } + if(args[0].equals("-l")) { + command = COMMAND_LIST; + } else { + command = COMMAND_STATS; + } + fsImage = args[1]; + } + } + + try { + CoffeeConfiguration conf = new CoffeeConfiguration(platform + ".properties"); + coffeeFS = new CoffeeFS(new CoffeeImageFile(fsImage, conf)); + switch (command) { + case COMMAND_INSERT: + if(coffeeFS.getFiles().get(localFile) != null) { + System.err.println("error: file \"" + localFile + "\" already exists"); + break; + } + if(coffeeFS.insertFile(localFile) != null) { + System.out.println("Inserted the local file \"" + localFile + "\" into the file system image"); + } + break; + case COMMAND_EXTRACT: + if(coffeeFS.extractFile(coffeeFile, localFile) == false) { + System.err.println("Inexistent file: " + coffeeFile); + System.exit(1); + } + System.out.println("Saved the file \"" + coffeeFile + "\" from the system image into the local file \"" + localFile + "\""); + break; + case COMMAND_REMOVE: + coffeeFS.removeFile(coffeeFile); + System.out.println("Removed the file \"" + coffeeFile + "\" from the Coffee file system image"); + break; + case COMMAND_LIST: + printFiles(coffeeFS.getFiles()); + break; + case COMMAND_STATS: + printStatistics(coffeeFS); + break; + default: + System.err.println("Unknown command!"); + System.exit(1); + } + } catch (IOException e) { + System.err.println(e.getMessage()); + } + } + + private static void printStatistics(CoffeeFS coffeeFS) { + int bytesWritten = 0; + int bytesReserved = 0; + int fileCount = 0; + CoffeeConfiguration conf = coffeeFS.getConfiguration(); + + try { + Iterator> iterator = + coffeeFS.getFiles().entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry pair = (Map.Entry) iterator.next(); + String key = pair.getKey(); + CoffeeFile file = pair.getValue(); + bytesWritten += file.getLength(); + bytesReserved += file.getHeader().getReservedSize(); + fileCount++; + } + bytesReserved *= conf.pageSize; + System.out.println("File system size: " + + conf.fsSize / 1024 + "kb"); + System.out.println("Allocated files: " + fileCount); + System.out.println("Reserved bytes: " + bytesReserved + " (" + + (100 * ((float) bytesReserved / conf.fsSize)) + + "%)"); + System.out.println("Written bytes: " + bytesWritten + + " (" + + (100 * ((float) bytesWritten / conf.fsSize)) + + "%)"); + } catch (IOException e) { + System.err.println("failed to determine the file length"); + } + } + + private static void printFiles(Map files) { + try { + Iterator> iterator = files.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry pair = (Map.Entry) iterator.next(); + String key = pair.getKey(); + CoffeeFile file = pair.getValue(); + System.out.println(file.getName() + " " + file.getLength()); + } + } catch (IOException e) { + System.err.println("failed to determine the file length"); + } + } +} diff --git a/tools/coffee-manager/sky.properties b/tools/coffee-manager/sky.properties new file mode 100644 index 000000000..924663fff --- /dev/null +++ b/tools/coffee-manager/sky.properties @@ -0,0 +1,8 @@ +fs_size 983040 +sector_size 65536 +page_size 256 +start_offset 65536 +default_file_size 4096 +default_log_size 1024 +use_micro_logs true +page_type_size 2