1 /* 2 * Copyright (C) 2020 Square, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package okio 17 18 import kotlin.reflect.KClass 19 import kotlin.reflect.cast 20 21 /** 22 * Description of a file or another object referenced by a path. 23 * 24 * In simple use a file system is a mechanism for organizing files and directories on a local 25 * storage device. In practice file systems are more capable and their contents more varied. For 26 * example, a path may refer to: 27 * 28 * * An operating system process that consumes data, produces data, or both. For example, reading 29 * from the `/dev/urandom` file on Linux returns a unique sequence of pseudorandom bytes to each 30 * reader. 31 * 32 * * A stream that connects a pair of programs together. A pipe is a special file that a producing 33 * program writes to and a consuming program reads from. Both programs operate concurrently. The 34 * size of a pipe is not well defined: the writer can write as much data as the reader is able to 35 * read. 36 * 37 * * A file on a remote file system. The performance and availability of remote files may be quite 38 * different from that of local files! 39 * 40 * * A symbolic link (symlink) to another path. When attempting to access this path the file system 41 * will follow the link and return data from the target path. 42 * 43 * * The same content as another path without a symlink. On UNIX file systems an inode is an 44 * anonymous handle to a file's content, and multiple paths may target the same inode without any 45 * other relationship to one another. A consequence of this design is that a directory with three 46 * 1 GiB files may only need 1 GiB on the storage device. 47 * 48 * This class does not attempt to model these rich file system features! It exposes a limited view 49 * useful for programs with only basic file system needs. Be cautious of the potential consequences 50 * of special files when writing programs that operate on a file system. 51 * 52 * File metadata is subject to change, and code that operates on file systems should defend against 53 * changes to the file that occur between reading metadata and subsequent operations. 54 */ 55 class FileMetadata( 56 /** True if this file is a container of bytes. If this is true, then [size] is non-null. */ 57 val isRegularFile: Boolean = false, 58 59 /** 60 * True if the path refers to a directory that contains 0 or more child paths. 61 * 62 * Note that a path does not need to be a directory for [FileSystem.list] to return successfully. 63 * For example, mounted storage devices may have child files, but do not identify themselves as 64 * directories. 65 */ 66 val isDirectory: Boolean = false, 67 68 /** 69 * The absolute or relative path that this file is a symlink to, or null if this is not a symlink. 70 * If this is a relative path, it is relative to the source file's parent directory. 71 */ 72 val symlinkTarget: Path? = null, 73 74 /** 75 * The number of bytes readable from this file. The amount of storage resources consumed by this 76 * file may be larger (due to block size overhead, redundant copies for RAID, etc.), or smaller 77 * (due to file system compression, shared inodes, etc). 78 */ 79 val size: Long? = null, 80 81 /** 82 * The system time of the host computer when this file was created, if the host file system 83 * supports this feature. This is typically available on Windows NTFS file systems and not 84 * available on UNIX or Windows FAT file systems. 85 */ 86 val createdAtMillis: Long? = null, 87 88 /** 89 * The system time of the host computer when this file was most recently written. 90 * 91 * Note that the accuracy of the returned time may be much more coarse than its precision. In 92 * particular, this value is expressed with millisecond precision but may be accessed at 93 * second- or day-accuracy only. 94 */ 95 val lastModifiedAtMillis: Long? = null, 96 97 /** 98 * The system time of the host computer when this file was most recently read or written. 99 * 100 * Note that the accuracy of the returned time may be much more coarse than its precision. In 101 * particular, this value is expressed with millisecond precision but may be accessed at 102 * second- or day-accuracy only. 103 */ 104 val lastAccessedAtMillis: Long? = null, 105 106 extras: Map<KClass<*>, Any> = mapOf(), 107 ) { 108 /** 109 * Additional file system-specific metadata organized by the class of that metadata. File systems 110 * may use this to include information like permissions, content-type, or linked applications. 111 * 112 * Values in this map should be instances of immutable classes. Keys should be the types of those 113 * classes. 114 */ 115 val extras: Map<KClass<*>, Any> = extras.toMap() 116 117 /** Returns extra metadata of type [type], or null if no such metadata is held. */ extranull118 fun <T : Any> extra(type: KClass<out T>): T? { 119 val value = extras[type] ?: return null 120 return type.cast(value) 121 } 122 copynull123 fun copy( 124 isRegularFile: Boolean = this.isRegularFile, 125 isDirectory: Boolean = this.isDirectory, 126 symlinkTarget: Path? = this.symlinkTarget, 127 size: Long? = this.size, 128 createdAtMillis: Long? = this.createdAtMillis, 129 lastModifiedAtMillis: Long? = this.lastModifiedAtMillis, 130 lastAccessedAtMillis: Long? = this.lastAccessedAtMillis, 131 extras: Map<KClass<*>, Any> = this.extras, 132 ): FileMetadata { 133 return FileMetadata( 134 isRegularFile = isRegularFile, 135 isDirectory = isDirectory, 136 symlinkTarget = symlinkTarget, 137 size = size, 138 createdAtMillis = createdAtMillis, 139 lastAccessedAtMillis = lastAccessedAtMillis, 140 lastModifiedAtMillis = lastModifiedAtMillis, 141 extras = extras, 142 ) 143 } 144 toStringnull145 override fun toString(): String { 146 val fields = mutableListOf<String>() 147 if (isRegularFile) fields += "isRegularFile" 148 if (isDirectory) fields += "isDirectory" 149 if (size != null) fields += "byteCount=$size" 150 if (createdAtMillis != null) fields += "createdAt=$createdAtMillis" 151 if (lastModifiedAtMillis != null) fields += "lastModifiedAt=$lastModifiedAtMillis" 152 if (lastAccessedAtMillis != null) fields += "lastAccessedAt=$lastAccessedAtMillis" 153 if (extras.isNotEmpty()) fields += "extras=$extras" 154 return fields.joinToString(separator = ", ", prefix = "FileMetadata(", postfix = ")") 155 } 156 } 157