1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2/****************************************************************************** 3 * 4 * Module Name: apfiles - File-related functions for acpidump utility 5 * 6 * Copyright (C) 2000 - 2023, Intel Corp. 7 * 8 *****************************************************************************/ 9 10#include "acpidump.h" 11 12/* Local prototypes */ 13 14static int ap_is_existing_file(char *pathname); 15 16/****************************************************************************** 17 * 18 * FUNCTION: ap_is_existing_file 19 * 20 * PARAMETERS: pathname - Output filename 21 * 22 * RETURN: 0 on success 23 * 24 * DESCRIPTION: Query for file overwrite if it already exists. 25 * 26 ******************************************************************************/ 27 28static int ap_is_existing_file(char *pathname) 29{ 30#if !defined(_GNU_EFI) && !defined(_EDK2_EFI) 31 struct stat stat_info; 32 int in_char; 33 34 if (!stat(pathname, &stat_info)) { 35 fprintf(stderr, 36 "Target path already exists, overwrite? [y|n] "); 37 38 in_char = fgetc(stdin); 39 if (in_char == '\n') { 40 in_char = fgetc(stdin); 41 } 42 43 if (in_char != 'y' && in_char != 'Y') { 44 return (-1); 45 } 46 } 47#endif 48 49 return (0); 50} 51 52/****************************************************************************** 53 * 54 * FUNCTION: ap_open_output_file 55 * 56 * PARAMETERS: pathname - Output filename 57 * 58 * RETURN: Open file handle 59 * 60 * DESCRIPTION: Open a text output file for acpidump. Checks if file already 61 * exists. 62 * 63 ******************************************************************************/ 64 65int ap_open_output_file(char *pathname) 66{ 67 ACPI_FILE file; 68 69 /* If file exists, prompt for overwrite */ 70 71 if (ap_is_existing_file(pathname) != 0) { 72 return (-1); 73 } 74 75 /* Point stdout to the file */ 76 77 file = fopen(pathname, "w"); 78 if (!file) { 79 fprintf(stderr, "Could not open output file: %s\n", pathname); 80 return (-1); 81 } 82 83 /* Save the file and path */ 84 85 gbl_output_file = file; 86 gbl_output_filename = pathname; 87 return (0); 88} 89 90/****************************************************************************** 91 * 92 * FUNCTION: ap_write_to_binary_file 93 * 94 * PARAMETERS: table - ACPI table to be written 95 * instance - ACPI table instance no. to be written 96 * 97 * RETURN: Status 98 * 99 * DESCRIPTION: Write an ACPI table to a binary file. Builds the output 100 * filename from the table signature. 101 * 102 ******************************************************************************/ 103 104int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance) 105{ 106 char filename[ACPI_NAMESEG_SIZE + 16]; 107 char instance_str[16]; 108 ACPI_FILE file; 109 acpi_size actual; 110 u32 table_length; 111 112 /* Obtain table length */ 113 114 table_length = ap_get_table_length(table); 115 116 /* Construct lower-case filename from the table local signature */ 117 118 if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { 119 ACPI_COPY_NAMESEG(filename, ACPI_RSDP_NAME); 120 } else { 121 ACPI_COPY_NAMESEG(filename, table->signature); 122 } 123 124 filename[0] = (char)tolower((int)filename[0]); 125 filename[1] = (char)tolower((int)filename[1]); 126 filename[2] = (char)tolower((int)filename[2]); 127 filename[3] = (char)tolower((int)filename[3]); 128 filename[ACPI_NAMESEG_SIZE] = 0; 129 130 /* Handle multiple SSDts - create different filenames for each */ 131 132 if (instance > 0) { 133 snprintf(instance_str, sizeof(instance_str), "%u", instance); 134 strcat(filename, instance_str); 135 } 136 137 strcat(filename, FILE_SUFFIX_BINARY_TABLE); 138 139 if (gbl_verbose_mode) { 140 fprintf(stderr, 141 "Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n", 142 table->signature, filename, table->length, 143 table->length); 144 } 145 146 /* Open the file and dump the entire table in binary mode */ 147 148 file = fopen(filename, "wb"); 149 if (!file) { 150 fprintf(stderr, "Could not open output file: %s\n", filename); 151 return (-1); 152 } 153 154 actual = fwrite(table, 1, table_length, file); 155 if (actual != table_length) { 156 fprintf(stderr, "Error writing binary output file: %s\n", 157 filename); 158 fclose(file); 159 return (-1); 160 } 161 162 fclose(file); 163 return (0); 164} 165 166/****************************************************************************** 167 * 168 * FUNCTION: ap_get_table_from_file 169 * 170 * PARAMETERS: pathname - File containing the binary ACPI table 171 * out_file_size - Where the file size is returned 172 * 173 * RETURN: Buffer containing the ACPI table. NULL on error. 174 * 175 * DESCRIPTION: Open a file and read it entirely into a new buffer 176 * 177 ******************************************************************************/ 178 179struct acpi_table_header *ap_get_table_from_file(char *pathname, 180 u32 *out_file_size) 181{ 182 struct acpi_table_header *buffer = NULL; 183 ACPI_FILE file; 184 u32 file_size; 185 acpi_size actual; 186 187 /* Must use binary mode */ 188 189 file = fopen(pathname, "rb"); 190 if (!file) { 191 fprintf(stderr, "Could not open input file: %s\n", pathname); 192 return (NULL); 193 } 194 195 /* Need file size to allocate a buffer */ 196 197 file_size = cm_get_file_size(file); 198 if (file_size == ACPI_UINT32_MAX) { 199 fprintf(stderr, 200 "Could not get input file size: %s\n", pathname); 201 goto cleanup; 202 } 203 204 /* Allocate a buffer for the entire file */ 205 206 buffer = ACPI_ALLOCATE_ZEROED(file_size); 207 if (!buffer) { 208 fprintf(stderr, 209 "Could not allocate file buffer of size: %u\n", 210 file_size); 211 goto cleanup; 212 } 213 214 /* Read the entire file */ 215 216 actual = fread(buffer, 1, file_size, file); 217 if (actual != file_size) { 218 fprintf(stderr, "Could not read input file: %s\n", pathname); 219 ACPI_FREE(buffer); 220 buffer = NULL; 221 goto cleanup; 222 } 223 224 *out_file_size = file_size; 225 226cleanup: 227 fclose(file); 228 return (buffer); 229} 230