xref: /aosp_15_r20/external/okio/okio/src/commonMain/kotlin/okio/FileMetadata.kt (revision f9742813c14b702d71392179818a9e591da8620c)
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