001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.vfs2.provider.local; 018 019import java.io.File; 020import java.io.FileInputStream; 021import java.io.FileOutputStream; 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.OutputStream; 025 026import org.apache.commons.vfs2.FileObject; 027import org.apache.commons.vfs2.FileSystemException; 028import org.apache.commons.vfs2.FileType; 029import org.apache.commons.vfs2.RandomAccessContent; 030import org.apache.commons.vfs2.provider.AbstractFileName; 031import org.apache.commons.vfs2.provider.AbstractFileObject; 032import org.apache.commons.vfs2.provider.UriParser; 033import org.apache.commons.vfs2.util.FileObjectUtils; 034import org.apache.commons.vfs2.util.RandomAccessMode; 035 036/** 037 * A file object implementation which uses direct file access. 038 */ 039public class LocalFile extends AbstractFileObject<LocalFileSystem> { 040 private final String rootFile; 041 042 private File file; 043 044 /** 045 * Creates a non-root file. 046 * 047 * @param fileSystem the file system this file belongs to. 048 * @param rootFile the root file for the file system. 049 * @param name the file name on this file system. 050 * @throws FileSystemException if an error occurs. 051 */ 052 protected LocalFile(final LocalFileSystem fileSystem, final String rootFile, final AbstractFileName name) 053 throws FileSystemException { 054 super(name, fileSystem); 055 this.rootFile = rootFile; 056 } 057 058 /** 059 * Returns the local file that this file object represents. 060 * 061 * @return the local file that this file object represents. 062 */ 063 protected File getLocalFile() { 064 return file; 065 } 066 067 /** 068 * Attaches this file object to its file resource. 069 */ 070 @Override 071 protected void doAttach() throws Exception { 072 if (file == null) { 073 // Remove the "file:///" 074 // LocalFileName localFileName = (LocalFileName) getName(); 075 final String fileName = rootFile + getName().getPathDecoded(); 076 // fileName = UriParser.decode(fileName); 077 file = new File(fileName); 078 } 079 } 080 081 /** 082 * Returns the file's type. 083 */ 084 @Override 085 protected FileType doGetType() throws Exception { 086 // JDK BUG: 6192331 087 // if (!file.exists()) 088 if (!file.exists() && file.length() < 1) { 089 return FileType.IMAGINARY; 090 } 091 092 if (file.isDirectory()) { 093 return FileType.FOLDER; 094 } 095 096 // In doubt, treat an existing file as file 097 // if (file.isFile()) 098 // { 099 return FileType.FILE; 100 // } 101 102 // throw new FileSystemException("vfs.provider.local/get-type.error", file); 103 } 104 105 /** 106 * Returns the children of the file. 107 */ 108 @Override 109 protected String[] doListChildren() throws Exception { 110 return UriParser.encode(file.list()); 111 } 112 113 /** 114 * Deletes this file, and all children. 115 */ 116 @Override 117 protected void doDelete() throws Exception { 118 if (!file.delete()) { 119 throw new FileSystemException("vfs.provider.local/delete-file.error", file); 120 } 121 } 122 123 /** 124 * rename this file 125 */ 126 @Override 127 protected void doRename(final FileObject newFile) throws Exception { 128 final LocalFile newLocalFile = (LocalFile) FileObjectUtils.getAbstractFileObject(newFile); 129 130 if (!file.renameTo(newLocalFile.getLocalFile())) { 131 throw new FileSystemException("vfs.provider.local/rename-file.error", file.toString(), newFile.toString()); 132 } 133 } 134 135 /** 136 * Creates this folder. 137 */ 138 @Override 139 protected void doCreateFolder() throws Exception { 140 if (!file.mkdirs()) { 141 throw new FileSystemException("vfs.provider.local/create-folder.error", file); 142 } 143 } 144 145 /** 146 * Determines if this file can be written to. 147 */ 148 @Override 149 protected boolean doIsWriteable() throws FileSystemException { 150 return file.canWrite(); 151 } 152 153 @Override 154 protected boolean doSetWritable(final boolean writable, final boolean ownerOnly) throws Exception { 155 return file.setWritable(writable, ownerOnly); 156 } 157 158 /** 159 * Determines if this file is hidden. 160 */ 161 @Override 162 protected boolean doIsExecutable() { 163 return file.canExecute(); 164 } 165 166 /** 167 * Determines if this file is hidden. 168 */ 169 @Override 170 protected boolean doIsHidden() { 171 return file.isHidden(); 172 } 173 174 /** 175 * Determines if this file can be read. 176 */ 177 @Override 178 protected boolean doIsReadable() throws FileSystemException { 179 return file.canRead(); 180 } 181 182 @Override 183 protected boolean doSetReadable(final boolean readable, final boolean ownerOnly) throws Exception { 184 return file.setReadable(readable, ownerOnly); 185 } 186 187 @Override 188 protected boolean doSetExecutable(final boolean executable, final boolean ownerOnly) throws Exception { 189 return file.setExecutable(executable, ownerOnly); 190 } 191 192 /** 193 * Gets the last modified time of this file. 194 */ 195 @Override 196 protected long doGetLastModifiedTime() throws FileSystemException { 197 return file.lastModified(); 198 } 199 200 /** 201 * Sets the last modified time of this file. 202 * 203 * @since 2.0 204 */ 205 @Override 206 protected boolean doSetLastModifiedTime(final long modtime) throws FileSystemException { 207 return file.setLastModified(modtime); 208 } 209 210 /** 211 * Creates an input stream to read the content from. 212 */ 213 @Override 214 protected InputStream doGetInputStream() throws Exception { 215 return new FileInputStream(file); 216 } 217 218 /** 219 * Creates an output stream to write the file content to. 220 */ 221 @Override 222 protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception { 223 return new FileOutputStream(file.getPath(), bAppend); 224 } 225 226 /** 227 * Returns the size of the file content (in bytes). 228 */ 229 @Override 230 protected long doGetContentSize() throws Exception { 231 return file.length(); 232 } 233 234 @Override 235 protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { 236 return new LocalFileRandomAccessContent(file, mode); 237 } 238 239 @Override 240 protected boolean doIsSameFile(final FileObject destFile) throws FileSystemException { 241 if (!FileObjectUtils.isInstanceOf(destFile, LocalFile.class)) { 242 return false; 243 } 244 245 final LocalFile destLocalFile = (LocalFile) FileObjectUtils.getAbstractFileObject(destFile); 246 if (!exists() || !destLocalFile.exists()) { 247 return false; 248 } 249 250 try { 251 return file.getCanonicalPath().equals(destLocalFile.file.getCanonicalPath()); 252 } catch (final IOException e) { 253 throw new FileSystemException(e); 254 } 255 } 256 257 /** 258 * Returns the URI of the file. 259 * 260 * @return The URI of the file. 261 */ 262 @Override 263 public String toString() { 264 try { 265 // VFS-325: URI may contain percent-encoded values as part of filename, so decode 266 // those characters before returning 267 return UriParser.decode(getName().getURI()); 268 } catch (final FileSystemException e) { 269 return getName().getURI(); 270 } 271 } 272}