Add a managment tool for Coffee file system images.

This commit is contained in:
nvt-se 2009-08-04 10:36:53 +00:00
parent 893a3517a9
commit 0f1f50d9c8
12 changed files with 1058 additions and 0 deletions

View file

@ -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.

View file

@ -0,0 +1,2 @@
Manifest-Version: 1.0
Main-Class: se.sics.coffee.CoffeeManager

View file

@ -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 <Coffee file> <file>] [-r <Coffee file>]
[-l|s] <file system image>
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 <nvt@sics.se>

2
tools/coffee-manager/build.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/sh
(cd se/sics/coffee && javac *.java) && jar cvfm coffee.jar MANIFEST.MF se/

View file

@ -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;
}
}

View file

@ -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<String, CoffeeFile> 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<String, CoffeeFile>();
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<String, CoffeeFile> 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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -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 <Coffee file> <file>] ";
usage += "[-r <Coffee file>] ";
usage += "[-l|s] ";
usage += "<file system image>";
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<Map.Entry<String, CoffeeFile>> iterator =
coffeeFS.getFiles().entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, CoffeeFile> pair = (Map.Entry<String, CoffeeFile>) 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<String, CoffeeFile> files) {
try {
Iterator<Map.Entry<String, CoffeeFile>> iterator = files.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, CoffeeFile> pair = (Map.Entry<String, CoffeeFile>) 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");
}
}
}

View file

@ -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