/*
* Copyright (C) 2012 The CyanogenMod Project
*
* Licensed 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 com.cyanogenmod.filemanager.commands.shell;
import android.util.Log;
import com.cyanogenmod.filemanager.commands.ListExecutable;
import com.cyanogenmod.filemanager.console.CommandNotFoundException;
import com.cyanogenmod.filemanager.console.ExecutionException;
import com.cyanogenmod.filemanager.console.InsufficientPermissionsException;
import com.cyanogenmod.filemanager.console.shell.ShellConsole;
import com.cyanogenmod.filemanager.model.FileSystemObject;
import com.cyanogenmod.filemanager.model.ParentDirectory;
import com.cyanogenmod.filemanager.util.FileHelper;
import com.cyanogenmod.filemanager.util.ParseHelper;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringReader;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
/**
* A class for list information about files and directories.
*
* {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?stat"}
*/
public class ListCommand extends SyncResultProgram implements ListExecutable {
private static final String TAG = "ListCommand"; //$NON-NLS-1$
private static final String ID_LS = "ls"; //$NON-NLS-1$
private static final String ID_FILEINFO = "fileinfo"; //$NON-NLS-1$
private final LIST_MODE mMode;
private final List<FileSystemObject> mFiles;
private String mParentDir;
/**
* Constructor of <code>ListCommand</code>. List mode.
*
* @param src The file system object to be listed
* @param console The console in which retrieve the parent directory information.
* <code>null</code> to attach to the default console
* @throws InvalidCommandDefinitionException If the command has an invalid definition
*/
public ListCommand(String src, ShellConsole console)
throws InvalidCommandDefinitionException {
// Always add backslash for list the files of the directory, instead of
// the directory.
super(ID_LS, new String[]{ FileHelper.addTrailingSlash(src) });
//Initialize files to something distinct of null
this.mFiles = new ArrayList<FileSystemObject>();
this.mMode = LIST_MODE.DIRECTORY;
//Retrieve parent directory information
if (src.compareTo(FileHelper.ROOT_DIRECTORY) == 0) {
this.mParentDir = null;
} else {
this.mParentDir = new File(src).getAbsolutePath();
}
}
/**
* Constructor of <code>ListCommand</code>. FileInfo mode
*
* @param src The file system object to be listed
* @param followSymlinks If follow the symlink
* @param console The console in which retrieve the parent directory information.
* <code>null</code> to attach to the default console
* @throws InvalidCommandDefinitionException If the command has an invalid definition
* @throws FileNotFoundException If the initial directory not exists
* @throws IOException If initial directory couldn't be checked
*/
public ListCommand(String src, boolean followSymlinks, ShellConsole console)
throws InvalidCommandDefinitionException, FileNotFoundException, IOException {
// Always remove backslash for avoid listing the files of the directory, instead of
// the directory.
super(ID_FILEINFO,
new String[]{
FileHelper.removeTrailingSlash(
followSymlinks ?
new File(src).getCanonicalPath() :
new File(src).getAbsolutePath())});
//Initialize files to something distinct of null
this.mFiles = new ArrayList<FileSystemObject>();
this.mMode = LIST_MODE.FILEINFO;
//Get the absolute path
if (followSymlinks) {
this.mParentDir =
FileHelper.removeTrailingSlash(
new File(src).getCanonicalFile().getParent());
} else {
this.mParentDir =
FileHelper.removeTrailingSlash(
new File(src).getAbsoluteFile().getParent());
}
}
/**
* {@inheritDoc}
*/
@Override
public void parse(String in, String err) throws ParseException {
//Release the array
this.mFiles.clear();
// Read every line and parse it
BufferedReader br = null;
try {
br = new BufferedReader(new StringReader(in));
String line = null;
while ((line = br.readLine()) != null) {
//Checks that there is some text in the line. Otherwise ignore it
if (line.trim().length() == 0) {
break;
}
// Parse and add to result files
try {
this.mFiles.add(ParseHelper.parseStatOutput(line));
} catch (Exception e) {
// Log the parsing error
if (isTrace()) {
Log.w(TAG,
String.format(
"Failed to parse output: %s", //$NON-NLS-1$
String.valueOf(line)));
}
}
}
// Add the parent directory
if (this.mParentDir != null &&
this.mParentDir.compareTo(FileHelper.ROOT_DIRECTORY) != 0 &&
this.mMode.compareTo(LIST_MODE.DIRECTORY) == 0) {
this.mFiles.add(0, new ParentDirectory(new File(this.mParentDir).getParent()));
}
} catch (IOException ioEx) {
throw new ParseException(ioEx.getMessage(), 0);
} catch (Exception ex) {
throw new ParseException(ex.getMessage(), 0);
} finally {
try {
if (br != null) {
br.close();
}
} catch (Throwable ex) {
/**NON BLOCK**/
}
}
}
/**
* {@inheritDoc}
*/
@Override
public List<FileSystemObject> getResult() {
return this.mFiles;
}
/**
* Method that returns a single result of the program invocation.
* Only must be called within a <code>FILEINFO</code> mode listing.
*
* @return FileSystemObject The file system object reference
*/
public FileSystemObject getSingleResult() {
return this.mFiles.get(0);
}
/**
* {@inheritDoc}
*/
@Override
public void checkExitCode(int exitCode)
throws InsufficientPermissionsException, CommandNotFoundException, ExecutionException {
// 123: stat failed ... Function not implemented (for broken symlinks)
if (exitCode != 0 && exitCode != 1 && exitCode != 123) {
throw new ExecutionException("exitcode != 0 && != 1 && != 123"); //$NON-NLS-1$
}
}
}