blob: 04e40a1ec1d3f80af32685eefc4497bd29048b26 [file] [log] [blame]
// Copyright (C) 2025 The Android Open Source 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.
#ifndef _AEMU_DIRENT_H_
#define _AEMU_DIRENT_H_
#include <sys/types.h>
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file dirent.h
* @brief A POSIX-like dirent API implementation for Windows using the Windows API.
*
* This header provides a subset of the POSIX dirent API for Windows, allowing C and C++
* code to use familiar functions like opendir(), readdir(), closedir(), etc. to
* iterate through directory entries.
*
* @warning **Limitations:**
* - **`telldir()` and `seekdir()` are minimally implemented.** `seekdir()` only supports
* seeking to the beginning (loc = 0), the end (loc = -1), or forward to a specific entry
* by its index (loc > 0). Seeking to arbitrary positions is implemented by iterating
* through the entries, making it an **O(N)** operation in the worst case, where N is
* the desired position. `telldir()` returns the index of the last entry read by `readdir()`.
* - **`d_ino` is implemented using Windows file index.** It does not represent a
* true POSIX inode number but can be used to identify files uniquely.
* - **`d_reclen` is not supported.** The field is not present in this implementation.
* - **Thread safety:** This implementation is not inherently thread-safe. Using the
* same `DIR` pointer from multiple threads simultaneously can lead to undefined
* behavior.
*
* @note **Windows-Specific Behavior:**
* - Filenames are stored in `d_name` as **UTF-8** encoded strings.
* - Extended-length paths (longer than `MAX_PATH`) are supported using the `\\?\` prefix.
* - The implementation uses the Windows API (`FindFirstFileW`, `FindNextFileW`, etc.)
* internally.
* - The `DIR` type is an opaque pointer to an internal structure.
*/
/**
* @brief The maximum length of a file name, including the null terminator.
*
* This is set to `MAX_PATH` (260) for compatibility but internally the implementation
* supports extended-length paths using the `\\?\` prefix.
*/
#define FILENAME_MAX MAX_PATH
/**
* @brief Represents a directory entry.
*/
struct dirent {
/**
* @brief File ID (from the Windows file index).
*
* This is not a true POSIX inode number but can be used as a unique file
* identifier on Windows. It is obtained using `GetFileInformationByHandle`
* and represents a file's unique ID within a volume.
* @warning This field might not be fully unique across different volumes or over time.
*/
uint64_t d_ino;
/**
* @brief Null-terminated file name in UTF-8 encoding.
*
* @warning The maximum length of the filename (excluding the null terminator)
* that can be stored in this field is `FILENAME_MAX`. If a filename exceeds this
* limit, `readdir` will skip the entry and set `errno` to `ENAMETOOLONG`.
*/
char d_name[FILENAME_MAX];
};
/**
* @brief An opaque type representing a directory stream.
*/
typedef struct DIR DIR;
/**
* @brief Opens a directory stream for reading.
*
* @param name The path to the directory to open. This should be a UTF-8 encoded string.
*
* @return A pointer to a `DIR` structure representing the opened directory stream,
* or `nullptr` if an error occurred. If `nullptr` is returned, `errno` is set
* to indicate the error.
*
* @retval EACCES Search permission is denied for the directory.
* @retval EMFILE The maximum number of file descriptors are already open.
* @retval ENFILE The maximum number of files are already open in the system.
* @retval ENOENT The named directory does not exist or is an empty string.
* @retval ENOMEM Insufficient memory is available.
* @retval ENOTDIR A component of the path is not a directory.
* @retval EINVAL The `name` argument is invalid (e.g., contains invalid characters).
*/
DIR* opendir(const char* name);
/**
* @brief Reads the next directory entry from a directory stream.
*
* @param dirp A pointer to a `DIR` structure returned by `opendir()`.
*
* @return A pointer to a `dirent` structure representing the next directory entry,
* or `nullptr` if the end of the directory stream is reached or an error
* occurred. If `nullptr` is returned and `errno` is not 0, an error occurred.
*
* @retval EBADF The `dirp` argument does not refer to an open directory stream.
* @retval ENOMEM Insufficient memory is available.
* @retval ENOENT No more directory entries.
* @retval EIO An I/O error occurred.
* @retval ENAMETOOLONG A filename exceeded `FILENAME_MAX`.
*/
struct dirent* readdir(DIR* dirp);
/**
* @brief Closes a directory stream.
*
* @param dirp A pointer to a `DIR` structure returned by `opendir()`.
*
* @return 0 on success, -1 on failure. If -1 is returned, `errno` is set to
* indicate the error.
*
* @retval EBADF The `dirp` argument does not refer to an open directory stream.
*/
int closedir(DIR* dirp);
/**
* @brief Resets the position of a directory stream to the beginning.
*
* @param dirp A pointer to a `DIR` structure returned by `opendir()`.
*
* @retval EBADF The `dirp` argument does not refer to an open directory stream.
* @retval EIO An I/O error occurred.
*/
void rewinddir(DIR* dirp);
/**
* @brief Gets the current position of a directory stream.
*
* @param dirp A pointer to a `DIR` structure returned by `opendir()`.
*
* @return The current position of the directory stream. This is the index of the last
* entry read by `readdir()`. Returns -1 if at the end of the directory stream.
* If -1 is returned and `errno` is not 0, an error occurred.
*
* @retval EBADF The `dirp` argument does not refer to an open directory stream.
*
* @note The position returned by `telldir()` is an opaque value that should only be
* used in conjunction with `seekdir()`.
*/
long telldir(DIR* dirp);
/**
* @brief Sets the position of a directory stream.
*
* @param dirp A pointer to a `DIR` structure returned by `opendir()`.
* @param loc The new position of the directory stream. The following values are supported:
* - **0:** Seek to the beginning of the stream (equivalent to `rewinddir()`).
* - **-1:** Seek to the end of the stream.
* - **\>0:** Seek to a specific entry by its index (the value returned by `telldir()`).
*
* @retval EBADF The `dirp` argument does not refer to an open directory stream.
* @retval EINVAL The `loc` argument is invalid (e.g., negative value other than -1, or a
* value that is greater than the number of entries in the directory).
*
* @note Seeking to arbitrary positions (other than the beginning or end) is implemented
* by rewinding the directory stream and then calling `readdir()` repeatedly until
* the desired position is reached.
* @note **Time Complexity:**
* - O(1) for `loc = 0` (rewind) and `loc = -1` (seek to end).
* - O(N) for `loc > 0`, where N is the position being sought to. In the worst case,
* seeking to the end of a large directory can be a slow operation.
*/
void seekdir(DIR* dirp, long loc);
#ifdef __cplusplus
}
#endif
#endif /* Not _AEMU_DIRENT_H_ */