1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/******************************************************************************
3 *
4 * Module Name: osunixdir - Unix directory access interfaces
5 *
6 * Copyright (C) 2000 - 2023, Intel Corp.
7 *
8 *****************************************************************************/
9
10#include <acpi/acpi.h>
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <dirent.h>
16#include <fnmatch.h>
17#include <ctype.h>
18#include <sys/stat.h>
19
20/*
21 * Allocated structure returned from os_open_directory
22 */
23typedef struct external_find_info {
24	char *dir_pathname;
25	DIR *dir_ptr;
26	char temp_buffer[256];
27	char *wildcard_spec;
28	char requested_file_type;
29
30} external_find_info;
31
32/*******************************************************************************
33 *
34 * FUNCTION:    acpi_os_open_directory
35 *
36 * PARAMETERS:  dir_pathname        - Full pathname to the directory
37 *              wildcard_spec       - string of the form "*.c", etc.
38 *
39 * RETURN:      A directory "handle" to be used in subsequent search operations.
40 *              NULL returned on failure.
41 *
42 * DESCRIPTION: Open a directory in preparation for a wildcard search
43 *
44 ******************************************************************************/
45
46void *acpi_os_open_directory(char *dir_pathname,
47			     char *wildcard_spec, char requested_file_type)
48{
49	struct external_find_info *external_info;
50	DIR *dir;
51
52	/* Allocate the info struct that will be returned to the caller */
53
54	external_info = calloc(1, sizeof(struct external_find_info));
55	if (!external_info) {
56		return (NULL);
57	}
58
59	/* Get the directory stream */
60
61	dir = opendir(dir_pathname);
62	if (!dir) {
63		fprintf(stderr, "Cannot open directory - %s\n", dir_pathname);
64		free(external_info);
65		return (NULL);
66	}
67
68	/* Save the info in the return structure */
69
70	external_info->wildcard_spec = wildcard_spec;
71	external_info->requested_file_type = requested_file_type;
72	external_info->dir_pathname = dir_pathname;
73	external_info->dir_ptr = dir;
74	return (external_info);
75}
76
77/*******************************************************************************
78 *
79 * FUNCTION:    acpi_os_get_next_filename
80 *
81 * PARAMETERS:  dir_handle          - Created via acpi_os_open_directory
82 *
83 * RETURN:      Next filename matched. NULL if no more matches.
84 *
85 * DESCRIPTION: Get the next file in the directory that matches the wildcard
86 *              specification.
87 *
88 ******************************************************************************/
89
90char *acpi_os_get_next_filename(void *dir_handle)
91{
92	struct external_find_info *external_info = dir_handle;
93	struct dirent *dir_entry;
94	char *temp_str;
95	int str_len;
96	struct stat temp_stat;
97	int err;
98
99	while ((dir_entry = readdir(external_info->dir_ptr))) {
100		if (!fnmatch
101		    (external_info->wildcard_spec, dir_entry->d_name, 0)) {
102			if (dir_entry->d_name[0] == '.') {
103				continue;
104			}
105
106			str_len = strlen(dir_entry->d_name) +
107			    strlen(external_info->dir_pathname) + 2;
108
109			temp_str = calloc(str_len, 1);
110			if (!temp_str) {
111				fprintf(stderr,
112					"Could not allocate buffer for temporary string\n");
113				return (NULL);
114			}
115
116			strcpy(temp_str, external_info->dir_pathname);
117			strcat(temp_str, "/");
118			strcat(temp_str, dir_entry->d_name);
119
120			err = stat(temp_str, &temp_stat);
121			if (err == -1) {
122				fprintf(stderr,
123					"Cannot stat file (should not happen) - %s\n",
124					temp_str);
125				free(temp_str);
126				return (NULL);
127			}
128
129			free(temp_str);
130
131			if ((S_ISDIR(temp_stat.st_mode)
132			     && (external_info->requested_file_type ==
133				 REQUEST_DIR_ONLY))
134			    || ((!S_ISDIR(temp_stat.st_mode)
135				 && external_info->requested_file_type ==
136				 REQUEST_FILE_ONLY))) {
137
138				/* copy to a temp buffer because dir_entry struct is on the stack */
139
140				strcpy(external_info->temp_buffer,
141				       dir_entry->d_name);
142				return (external_info->temp_buffer);
143			}
144		}
145	}
146
147	return (NULL);
148}
149
150/*******************************************************************************
151 *
152 * FUNCTION:    acpi_os_close_directory
153 *
154 * PARAMETERS:  dir_handle          - Created via acpi_os_open_directory
155 *
156 * RETURN:      None.
157 *
158 * DESCRIPTION: Close the open directory and cleanup.
159 *
160 ******************************************************************************/
161
162void acpi_os_close_directory(void *dir_handle)
163{
164	struct external_find_info *external_info = dir_handle;
165
166	/* Close the directory and free allocations */
167
168	closedir(external_info->dir_ptr);
169	free(dir_handle);
170}
171