]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c
ShellPkg/hexedit: Fix a read-after-free bug
[mirror_edk2.git] / ShellPkg / Library / UefiShellDebug1CommandsLib / HexEdit / FileImage.c
1 /** @file
2 Functions to deal with file buffer.
3
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved. <BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "HexEditor.h"
16
17 extern EFI_HANDLE HImageHandleBackup;
18 extern HEFI_EDITOR_BUFFER_IMAGE HBufferImage;
19
20 extern BOOLEAN HBufferImageNeedRefresh;
21 extern BOOLEAN HBufferImageOnlyLineNeedRefresh;
22 extern BOOLEAN HBufferImageMouseNeedRefresh;
23
24 extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor;
25
26 HEFI_EDITOR_FILE_IMAGE HFileImage;
27 HEFI_EDITOR_FILE_IMAGE HFileImageBackupVar;
28
29 //
30 // for basic initialization of HFileImage
31 //
32 HEFI_EDITOR_BUFFER_IMAGE HFileImageConst = {
33 NULL,
34 0,
35 FALSE
36 };
37
38 /**
39 Initialization function for HFileImage
40
41 @retval EFI_SUCCESS The operation was successful.
42 **/
43 EFI_STATUS
44 HFileImageInit (
45 VOID
46 )
47 {
48 //
49 // basically initialize the HFileImage
50 //
51 CopyMem (&HFileImage, &HFileImageConst, sizeof (HFileImage));
52
53 CopyMem (
54 &HFileImageBackupVar,
55 &HFileImageConst,
56 sizeof (HFileImageBackupVar)
57 );
58
59 return EFI_SUCCESS;
60 }
61
62 /**
63 Backup function for HFileImage. Only a few fields need to be backup.
64 This is for making the file buffer refresh as few as possible.
65
66 @retval EFI_SUCCESS The operation was successful.
67 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
68 **/
69 EFI_STATUS
70 HFileImageBackup (
71 VOID
72 )
73 {
74 SHELL_FREE_NON_NULL (HFileImageBackupVar.FileName);
75 HFileImageBackupVar.FileName = CatSPrint(NULL, L"%s", HFileImage.FileName);
76 if (HFileImageBackupVar.FileName == NULL) {
77 return EFI_OUT_OF_RESOURCES;
78 }
79
80 return EFI_SUCCESS;
81 }
82
83 /**
84 Cleanup function for HFileImage.
85
86 @retval EFI_SUCCESS The operation was successful.
87 **/
88 EFI_STATUS
89 HFileImageCleanup (
90 VOID
91 )
92 {
93
94 SHELL_FREE_NON_NULL (HFileImage.FileName);
95 SHELL_FREE_NON_NULL (HFileImageBackupVar.FileName);
96
97 return EFI_SUCCESS;
98 }
99
100 /**
101 Set FileName field in HFileImage
102
103 @param[in] Str File name to set.
104
105 @retval EFI_SUCCESS The operation was successful.
106 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
107 **/
108 EFI_STATUS
109 HFileImageSetFileName (
110 IN CONST CHAR16 *Str
111 )
112 {
113 if (Str == HFileImage.FileName) {
114 //
115 // This function might be called using HFileImage.FileName as Str.
116 // Directly return without updating HFileImage.FileName.
117 //
118 return EFI_SUCCESS;
119 }
120 //
121 // free the old file name
122 //
123 SHELL_FREE_NON_NULL (HFileImage.FileName);
124 HFileImage.FileName = AllocateCopyPool (StrSize (Str), Str);
125 if (HFileImage.FileName == NULL) {
126 return EFI_OUT_OF_RESOURCES;
127 }
128
129 return EFI_SUCCESS;
130 }
131
132 /**
133 Read a file from disk into HBufferImage.
134
135 @param[in] FileName filename to read.
136 @param[in] Recover if is for recover, no information print.
137
138 @retval EFI_SUCCESS The operation was successful.
139 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
140 @retval EFI_LOAD_ERROR A load error occured.
141 **/
142 EFI_STATUS
143 HFileImageRead (
144 IN CONST CHAR16 *FileName,
145 IN BOOLEAN Recover
146 )
147 {
148 HEFI_EDITOR_LINE *Line;
149 UINT8 *Buffer;
150 CHAR16 *UnicodeBuffer;
151 EFI_STATUS Status;
152
153 //
154 // variable initialization
155 //
156 Line = NULL;
157
158 //
159 // in this function, when you return error ( except EFI_OUT_OF_RESOURCES )
160 // you should set status string
161 // since this function maybe called before the editorhandleinput loop
162 // so any error will cause editor return
163 // so if you want to print the error status
164 // you should set the status string
165 //
166 Status = ReadFileIntoBuffer (FileName, (VOID**)&Buffer, &HFileImage.Size, &HFileImage.ReadOnly);
167 //
168 // NULL pointer is only also a failure for a non-zero file size.
169 //
170 if ((EFI_ERROR(Status)) || (Buffer == NULL && HFileImage.Size != 0)) {
171 UnicodeBuffer = CatSPrint(NULL, L"Read error on file %s: %r", FileName, Status);
172 if (UnicodeBuffer == NULL) {
173 SHELL_FREE_NON_NULL(Buffer);
174 return EFI_OUT_OF_RESOURCES;
175 }
176
177 StatusBarSetStatusString (UnicodeBuffer);
178 FreePool (UnicodeBuffer);
179 return EFI_OUT_OF_RESOURCES;
180 }
181
182 HFileImageSetFileName (FileName);
183
184 //
185 // free the old lines
186 //
187 HBufferImageFree ();
188
189 Status = HBufferImageBufferToList (Buffer, HFileImage.Size);
190 SHELL_FREE_NON_NULL (Buffer);
191 if (EFI_ERROR (Status)) {
192 StatusBarSetStatusString (L"Error parsing file.");
193 return Status;
194 }
195
196 HBufferImage.DisplayPosition.Row = 2;
197 HBufferImage.DisplayPosition.Column = 10;
198 HBufferImage.MousePosition.Row = 2;
199 HBufferImage.MousePosition.Column = 10;
200 HBufferImage.LowVisibleRow = 1;
201 HBufferImage.HighBits = TRUE;
202 HBufferImage.BufferPosition.Row = 1;
203 HBufferImage.BufferPosition.Column = 1;
204 HBufferImage.BufferType = FileTypeFileBuffer;
205
206 if (!Recover) {
207 UnicodeBuffer = CatSPrint(NULL, L"%d Lines Read", HBufferImage.NumLines);
208 if (UnicodeBuffer == NULL) {
209 SHELL_FREE_NON_NULL(Buffer);
210 return EFI_OUT_OF_RESOURCES;
211 }
212
213 StatusBarSetStatusString (UnicodeBuffer);
214 FreePool (UnicodeBuffer);
215
216 HMainEditor.SelectStart = 0;
217 HMainEditor.SelectEnd = 0;
218 }
219
220 //
221 // has line
222 //
223 if (HBufferImage.Lines != 0) {
224 HBufferImage.CurrentLine = CR (HBufferImage.ListHead->ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
225 } else {
226 //
227 // create a dummy line
228 //
229 Line = HBufferImageCreateLine ();
230 if (Line == NULL) {
231 SHELL_FREE_NON_NULL(Buffer);
232 return EFI_OUT_OF_RESOURCES;
233 }
234
235 HBufferImage.CurrentLine = Line;
236 }
237
238 HBufferImage.Modified = FALSE;
239 HBufferImageNeedRefresh = TRUE;
240 HBufferImageOnlyLineNeedRefresh = FALSE;
241 HBufferImageMouseNeedRefresh = TRUE;
242
243 return EFI_SUCCESS;
244 }
245
246 /**
247 Save lines in HBufferImage to disk.
248
249 @param[in] FileName The file name.
250
251 @retval EFI_SUCCESS The operation was successful.
252 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
253 @retval EFI_LOAD_ERROR A load error occured.
254 **/
255 EFI_STATUS
256 HFileImageSave (
257 IN CHAR16 *FileName
258 )
259 {
260
261 LIST_ENTRY *Link;
262 HEFI_EDITOR_LINE *Line;
263 CHAR16 *Str;
264 EFI_STATUS Status;
265 UINTN NumLines;
266 SHELL_FILE_HANDLE FileHandle;
267 UINTN TotalSize;
268 UINT8 *Buffer;
269 UINT8 *Ptr;
270 EDIT_FILE_TYPE BufferTypeBackup;
271
272 BufferTypeBackup = HBufferImage.BufferType;
273 HBufferImage.BufferType = FileTypeFileBuffer;
274
275 //
276 // if is the old file
277 //
278 if (HFileImage.FileName != NULL && FileName != NULL && StrCmp (FileName, HFileImage.FileName) == 0) {
279 //
280 // check whether file exists on disk
281 //
282 if (ShellIsFile(FileName) == EFI_SUCCESS) {
283 //
284 // current file exists on disk
285 // so if not modified, then not save
286 //
287 if (HBufferImage.Modified == FALSE) {
288 return EFI_SUCCESS;
289 }
290 //
291 // if file is read-only, set error
292 //
293 if (HFileImage.ReadOnly == TRUE) {
294 StatusBarSetStatusString (L"Read Only File Can Not Be Saved");
295 return EFI_SUCCESS;
296 }
297 }
298 }
299
300 if (ShellIsDirectory(FileName) == EFI_SUCCESS) {
301 StatusBarSetStatusString (L"Directory Can Not Be Saved");
302 return EFI_LOAD_ERROR;
303 }
304
305 Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);
306
307 if (!EFI_ERROR (Status)) {
308 //
309 // the file exits, delete it
310 //
311 Status = ShellDeleteFile (&FileHandle);
312 if (EFI_ERROR (Status) || Status == EFI_WARN_DELETE_FAILURE) {
313 StatusBarSetStatusString (L"Write File Failed");
314 return EFI_LOAD_ERROR;
315 }
316 }
317
318 //
319 // write all the lines back to disk
320 //
321 NumLines = 0;
322 TotalSize = 0;
323 for (Link = HBufferImage.ListHead->ForwardLink; Link != HBufferImage.ListHead; Link = Link->ForwardLink) {
324 Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
325
326 if (Line->Size != 0) {
327 TotalSize += Line->Size;
328 }
329 //
330 // end of if Line -> Size != 0
331 //
332 NumLines++;
333 }
334 //
335 // end of for Link
336 //
337 Buffer = AllocateZeroPool (TotalSize);
338 if (Buffer == NULL) {
339 return EFI_OUT_OF_RESOURCES;
340 }
341
342 Ptr = Buffer;
343 for (Link = HBufferImage.ListHead->ForwardLink; Link != HBufferImage.ListHead; Link = Link->ForwardLink) {
344 Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
345
346 if (Line->Size != 0) {
347 CopyMem (Ptr, Line->Buffer, Line->Size);
348 Ptr += Line->Size;
349 }
350 //
351 // end of if Line -> Size != 0
352 //
353 }
354
355
356 Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
357
358 if (EFI_ERROR (Status)) {
359 StatusBarSetStatusString (L"Create File Failed");
360 return EFI_LOAD_ERROR;
361 }
362
363 Status = ShellWriteFile (FileHandle, &TotalSize, Buffer);
364 FreePool (Buffer);
365 if (EFI_ERROR (Status)) {
366 ShellDeleteFile (&FileHandle);
367 return EFI_LOAD_ERROR;
368 }
369
370 ShellCloseFile(&FileHandle);
371
372 HBufferImage.Modified = FALSE;
373
374 //
375 // set status string
376 //
377 Str = CatSPrint(NULL, L"%d Lines Wrote", NumLines);
378 StatusBarSetStatusString (Str);
379 FreePool (Str);
380
381 //
382 // now everything is ready , you can set the new file name to filebuffer
383 //
384 if ((BufferTypeBackup != FileTypeFileBuffer && FileName != NULL) ||
385 (FileName != NULL && HFileImage.FileName != NULL && StringNoCaseCompare (&FileName, &HFileImage.FileName) != 0)){
386 //
387 // not the same
388 //
389 HFileImageSetFileName (FileName);
390 if (HFileImage.FileName == NULL) {
391 return EFI_OUT_OF_RESOURCES;
392 }
393 }
394
395 HFileImage.ReadOnly = FALSE;
396
397 return EFI_SUCCESS;
398 }