• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2025 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #ifndef _AEMU_DIRENT_H_
15 #define _AEMU_DIRENT_H_
16 
17 #include <sys/types.h>
18 #include <windows.h>
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 /**
25  * @file dirent.h
26  * @brief A POSIX-like dirent API implementation for Windows using the Windows API.
27  *
28  * This header provides a subset of the POSIX dirent API for Windows, allowing C and C++
29  * code to use familiar functions like opendir(), readdir(), closedir(), etc. to
30  * iterate through directory entries.
31  *
32  * @warning **Limitations:**
33  *   - **`telldir()` and `seekdir()` are minimally implemented.** `seekdir()` only supports
34  *     seeking to the beginning (loc = 0), the end (loc = -1), or forward to a specific entry
35  *     by its index (loc > 0). Seeking to arbitrary positions is implemented by iterating
36  *     through the entries, making it an **O(N)** operation in the worst case, where N is
37  *     the desired position. `telldir()` returns the index of the last entry read by `readdir()`.
38  *   - **`d_ino` is implemented using Windows file index.** It does not represent a
39  *     true POSIX inode number but can be used to identify files uniquely.
40  *   - **`d_reclen` is not supported.** The field is not present in this implementation.
41  *   - **Thread safety:** This implementation is not inherently thread-safe. Using the
42  *     same `DIR` pointer from multiple threads simultaneously can lead to undefined
43  *     behavior.
44  *
45  * @note **Windows-Specific Behavior:**
46  *   - Filenames are stored in `d_name` as **UTF-8** encoded strings.
47  *   - Extended-length paths (longer than `MAX_PATH`) are supported using the `\\?\` prefix.
48  *   - The implementation uses the Windows API (`FindFirstFileW`, `FindNextFileW`, etc.)
49  *     internally.
50  *   - The `DIR` type is an opaque pointer to an internal structure.
51  */
52 
53 /**
54  * @brief The maximum length of a file name, including the null terminator.
55  *
56  * This is set to `MAX_PATH` (260) for compatibility but internally the implementation
57  * supports extended-length paths using the `\\?\` prefix.
58  */
59 #define FILENAME_MAX MAX_PATH
60 
61 /**
62  * @brief Represents a directory entry.
63  */
64 struct dirent {
65     /**
66      * @brief File ID (from the Windows file index).
67      *
68      * This is not a true POSIX inode number but can be used as a unique file
69      * identifier on Windows. It is obtained using `GetFileInformationByHandle`
70      * and represents a file's unique ID within a volume.
71      * @warning This field might not be fully unique across different volumes or over time.
72      */
73     uint64_t d_ino;
74 
75     /**
76      * @brief Null-terminated file name in UTF-8 encoding.
77      *
78      * @warning The maximum length of the filename (excluding the null terminator)
79      * that can be stored in this field is `FILENAME_MAX`. If a filename exceeds this
80      * limit, `readdir` will skip the entry and set `errno` to `ENAMETOOLONG`.
81      */
82     char d_name[FILENAME_MAX];
83 };
84 
85 /**
86  * @brief An opaque type representing a directory stream.
87  */
88 typedef struct DIR DIR;
89 
90 
91 /**
92  * @brief Opens a directory stream for reading.
93  *
94  * @param name The path to the directory to open. This should be a UTF-8 encoded string.
95  *
96  * @return A pointer to a `DIR` structure representing the opened directory stream,
97  *         or `nullptr` if an error occurred. If `nullptr` is returned, `errno` is set
98  *         to indicate the error.
99  *
100  * @retval EACCES       Search permission is denied for the directory.
101  * @retval EMFILE       The maximum number of file descriptors are already open.
102  * @retval ENFILE       The maximum number of files are already open in the system.
103  * @retval ENOENT       The named directory does not exist or is an empty string.
104  * @retval ENOMEM       Insufficient memory is available.
105  * @retval ENOTDIR      A component of the path is not a directory.
106  * @retval EINVAL       The `name` argument is invalid (e.g., contains invalid characters).
107  */
108 DIR* opendir(const char* name);
109 
110 /**
111  * @brief Reads the next directory entry from a directory stream.
112  *
113  * @param dirp A pointer to a `DIR` structure returned by `opendir()`.
114  *
115  * @return A pointer to a `dirent` structure representing the next directory entry,
116  *         or `nullptr` if the end of the directory stream is reached or an error
117  *         occurred. If `nullptr` is returned and `errno` is not 0, an error occurred.
118  *
119  * @retval EBADF      The `dirp` argument does not refer to an open directory stream.
120  * @retval ENOMEM     Insufficient memory is available.
121  * @retval ENOENT     No more directory entries.
122  * @retval EIO        An I/O error occurred.
123  * @retval ENAMETOOLONG A filename exceeded `FILENAME_MAX`.
124  */
125 struct dirent* readdir(DIR* dirp);
126 
127 /**
128  * @brief Closes a directory stream.
129  *
130  * @param dirp A pointer to a `DIR` structure returned by `opendir()`.
131  *
132  * @return 0 on success, -1 on failure. If -1 is returned, `errno` is set to
133  *         indicate the error.
134  *
135  * @retval EBADF      The `dirp` argument does not refer to an open directory stream.
136  */
137 int closedir(DIR* dirp);
138 
139 /**
140  * @brief Resets the position of a directory stream to the beginning.
141  *
142  * @param dirp A pointer to a `DIR` structure returned by `opendir()`.
143  *
144  * @retval EBADF      The `dirp` argument does not refer to an open directory stream.
145  * @retval EIO        An I/O error occurred.
146  */
147 void rewinddir(DIR* dirp);
148 /**
149  * @brief Gets the current position of a directory stream.
150  *
151  * @param dirp A pointer to a `DIR` structure returned by `opendir()`.
152  *
153  * @return The current position of the directory stream. This is the index of the last
154  *         entry read by `readdir()`. Returns -1 if at the end of the directory stream.
155  *         If -1 is returned and `errno` is not 0, an error occurred.
156  *
157  * @retval EBADF The `dirp` argument does not refer to an open directory stream.
158  *
159  * @note   The position returned by `telldir()` is an opaque value that should only be
160  *         used in conjunction with `seekdir()`.
161  */
162 long telldir(DIR* dirp);
163 
164 /**
165  * @brief Sets the position of a directory stream.
166  *
167  * @param dirp A pointer to a `DIR` structure returned by `opendir()`.
168  * @param loc  The new position of the directory stream. The following values are supported:
169  *             - **0:** Seek to the beginning of the stream (equivalent to `rewinddir()`).
170  *             - **-1:** Seek to the end of the stream.
171  *             - **\>0:** Seek to a specific entry by its index (the value returned by `telldir()`).
172  *
173  * @retval EBADF      The `dirp` argument does not refer to an open directory stream.
174  * @retval EINVAL     The `loc` argument is invalid (e.g., negative value other than -1, or a
175  *                     value that is greater than the number of entries in the directory).
176  *
177  * @note   Seeking to arbitrary positions (other than the beginning or end) is implemented
178  *         by rewinding the directory stream and then calling `readdir()` repeatedly until
179  *         the desired position is reached.
180  * @note   **Time Complexity:**
181  *         - O(1) for `loc = 0` (rewind) and `loc = -1` (seek to end).
182  *         - O(N) for `loc > 0`, where N is the position being sought to. In the worst case,
183  *           seeking to the end of a large directory can be a slow operation.
184  */
185 void seekdir(DIR* dirp, long loc);
186 
187 #ifdef __cplusplus
188 }
189 #endif
190 
191 #endif	/* Not _AEMU_DIRENT_H_ */