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  */
23 typedef 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 
46 void *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 
90 char *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 
162 void 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