Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fs/build-tests.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ help Output these messages
<test name="org.jnode.test.driver.bus.ide.IDEDriveDescriptorTest" todir="${basedir}/build/reports/junit"/>
<test name="org.jnode.test.fs.filesystem.FSTestSuite" todir="${basedir}/build/reports/junit"/>
<test name="org.jnode.test.fs.driver.tests.BlockDeviceAPITest" todir="${basedir}/build/reports/junit"/>
<test name="org.jnode.test.fs.command.SyncCommandTest" todir="${basedir}/build/reports/junit"/>
</junit>
</target>

Expand Down
7 changes: 7 additions & 0 deletions fs/descriptors/org.jnode.fs.command.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
<extension point="org.jnode.shell.aliases">
<alias name="eject" class="org.jnode.fs.command.EjectCommand"/>
<alias name="mount" class="org.jnode.fs.command.MountCommand"/>
<alias name="sync" class="org.jnode.fs.command.SyncCommand"/>
</extension>

<extension point="org.jnode.shell.syntaxes">
Expand All @@ -59,6 +60,12 @@
<argument argLabel="fsPath" description="the file system's root directory"/>
</sequence>
</syntax>
<syntax alias="sync">
<empty description="Flush all mounted filesystems to disk"/>
<sequence description="Flush the filesystem at a specific path">
<argument argLabel="path" description="the path of the filesystem to flush"/>
</sequence>
</syntax>
</extension>

<extension point="org.jnode.security.permissions">
Expand Down
130 changes: 130 additions & 0 deletions fs/src/commands/org/jnode/fs/command/SyncCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

package org.jnode.fs.command;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import org.jnode.driver.ApiNotFoundException;
import org.jnode.driver.Device;
import org.jnode.driver.block.BlockDeviceAPI;
import org.jnode.fs.FileSystem;
import org.jnode.fs.service.FileSystemService;
import org.jnode.fs.spi.AbstractFileSystem;
import org.jnode.naming.InitialNaming;
import org.jnode.shell.AbstractCommand;
import org.jnode.shell.syntax.Argument;
import org.jnode.shell.syntax.FileArgument;

/**
* Flush filesystem buffers to disk.
*/
public class SyncCommand extends AbstractCommand {

private final FileArgument argPath =
new FileArgument("path", Argument.OPTIONAL,
"flush only the filesystem mounted at this path");

public SyncCommand() {
super("Flush filesystem buffers to disk");
registerArguments(argPath);
}

public static void main(String[] args) throws Exception {
new SyncCommand().execute(args);
}

public void execute() throws Exception {
FileSystemService fss = InitialNaming.lookup(FileSystemService.NAME);
PrintWriter out = getOutput().getPrintWriter();
PrintWriter err = getError().getPrintWriter();

if (argPath.isSet()) {
String path = argPath.getValue().getCanonicalPath();
Map.Entry<String, FileSystem<?>> match =
findMountPoint(fss.getMountPoints(), path);
if (match == null) {
err.println("No filesystem mounted at " + path);
exit(1);
}
flushFileSystem(match.getValue(), match.getKey(), out, err);
} else {
int errors = 0;
for (Map.Entry<String, FileSystem<?>> e : fss.getMountPoints().entrySet()) {
try {
flushFileSystem(e.getValue(), e.getKey(), out, err);
} catch (IOException ex) {
err.println("sync failed on " + e.getKey() + ": " + ex.getMessage());
errors++;
}
}
if (errors > 0) exit(1);
}
}

public static Map.Entry<String, FileSystem<?>> findMountPoint(
Map<String, FileSystem<?>> mountPoints, String path) {
FileSystem<?> target = null;
String mountPoint = null;
for (Map.Entry<String, FileSystem<?>> e : mountPoints.entrySet()) {
String key = e.getKey();
if (path.equals(key) || path.startsWith(key + "/") ||
(key.length() == 1 && path.length() > 0)) {
if (target == null || e.getKey().length() > mountPoint.length()) {
target = e.getValue();
mountPoint = e.getKey();
}
}
}
if (target == null) {
return null;
}
final FileSystem<?> t = target;
final String mp = mountPoint;
return new Map.Entry<String, FileSystem<?>>() {
public String getKey() { return mp; }
public FileSystem<?> getValue() { return t; }
public FileSystem<?> setValue(FileSystem<?> v) { throw new UnsupportedOperationException(); }
};
}

private void flushFileSystem(FileSystem<?> fs, String mountPoint,
PrintWriter out, PrintWriter err) throws IOException {
if (fs instanceof AbstractFileSystem) {
((AbstractFileSystem<?>) fs).flush();
}
Device device = fs.getDevice();
boolean deviceFlushed = false;
if (device != null) {
try {
BlockDeviceAPI api = device.getAPI(BlockDeviceAPI.class);
api.flush();
deviceFlushed = true;
} catch (ApiNotFoundException ex) {
}
}
out.print("synced " + mountPoint);
if (!deviceFlushed) {
out.print(" (device flush skipped)");
}
out.println();
}
}
129 changes: 129 additions & 0 deletions fs/src/test/org/jnode/test/fs/command/SyncCommandTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

