blob: a278e88975b6c2a9714fc27d03e723fa962ec7d4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.felix.gogo.command;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.apache.felix.service.command.CommandSession;
import org.apache.felix.service.command.Descriptor;
import org.osgi.framework.BundleContext;
import static org.apache.felix.gogo.command.Util.CWD;
public class Files
{
@SuppressWarnings("unused")
private final BundleContext m_bc;
public Files(BundleContext bc)
{
m_bc = bc;
}
@Descriptor("get current directory")
public File cd(
@Descriptor("automatically supplied shell session") CommandSession session)
{
try
{
return cd(session, null);
}
catch (IOException ex)
{
throw new RuntimeException("Unable to get current directory");
}
}
@Descriptor("change current directory")
public File cd(
@Descriptor("automatically supplied shell session") CommandSession session,
@Descriptor("target directory") String dir)
throws IOException
{
File cwd = (File) session.get(CWD);
if (cwd == null)
{
cwd = new File(".").getCanonicalFile();
session.put(CWD, cwd);
}
if ((dir == null) || (dir.length() == 0))
{
return cwd;
}
URI curUri = cwd.toURI();
URI newUri = curUri.resolve(dir);
cwd = new File(newUri);
if (!cwd.exists())
{
throw new IOException("Directory does not exist");
}
else if (!cwd.isDirectory())
{
throw new IOException("Target is not a directory");
}
session.put(CWD, cwd.getCanonicalFile());
return cwd;
}
@Descriptor("get current directory contents")
public File[] ls(
@Descriptor("automatically supplied shell session") CommandSession session)
throws IOException
{
return ls(session, null);
}
@Descriptor("get specified path contents")
public File[] ls(
@Descriptor("automatically supplied shell session") CommandSession session,
@Descriptor("path with optionally wildcarded file name") String pattern)
throws IOException
{
pattern = ((pattern == null) || (pattern.length() == 0)) ? "." : pattern;
pattern = ((pattern.charAt(0) != File.separatorChar) && (pattern.charAt(0) != '.'))
? "./" + pattern : pattern;
int idx = pattern.lastIndexOf(File.separatorChar);
String parent = (idx < 0) ? "." : pattern.substring(0, idx + 1);
String target = (idx < 0) ? pattern : pattern.substring(idx + 1);
File actualParent = ((parent.charAt(0) == File.separatorChar)
? new File(parent) : new File(cd(session), parent)).getCanonicalFile();
idx = target.indexOf(File.separatorChar, idx);
boolean isWildcarded = (target.indexOf('*', idx) >= 0);
File[] files;
if (isWildcarded)
{
if (!actualParent.exists())
{
throw new IOException("File does not exist");
}
final List<String> pieces = parseSubstring(target);
files = actualParent.listFiles(new FileFilter() {
public boolean accept(File pathname)
{
return compareSubstring(pieces, pathname.getName());
}
});
}
else
{
File actualTarget = new File(actualParent, target).getCanonicalFile();
if (!actualTarget.exists())
{
throw new IOException("File does not exist");
}
if (actualTarget.isDirectory())
{
files = actualTarget.listFiles();
}
else
{
files = new File[] { actualTarget };
}
}
return files;
}
public static List<String> parseSubstring(String value)
{
List<String> pieces = new ArrayList<>();
StringBuilder ss = new StringBuilder();
// int kind = SIMPLE; // assume until proven otherwise
boolean wasStar = false; // indicates last piece was a star
boolean leftstar = false; // track if the initial piece is a star
boolean rightstar = false; // track if the final piece is a star
int idx = 0;
// We assume (sub)strings can contain leading and trailing blanks
boolean escaped = false;
loop: for (;;)
{
if (idx >= value.length())
{
if (wasStar)
{
// insert last piece as "" to handle trailing star
rightstar = true;
}
else
{
pieces.add(ss.toString());
// accumulate the last piece
// note that in the case of
// (cn=); this might be
// the string "" (!=null)
}
ss.setLength(0);
break loop;
}
// Read the next character and account for escapes.
char c = value.charAt(idx++);
if (!escaped && ((c == '(') || (c == ')')))
{
throw new IllegalArgumentException(
"Illegal value: " + value);
}
else if (!escaped && (c == '*'))
{
if (wasStar)
{
// encountered two successive stars;
// I assume this is illegal
throw new IllegalArgumentException("Invalid filter string: " + value);
}
if (ss.length() > 0)
{
pieces.add(ss.toString()); // accumulate the pieces
// between '*' occurrences
}
ss.setLength(0);
// if this is a leading star, then track it
if (pieces.size() == 0)
{
leftstar = true;
}
wasStar = true;
}
else if (!escaped && (c == '\\'))
{
escaped = true;
}
else
{
escaped = false;
wasStar = false;
ss.append(c);
}
}
if (leftstar || rightstar || pieces.size() > 1)
{
// insert leading and/or trailing "" to anchor ends
if (rightstar)
{
pieces.add("");
}
if (leftstar)
{
pieces.add(0, "");
}
}
return pieces;
}
public static boolean compareSubstring(List<String> pieces, String s)
{
// Walk the pieces to match the string
// There are implicit stars between each piece,
// and the first and last pieces might be "" to anchor the match.
// assert (pieces.length > 1)
// minimal case is <string>*<string>
boolean result = true;
int len = pieces.size();
int index = 0;
loop: for (int i = 0; i < len; i++)
{
String piece = pieces.get(i);
// If this is the first piece, then make sure the
// string starts with it.
if (i == 0)
{
if (!s.startsWith(piece))
{
result = false;
break loop;
}
}
// If this is the last piece, then make sure the
// string ends with it.
if (i == len - 1)
{
result = s.endsWith(piece);
break loop;
}
// If this is neither the first or last piece, then
// make sure the string contains it.
if ((i > 0) && (i < (len - 1)))
{
index = s.indexOf(piece, index);
if (index < 0)
{
result = false;
break loop;
}
}
// Move string index beyond the matching piece.
index += piece.length();
}
return result;
}
}