1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "hcs_file.h"
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <limits.h>
14 #include <unistd.h>
15 #include <securec.h>
16 #include "hcs_parser.h"
17 #include "hcs_mem.h"
18 #include "hcs_log.h"
19
20 static char *g_outputFileName = NULL;
21 static FILE *g_outputFile = NULL;
22 static const char *g_inputFileName = NULL;
23 static bool g_dummyOutput = false;
24 static uint32_t g_outputWriteCount = 0;
25 static struct HcsFileQueue g_inputSourceFileQueue = { 0 };
26 static struct HcsSourceName *g_sourceNameSetHead = NULL;
27
HcsSetInputFileName(const char * name)28 void HcsSetInputFileName(const char *name)
29 {
30 g_inputFileName = name;
31 }
32
HcsGetInputFileName(void)33 const char *HcsGetInputFileName(void)
34 {
35 return g_inputFileName;
36 }
37
HcsSourceNameSetPush(const char * name)38 int32_t HcsSourceNameSetPush(const char *name)
39 {
40 if (g_sourceNameSetHead == NULL) {
41 struct HcsSourceName *head = HcsMemZalloc(sizeof(*head));
42 if (head == NULL) {
43 HCS_ERROR("%s:%d OOM", __func__, __LINE__);
44 return EOOM;
45 }
46 head->name = name;
47 g_sourceNameSetHead = head;
48 return NOERR;
49 }
50
51 struct HcsSourceName *pre = g_sourceNameSetHead;
52 struct HcsSourceName *last = pre;
53 while (last != NULL) {
54 if (!strcmp(last->name, name)) {
55 return EREOPENF;
56 }
57 pre = last;
58 last = last->next;
59 }
60
61 struct HcsSourceName *newName = HcsMemZalloc(sizeof(struct HcsSourceName));
62 if (newName == NULL) {
63 HCS_ERROR("%s:%d OOM", __func__, __LINE__);
64 return EOOM;
65 }
66 newName->name = name;
67 pre->next = newName;
68 return NOERR;
69 }
70
HcsSourceNameSetFind(const char * name)71 bool HcsSourceNameSetFind(const char *name)
72 {
73 struct HcsSourceName *last = g_sourceNameSetHead;
74
75 while (last != NULL) {
76 if (!strcmp(last->name, name)) {
77 return true;
78 }
79 last = last->next;
80 }
81
82 return false;
83 }
84
HcsSourceNameSetClean(void)85 void HcsSourceNameSetClean(void)
86 {
87 struct HcsSourceName *term = g_sourceNameSetHead;
88
89 while (term != NULL) {
90 struct HcsSourceName *temp = term->next;
91 HcsMemFree((void *)term->name);
92 HcsMemFree(term);
93 term = temp;
94 }
95
96 g_sourceNameSetHead = NULL;
97 }
98
GetFileName(const char * path)99 static const char *GetFileName(const char *path)
100 {
101 if (path == NULL) {
102 return NULL;
103 }
104 int32_t length = (int32_t)strlen(path);
105 int32_t i = length - 1;
106 for (; i >= 0; --i) {
107 if (path[i] == OS_SEPARATOR) {
108 break;
109 }
110 }
111
112 return i >= 0 ? path + i + 1 : path;
113 }
114
CopyFileName(const char * path)115 static const char *CopyFileName(const char *path)
116 {
117 return strdup(GetFileName(path));
118 }
119
GetFileNameWithoutSuffix(const char * path)120 static const char *GetFileNameWithoutSuffix(const char *path)
121 {
122 char *fileNameRet = strdup(path);
123 if (fileNameRet == NULL) {
124 HCS_ERROR("oom");
125 return NULL;
126 }
127 char *it = fileNameRet + strlen(fileNameRet);
128 while (it != fileNameRet) {
129 if (*it == '.') {
130 *it = '\0';
131 break;
132 }
133 if (*it == OS_SEPARATOR) {
134 break;
135 }
136 it--;
137 }
138
139 return fileNameRet;
140 }
141
CopyAndSaveFileName(const char * filePath,char ** savedFileName,char ** savedFilePath)142 static int32_t CopyAndSaveFileName(const char *filePath, char **savedFileName, char **savedFilePath)
143 {
144 const char *fileName = CopyFileName(filePath);
145 if (fileName == NULL) {
146 return EOOM;
147 }
148
149 /* if no specified output file name, use input name */
150 if (HcsGetOutPutFilePath() == NULL && HcsSetOutPutNameWithCurrentWorkPath(fileName)) {
151 HcsMemFree((void *)fileName);
152 return EOOM;
153 }
154
155 char *path = strdup(filePath);
156 if (path == NULL || HcsSourceNameSetPush(path)) {
157 HcsMemFree((void *)fileName);
158 HcsMemFree((void *)path);
159 return EOOM;
160 }
161 *savedFileName = (char *)fileName;
162 *savedFilePath = path;
163 return NOERR;
164 }
165
HcsOpenSourceFile(const char * path,struct HcsFile ** file,const char * flag)166 int32_t HcsOpenSourceFile(const char *path, struct HcsFile **file, const char *flag)
167 {
168 char pathBuf[PATH_MAX] = {'\0'};
169 #ifdef MINGW32
170 char *realPath = _fullpath(pathBuf, path, PATH_MAX);
171 #else
172 char *realPath = realpath(path, pathBuf);
173 #endif
174 if (realPath == NULL) {
175 HCS_ERROR("failed to open source file: %s", path);
176 return EINVALF;
177 }
178
179 /* push to name set and check reopen */
180 if (HcsSourceNameSetFind(realPath)) {
181 return EREOPENF;
182 }
183
184 HCS_DEBUG("source file path: %s", realPath);
185 FILE *f = fopen(realPath, flag ? flag : "r");
186 if (f == NULL) {
187 HCS_ERROR("failed to open source file: %s", realPath);
188 return EINVALF;
189 }
190
191 char *fileName = NULL;
192 char *filePath = NULL;
193 int32_t ret = CopyAndSaveFileName(realPath, &fileName, &filePath);
194 if (ret) {
195 fclose(f);
196 return EFAIL;
197 }
198
199 struct HcsFile *sourceFile = HcsMemZalloc(sizeof(struct HcsFile));
200 if (sourceFile == NULL) {
201 HcsMemFree(fileName);
202 HcsMemFree(filePath);
203 fclose(f);
204 HCS_ERROR("oom");
205 return EOOM;
206 }
207 sourceFile->name = fileName;
208 sourceFile->fullPath = filePath;
209 sourceFile->file = f;
210 sourceFile->pos = 0;
211 *file = sourceFile;
212 return NOERR;
213 }
214
HcsSourceFileGetSize(struct HcsFile * file)215 uint64_t HcsSourceFileGetSize(struct HcsFile *file)
216 {
217 uint64_t currentPos = ftell(file->file);
218
219 fseek(file->file, 0, SEEK_END);
220 uint64_t fileSize = ftell(file->file);
221 fseek(file->file, currentPos, SEEK_SET);
222
223 return fileSize;
224 }
225
HcsSourceFileRead(struct HcsFile * file,uint8_t * out,uint32_t readSize)226 int32_t HcsSourceFileRead(struct HcsFile *file, uint8_t *out, uint32_t readSize)
227 {
228 struct HcsFile *currentSrc = file ? file : HcsSourceQueueTop();
229 if (currentSrc == NULL) {
230 HCS_ERROR("source file not valid");
231 return -EINVALF;
232 }
233
234 return fread(out, 1, readSize, currentSrc->file);
235 }
236
HcsGetSourceFilePos(struct HcsFile * file)237 uint32_t HcsGetSourceFilePos(struct HcsFile *file)
238 {
239 struct HcsFile *currentSrc = file ? file : HcsSourceQueueTop();
240 return ftell(currentSrc->file);
241 }
242
HcsCloseFile(struct HcsFile * file)243 void HcsCloseFile(struct HcsFile *file)
244 {
245 if (file == NULL) {
246 return;
247 }
248
249 fclose(file->file);
250 HcsMemFree((void *)file->name);
251 HcsMemFree(file);
252 }
253
HcsSetOutPutNameWithCurrentWorkPath(const char * name)254 int32_t HcsSetOutPutNameWithCurrentWorkPath(const char *name)
255 {
256 char outPutPath[PATH_MAX] = {0};
257 char *cwd = getcwd(outPutPath, PATH_MAX);
258 if (cwd == NULL || !strlen(cwd)) {
259 return EFAIL;
260 }
261
262 if (sprintf_s(outPutPath + strlen(outPutPath), PATH_MAX - strlen(outPutPath), "%c", OS_SEPARATOR) < 0) {
263 return EFAIL;
264 }
265
266 if (strcat_s(outPutPath, PATH_MAX, name) != EOK) {
267 return EFAIL;
268 }
269
270 return HcsSetOutPutName(outPutPath);
271 }
272
HcsSetOutPutName(const char * name)273 int32_t HcsSetOutPutName(const char *name)
274 {
275 if (g_outputFileName != NULL) {
276 HcsMemFree(g_outputFileName);
277 }
278
279 g_outputFileName = strdup(name);
280 if (g_outputFileName == NULL) {
281 HCS_ERROR("oom");
282 return EOOM;
283 }
284 #ifdef OS_WIN
285 char *temp = g_outputFileName;
286 while (*temp != '\0') {
287 if (*temp == UNIX_SEPARATOR) {
288 *temp = WIN_SEPARATOR;
289 }
290 temp++;
291 }
292 #endif
293
294 return NOERR;
295 }
296
HcsSetOutputFileSuffix(const char * suffix)297 bool HcsSetOutputFileSuffix(const char *suffix)
298 {
299 const char *fileNameBefore = g_outputFileName;
300 const char *fileNameWithoutSuffix = GetFileNameWithoutSuffix(fileNameBefore);
301 if (fileNameWithoutSuffix == NULL) {
302 return false;
303 }
304
305 uint32_t newNameSize = strlen(g_outputFileName) + strlen(suffix) + 1;
306 char *newOutputFilename = HcsMemZalloc(newNameSize);
307 if (newOutputFilename == NULL) {
308 HcsMemFree((void *)fileNameWithoutSuffix);
309 return false;
310 }
311
312 int32_t ret = strcpy_s(newOutputFilename, newNameSize, fileNameWithoutSuffix);
313 HcsMemFree((void *)fileNameWithoutSuffix);
314 if (ret) {
315 HCS_ERROR("failed to copy string");
316 HcsMemFree(newOutputFilename);
317 return false;
318 }
319 ret = strcat_s(newOutputFilename, newNameSize, suffix);
320 if (ret) {
321 HCS_ERROR("failed to copy string");
322 HcsMemFree(newOutputFilename);
323 return false;
324 }
325
326 HcsMemFree((void *)fileNameBefore);
327 g_outputFileName = newOutputFilename;
328 return true;
329 }
330
331 // return output file name only
HcsGetOutputFileName(void)332 const char *HcsGetOutputFileName(void)
333 {
334 return GetFileName(g_outputFileName);
335 }
336
HcsGetOutputFileNameWithoutSuffix(void)337 char *HcsGetOutputFileNameWithoutSuffix(void)
338 {
339 const char *fileName = HcsGetOutputFileName();
340 if (fileName == NULL) {
341 return NULL;
342 }
343
344 char *retName = strdup(fileName);
345 if (retName == NULL) {
346 HCS_ERROR("oom");
347 return NULL;
348 }
349
350 char *dot = strchr(retName, '.');
351 if (dot != NULL) {
352 *dot = '\0';
353 }
354 return retName;
355 }
356
357
358 // return full path of output file
HcsGetOutPutFilePath(void)359 const char *HcsGetOutPutFilePath(void)
360 {
361 return g_outputFileName;
362 }
363
HcsOutputNameVerify()364 bool HcsOutputNameVerify()
365 {
366 const char *fileName = g_outputFileName;
367 char lastChar = fileName[strlen(fileName) - 1];
368 if (lastChar == OS_SEPARATOR) {
369 HCS_ERROR("output name is DIR");
370 return false;
371 }
372
373 return true;
374 }
375
HcsOpenOutputFile(const char * suffix)376 struct HcsFile *HcsOpenOutputFile(const char *suffix)
377 {
378 if (!HcsOutputNameVerify()) {
379 return NULL;
380 }
381 if (!HcsSetOutputFileSuffix(suffix)) {
382 return NULL;
383 }
384 const char *outputFileName = HcsGetOutPutFilePath();
385 g_outputFile = fopen(outputFileName, "wb");
386 if (g_outputFile == NULL) {
387 HCS_ERROR("failed to open output file: %s", outputFileName);
388 return NULL;
389 }
390
391 HCS_DEBUG("Output: %s", outputFileName);
392 struct HcsFile *outputFile = HcsMemZalloc(sizeof(struct HcsFile));
393 if (outputFile == NULL) {
394 HCS_ERROR("oom");
395 fclose(g_outputFile);
396 g_outputFile = NULL;
397 return NULL;
398 }
399 outputFile->name = outputFileName;
400 outputFile->file = g_outputFile;
401 outputFile->pos = 0;
402 outputFile->fullPath = outputFileName;
403 g_outputWriteCount = 0;
404
405 return outputFile;
406 }
407
HcsCloseOutput(struct HcsFile * output)408 void HcsCloseOutput(struct HcsFile *output)
409 {
410 if (output == NULL || output->file == NULL) {
411 return;
412 }
413
414 fflush(output->file);
415 fclose(output->file);
416
417 HcsMemFree(output);
418 g_outputWriteCount = 0;
419 }
420
HcsOutputWrite(const void * buffer,uint32_t length)421 int32_t HcsOutputWrite(const void *buffer, uint32_t length)
422 {
423 g_outputWriteCount += length;
424 if (g_dummyOutput || !length) {
425 return NOERR;
426 }
427
428 uint32_t writeLen = fwrite(buffer, 1, length, g_outputFile);
429 if (writeLen != length) {
430 HCS_ERROR("failed to write output file");
431 return EOUTPUT;
432 }
433
434 return NOERR;
435 }
436
437 #define WRITE_MAX_PER_TIME 2048
438
HcsFormatOutputWrite(const char * format,...)439 int32_t HcsFormatOutputWrite(const char *format, ...)
440 {
441 if (format == NULL) {
442 return EINVALARG;
443 }
444 static char writeBuffer[WRITE_MAX_PER_TIME] = {'\0'};
445
446 va_list argList;
447
448 va_start(argList, format);
449 int length = vsprintf_s(writeBuffer, WRITE_MAX_PER_TIME, format, argList);
450 va_end(argList);
451
452 if (length < 0) {
453 HCS_ERROR("Output too long in one time");
454 return EOUTPUT;
455 }
456 return HcsOutputWrite(writeBuffer, length);
457 }
458
HcsOutputWriteAlign(const void * buffer,uint32_t length)459 int32_t HcsOutputWriteAlign(const void *buffer, uint32_t length)
460 {
461 static const uint8_t alignData[ALIGN_SIZE] = {0};
462 int32_t ret = HcsOutputWrite(buffer, length);
463 if (ret) {
464 return ret;
465 }
466 int32_t appendSize = HcsAlign(length) - length;
467 if (appendSize) {
468 ret = HcsOutputWrite(alignData, appendSize);
469 }
470 return ret;
471 }
472
HcsMockOutPut(bool dummyOutput)473 void HcsMockOutPut(bool dummyOutput)
474 {
475 g_dummyOutput = dummyOutput;
476 }
477
HcsGetOutputCurrentCount(void)478 uint32_t HcsGetOutputCurrentCount(void)
479 {
480 return g_outputWriteCount;
481 }
482
HcsResetOutputCurrentCount(void)483 void HcsResetOutputCurrentCount(void)
484 {
485 g_outputWriteCount = 0;
486 }
487
HcsSourceQueuePush(struct HcsFile * sourceFile)488 void HcsSourceQueuePush(struct HcsFile *sourceFile)
489 {
490 struct HcsFileQueue *sourceQueue = &g_inputSourceFileQueue;
491 struct HcsFile *queueLast = sourceQueue->head;
492 if (queueLast == NULL) {
493 sourceQueue->head = sourceFile;
494 sourceQueue->count = 1;
495 return;
496 }
497
498 while (queueLast->next) {
499 queueLast = queueLast->next;
500 }
501
502 queueLast->next = sourceFile;
503 sourceQueue->count++;
504 }
505
HcsSourceQueuePop(void)506 void HcsSourceQueuePop(void)
507 {
508 struct HcsFileQueue *sourceQueue = &g_inputSourceFileQueue;
509 if (sourceQueue->head == NULL) {
510 return;
511 }
512 sourceQueue->head = sourceQueue->head->next;
513 sourceQueue->count--;
514 }
515
HcsSourceQueueTop(void)516 struct HcsFile *HcsSourceQueueTop(void)
517 {
518 return g_inputSourceFileQueue.head;
519 }
520
HcsSourceQueueSize(void)521 uint32_t HcsSourceQueueSize(void)
522 {
523 return g_inputSourceFileQueue.count;
524 }
525
HcsGetCurrentSourceName(void)526 const char *HcsGetCurrentSourceName(void)
527 {
528 struct HcsFile *source = HcsSourceQueueTop();
529 return source ? source->fullPath : "";
530 }
531
HcsFileCopyDir(char * dst,uint32_t dstBufferSize,const char * fullPath)532 bool HcsFileCopyDir(char *dst, uint32_t dstBufferSize, const char *fullPath)
533 {
534 const char *c = strrchr(fullPath, OS_SEPARATOR);
535 if (c == NULL) {
536 HCS_ERROR("%s: path '%s' not include dir", __func__, fullPath);
537 return false;
538 }
539 int32_t len = (int32_t)(c - fullPath) + 1;
540 int32_t ret = strncpy_s(dst, dstBufferSize, fullPath, len);
541 if (ret) {
542 HCS_ERROR("%s:string copy fail", __func__);
543 return false;
544 }
545 dst[len] = '\0';
546
547 return true;
548 }