package org.jnode.test.fs.command;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import junit.framework.TestCase;

import org.jnode.driver.Device;
import org.jnode.fs.FSEntry;
import org.jnode.fs.FileSystem;
import org.jnode.fs.FileSystemType;
import org.jnode.fs.command.SyncCommand;

public class SyncCommandTest extends TestCase {

private Map<String, FileSystem<?>> mountPoints;

@Override
protected void setUp() throws Exception {
super.setUp();
mountPoints = new HashMap<String, FileSystem<?>>();
mountPoints.put("/", new StubFileSystem("/"));
mountPoints.put("/home", new StubFileSystem("/home"));
mountPoints.put("/home/user", new StubFileSystem("/home/user"));
}

public void testExactMountPointMatch() {
Map.Entry<String, FileSystem<?>> result =
SyncCommand.findMountPoint(mountPoints, "/home");
assertNotNull(result);
assertEquals("/home", result.getKey());
}

public void testLongestPrefixMatch() {
Map.Entry<String, FileSystem<?>> result =
SyncCommand.findMountPoint(mountPoints, "/home/user/docs");
assertNotNull(result);
assertEquals("/home/user", result.getKey());
}

public void testNoMatchingMountPoint() {
Map<String, FileSystem<?>> noRoot = new HashMap<String, FileSystem<?>>();
noRoot.put("/home", new StubFileSystem("/home"));
noRoot.put("/home/user", new StubFileSystem("/home/user"));
Map.Entry<String, FileSystem<?>> result =
SyncCommand.findMountPoint(noRoot, "/var/log");
assertNull(result);
}

public void testRootMatch() {
Map.Entry<String, FileSystem<?>> result =
SyncCommand.findMountPoint(mountPoints, "/var/log");
assertNotNull(result);
assertEquals("/", result.getKey());
}

public void testExactRootMatch() {
Map.Entry<String, FileSystem<?>> result =
SyncCommand.findMountPoint(mountPoints, "/");
assertNotNull(result);
assertEquals("/", result.getKey());
}

private static class StubFileSystem implements FileSystem<FSEntry> {
private final String mp;

StubFileSystem(String mp) {
this.mp = mp;
}

public FileSystemType<? extends FileSystem<FSEntry>> getType() {
return null;
}

public Device getDevice() {
return null;
}

public FSEntry getRootEntry() throws IOException {
return null;
}

public boolean isReadOnly() {
return false;
}

public void close() throws IOException {
}

public boolean isClosed() {
return false;
}

public long getTotalSpace() throws IOException {
return 0;
}

public long getFreeSpace() throws IOException {
return 0;
}

public long getUsableSpace() throws IOException {
return 0;
}

public String getVolumeName() throws IOException {
return mp;
}
}
}
Loading