1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*******************************************************************************
3 * Copyright 2018-2019, Fraunhofer SIT sponsored by Infineon Technologies AG
4 * All rights reserved.
5 *******************************************************************************/
6
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <poll.h>
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <dirent.h>
20 #include <limits.h>
21 /* Need for some libc-versions */
22 #if !defined(__FreeBSD__) && !defined(__DragonFly__)
23 #include <malloc.h>
24 #endif
25
26 #include "tss2_common.h"
27 #include "ifapi_io.h"
28 #include "ifapi_helpers.h"
29 #include "ifapi_macros.h"
30 #define LOGMODULE fapi
31 #include "util/log.h"
32 #include "util/aux_util.h"
33
34 /** Start reading a file's complete content into memory in an asynchronous way.
35 *
36 * @param[in,out] io The input/output context being used for file I/O.
37 * @param[in] filename The name of the file to be read into memory.
38 * @retval TSS2_RC_SUCCESS: if the function call was a success.
39 * @retval TSS2_FAPI_RC_IO_ERROR: if an I/O error was encountered; such as the file was not found.
40 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
41 */
42 TSS2_RC
ifapi_io_read_async(struct IFAPI_IO * io,const char * filename)43 ifapi_io_read_async(
44 struct IFAPI_IO *io,
45 const char *filename)
46 {
47 struct stat statbuf;
48
49 if (stat(filename, &statbuf) == -1) {
50 LOG_ERROR("File \"%s\" not found.", filename);
51 return TSS2_FAPI_RC_IO_ERROR;
52 }
53
54 /* Check whether file is a directory. */
55 if (S_ISDIR(statbuf.st_mode)) {
56 LOG_ERROR("\"%s\" is a directory.", filename);
57 return TSS2_FAPI_RC_IO_ERROR;
58 }
59
60 if (io->char_rbuffer) {
61 LOG_ERROR("rbuffer still in use; maybe use of old API.");
62 return TSS2_FAPI_RC_IO_ERROR;
63 }
64
65 if (stat(filename, &statbuf) != 0) {
66 LOG_ERROR("stat failed for \"%s\".", filename);
67 fclose(io->stream);
68 return TSS2_FAPI_RC_IO_ERROR;
69 }
70
71 io->stream = fopen(filename, "rt");
72 if (io->stream == NULL) {
73 LOG_ERROR("Open file \"%s\": %s", filename, strerror(errno));
74 return TSS2_FAPI_RC_IO_ERROR;
75 }
76
77 /* Locking the file. Lock will be release upon close */
78 if (lockf(fileno(io->stream), F_TLOCK, 0) == -1 && errno == EAGAIN) {
79 LOG_ERROR("File %s currently locked.", filename);
80 fclose(io->stream);
81 return TSS2_FAPI_RC_IO_ERROR;
82 }
83
84 if (fseek(io->stream, 0L, SEEK_END) == -1) {
85 LOG_ERROR("fseek failed for \"%s\".", filename);
86 fclose(io->stream);
87 return TSS2_FAPI_RC_IO_ERROR;
88 };
89 long length = ftell(io->stream);
90 if (length == -1 || length == LONG_MAX) {
91 LOG_ERROR("ftell failed for \"%s\".", filename);
92 fclose(io->stream);
93 return TSS2_FAPI_RC_IO_ERROR;
94 };
95 fclose(io->stream);
96
97 io->stream = fopen(filename, "rt");
98 if (io->stream == NULL) {
99 LOG_ERROR("Open file \"%s\": %s", filename, strerror(errno));
100 return TSS2_FAPI_RC_IO_ERROR;
101 }
102 io->char_rbuffer = malloc (length + 1);
103 if (io->char_rbuffer == NULL) {
104 fclose(io->stream);
105 io->stream = NULL;
106 LOG_ERROR("Memory could not be allocated. %li bytes requested", length + 1);
107 return TSS2_FAPI_RC_MEMORY;
108 }
109
110 int flags = fcntl(fileno(io->stream), F_GETFL, 0);
111 if (flags == -1) {
112 SAFE_FREE(io->char_rbuffer);
113 LOG_ERROR("fcntl failed with %d", errno);
114 return TSS2_FAPI_RC_IO_ERROR;
115 }
116 if (fcntl(fileno(io->stream), F_SETFL, flags | O_NONBLOCK) == -1) {
117 SAFE_FREE(io->char_rbuffer);
118 LOG_ERROR("fcntl failed with %d", errno);
119 return TSS2_FAPI_RC_IO_ERROR;
120 }
121
122 io->buffer_length = length;
123 io->buffer_idx = 0;
124 io->char_rbuffer[length] = '\0';
125
126 return TSS2_RC_SUCCESS;
127 }
128
129 /** Finish reading a file's complete content into memory in an asynchronous way.
130 *
131 * This function needs to be called repeatedly until it does not return TSS2_FAPI_RC_TRY_AGAIN.
132 *
133 * @param[in,out] io The input/output context being used for file I/O.
134 * @param[out] buffer The data that was read from file. (callee-allocated; use free())
135 * @param[out] length The length of the data that was read from file.
136 * @retval TSS2_RC_SUCCESS: if the function call was a success.
137 * @retval TSS2_FAPI_RC_IO_ERROR: if an I/O error was encountered; such as the file was not found.
138 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet complete.
139 * Call this function again later.
140 */
141 TSS2_RC
ifapi_io_read_finish(struct IFAPI_IO * io,uint8_t ** buffer,size_t * length)142 ifapi_io_read_finish(
143 struct IFAPI_IO *io,
144 uint8_t **buffer,
145 size_t *length)
146 {
147 io->pollevents = POLLIN;
148 if (_ifapi_io_retry-- > 0)
149 return TSS2_FAPI_RC_TRY_AGAIN;
150 else
151 _ifapi_io_retry = _IFAPI_IO_RETRIES;
152
153 ssize_t ret = read(fileno(io->stream),
154 &io->char_rbuffer[io->buffer_idx],
155 io->buffer_length - io->buffer_idx);
156 if (ret < 0 && (errno == EINTR || errno == EAGAIN))
157 return TSS2_FAPI_RC_TRY_AGAIN;
158
159 if (ret < 0) {
160 LOG_ERROR("Error reading from file: %i.", errno);
161 fclose(io->stream);
162 io->pollevents = 0;
163 SAFE_FREE(io->char_rbuffer);
164 return TSS2_FAPI_RC_IO_ERROR;
165 }
166
167 io->pollevents = 0;
168 io->buffer_idx += ret;
169 if (io->buffer_idx < io->buffer_length)
170 return TSS2_FAPI_RC_TRY_AGAIN;
171
172 fclose(io->stream);
173
174 if (!buffer) {
175 LOG_WARNING("The old file read API is still being used");
176 return TSS2_RC_SUCCESS;
177 }
178 *buffer = (uint8_t *)io->char_rbuffer;
179 io->char_rbuffer = NULL;
180
181 if (length)
182 *length = io->buffer_length;
183
184 return TSS2_RC_SUCCESS;
185 }
186
187 /** Start writing a buffer into a file in an asynchronous way.
188 *
189 * @param[in,out] io The input/output context being used for file I/O.
190 * @param[in] filename The name of the file to be read into memory.
191 * @param[in] buffer The buffer to be written.
192 * @param[in] length The number of bytes to be written.
193 * @retval TSS2_RC_SUCCESS: if the function call was a success.
194 * @retval TSS2_FAPI_RC_IO_ERROR: if an I/O error was encountered; such as the file was not found.
195 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
196 */
197 TSS2_RC
ifapi_io_write_async(struct IFAPI_IO * io,const char * filename,const uint8_t * buffer,size_t length)198 ifapi_io_write_async(
199 struct IFAPI_IO *io,
200 const char *filename,
201 const uint8_t *buffer,
202 size_t length)
203 {
204 TSS2_RC r;
205
206 if (io->char_rbuffer) {
207 LOG_ERROR("rbuffer still in use; maybe use of old API.");
208 return TSS2_FAPI_RC_IO_ERROR;
209 }
210
211 io->buffer_length = length;
212 io->buffer_idx = 0;
213 io->char_rbuffer = malloc(length);
214 if (io->char_rbuffer == NULL) {
215 LOG_ERROR("Memory could not be allocated. %zi bytes requested", length);
216 return TSS2_FAPI_RC_MEMORY;
217 }
218 memcpy(io->char_rbuffer, buffer, length);
219
220 io->stream = fopen(filename, "wt");
221 if (io->stream == NULL) {
222 goto_error(r, TSS2_FAPI_RC_IO_ERROR,
223 "Open file \"%s\" for writing: %s", error, filename,
224 strerror(errno));
225 }
226 /* Locking the file. Lock will be release upon close */
227 if (lockf(fileno(io->stream), F_TLOCK, 0) == -1 && errno == EAGAIN) {
228 fclose(io->stream);
229 goto_error(r, TSS2_FAPI_RC_IO_ERROR,
230 "File %s currently locked.", error, filename);
231 }
232
233 /* Use non blocking IO, so asynchronous write will be needed */
234 int rc, flags = fcntl(fileno(io->stream), F_GETFL, 0);
235 if (flags < 0) {
236 fclose(io->stream);
237 goto_error(r, TSS2_FAPI_RC_IO_ERROR,
238 "fcntl failed with %d", error, errno);
239 }
240 rc = fcntl(fileno(io->stream), F_SETFL, flags | O_NONBLOCK);
241 if (rc < 0) {
242 fclose(io->stream);
243 goto_error(r, TSS2_FAPI_RC_IO_ERROR,
244 "fcntl failed with %d", error, errno);
245 }
246 return TSS2_RC_SUCCESS;
247
248 error:
249 SAFE_FREE(io->char_rbuffer);
250 return r;
251 }
252
253 /** Finish writing a buffer into a file in an asynchronous way.
254 *
255 * This function needs to be called repeatedly until it does not return TSS2_FAPI_RC_TRY_AGAIN.
256 *
257 * @param[in,out] io The input/output context being used for file I/O.
258 * @retval TSS2_RC_SUCCESS: if the function call was a success.
259 * @retval TSS2_FAPI_RC_IO_ERROR: if an I/O error was encountered; such as the file was not found.
260 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet complete.
261 * Call this function again later.
262 */
263 TSS2_RC
ifapi_io_write_finish(struct IFAPI_IO * io)264 ifapi_io_write_finish(
265 struct IFAPI_IO *io)
266 {
267 io->pollevents = POLLOUT;
268 if (_ifapi_io_retry-- > 0)
269 return TSS2_FAPI_RC_TRY_AGAIN;
270 else
271 _ifapi_io_retry = _IFAPI_IO_RETRIES;
272
273 ssize_t ret = write(fileno(io->stream),
274 &io->char_rbuffer[io->buffer_idx],
275 io->buffer_length - io->buffer_idx);
276 if (ret < 0 && (errno == EINTR || errno == EAGAIN))
277 return TSS2_FAPI_RC_TRY_AGAIN;
278
279 if (ret < 0) {
280 LOG_ERROR("Error writing to file: %i.", errno);
281 fclose(io->stream);
282 io->pollevents = 0;
283 SAFE_FREE(io->char_rbuffer);
284 return TSS2_FAPI_RC_IO_ERROR;
285 }
286
287 io->pollevents = 0;
288 io->buffer_idx += ret;
289 if (io->buffer_idx < io->buffer_length)
290 return TSS2_FAPI_RC_TRY_AGAIN;
291
292 SAFE_FREE(io->char_rbuffer);
293 fclose(io->stream);
294
295 return TSS2_RC_SUCCESS;
296 }
297
298 /** Check whether a file is writeable.
299 *
300 * @param[in] file The name of the fileto be checked.
301 * @retval TSS2_RC_SUCCESS if the directories existed or were successfully created
302 * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error occurred
303 */
304 TSS2_RC
ifapi_io_check_file_writeable(const char * file)305 ifapi_io_check_file_writeable(
306 const char *file)
307 {
308 /* Check access rights to file */
309 if (access(file, FAPI_WRITE)) {
310 return_error2(TSS2_FAPI_RC_IO_ERROR, "File %s is not writeable.", file);
311 }
312 return TSS2_RC_SUCCESS;
313 }
314
315 /** Check for the existence of a directory and create it if it does not yet exist.
316 *
317 * @param[in] dirname The name of the directory to be checked / created
318 * @retval TSS2_RC_SUCCESS if the directories existed or were successfully created
319 * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error occurred
320 * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
321 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
322 * the function.
323 */
324 TSS2_RC
ifapi_io_check_create_dir(const char * dirname,int mode)325 ifapi_io_check_create_dir(
326 const char *dirname, int mode)
327 {
328 TSS2_RC r;
329 struct stat fbuffer;
330
331 /* Check existence of dirname and try to create it otherwise */
332 if (stat(dirname, &fbuffer)) {
333 LOG_WARNING("Directory %s does not exist, creating", dirname);
334
335 r = ifapi_create_dirs("", dirname);
336 return_if_error2(r, "Directory %s can't be created.", dirname);
337
338 LOG_DEBUG("Created directory: %s", dirname);
339 }
340
341 /* Check access rights to dirname */
342 if (access(dirname, mode)) {
343 return_error2(TSS2_FAPI_RC_IO_ERROR, "Directory %s is not %s.", dirname,
344 (mode == FAPI_WRITE) ? "writeable" : "readable");
345 }
346
347 return TSS2_RC_SUCCESS;
348 }
349
350 /** Remove a file.
351 *
352 * @param[in] file The absolute path of the file to be removed.
353 * @retval TSS2_RC_SUCCESS If the file was successfully removed
354 * @retval TSS2_FAPI_RC_IO_ERROR If the file could not be removed.
355 */
356 TSS2_RC
ifapi_io_remove_file(const char * file)357 ifapi_io_remove_file(const char *file)
358 {
359 if (remove(file) != 0) {
360 LOG_ERROR("File: %s can't be deleted.", file);
361 return TSS2_FAPI_RC_IO_ERROR;
362 }
363 return TSS2_RC_SUCCESS;
364 }
365
366 /** Remove a directory recursively; i.e. including its subdirectories.
367 *
368 * @param[in] dirname The directory to be removed
369 * @param[in] keystore_path The path of the current keystore directory, which should
370 * not be removed.
371 * @param[in] sub_dir The path of a sub directory of the keystore directory,
372 * which should not be removed (can be NULL, if not needed).
373 * It must start with a slash.
374 * @retval TSS2_RC_SUCCESS if the directories were successfully removed
375 * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error occurred
376 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
377 */
378 TSS2_RC
ifapi_io_remove_directories(const char * dirname,const char * keystore_path,const char * sub_dir)379 ifapi_io_remove_directories(
380 const char *dirname,
381 const char *keystore_path,
382 const char *sub_dir)
383 {
384 DIR *dir;
385 struct dirent *entry;
386 TSS2_RC r;
387 char *path;
388 size_t len_kstore_path, len_dir_path, diff_len, pos;
389
390 LOG_TRACE("Removing directory: %s", dirname);
391
392 if (!(dir = opendir(dirname))) {
393 return_error2(TSS2_FAPI_RC_IO_ERROR, "Could not open directory: %s",
394 dirname);
395 }
396
397 /* Iterating through the list of entries inside the directory. */
398 while ((entry = readdir(dir)) != NULL) {
399 LOG_TRACE("Deleting directory entry %s", entry->d_name);
400
401 /* Entries . and .. are obviously ignored */
402 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
403 continue;
404
405 /* If an entry is a directory then we call ourself recursively to remove those */
406 if (entry->d_type == DT_DIR) {
407 r = ifapi_asprintf(&path, "%s/%s", dirname, entry->d_name);
408 goto_if_error(r, "Out of memory", error_cleanup);
409
410 r = ifapi_io_remove_directories(path, keystore_path, sub_dir);
411 free(path);
412 goto_if_error(r, "remove directories.", error_cleanup);
413
414 continue;
415 }
416
417 /* If an entry is a file or symlink or anything else, we remove it */
418 r = ifapi_asprintf(&path, "%s/%s", dirname, entry->d_name);
419 goto_if_error(r, "Out of memory", error_cleanup);
420
421 LOG_WARNING("Removing: %s", path);
422
423 if (remove(path) != 0) {
424 free(path);
425 closedir(dir);
426 return_error2(TSS2_FAPI_RC_IO_ERROR, "Removing file");
427 }
428
429 free(path);
430 }
431 closedir(dir);
432
433 /* Check whether current directory is a keystore directory. These directories should
434 not be deleted. */
435 len_kstore_path = strlen(keystore_path);
436 len_dir_path = strlen(dirname);
437 diff_len = len_dir_path - len_kstore_path;
438 if (diff_len > 1) {
439 pos = strlen(keystore_path);
440 if (keystore_path[pos - 1] == '/')
441 pos += 1;
442 /* Check whether current sub_dir of keystore path should not be deleted. */
443 if (!sub_dir || strcmp(&dirname[pos], sub_dir) != 0) {
444 if (rmdir(dirname) != 0)
445 return_error2(TSS2_FAPI_RC_IO_ERROR, "Removing directory: %s", dirname);
446 }
447 }
448
449 LOG_TRACE("SUCCESS");
450 return TSS2_RC_SUCCESS;
451
452 error_cleanup:
453 closedir(dir);
454 return r;
455 }
456
457 /** Enumerate the list of files in a directory.
458 *
459 * Enumerage the regular files (no directories, symlinks etc) from a given directory.
460 *
461 * @param[in] dirname The directory to list files from.
462 * @param[out] files The list of file names.
463 * @param[out] numfiles The size of files.
464 * @retval TSS2_RC_SUCCESS if the directories were successfully removed
465 * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error occurred
466 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
467 * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
468 */
469 TSS2_RC
ifapi_io_dirfiles(const char * dirname,char *** files,size_t * numfiles)470 ifapi_io_dirfiles(
471 const char *dirname,
472 char ***files,
473 size_t *numfiles)
474 {
475 DIR *dir;
476 struct dirent *entry;
477 char **paths;
478 size_t numpaths = 0;
479 check_not_null(dirname);
480 check_not_null(files);
481 check_not_null(numfiles);
482
483 LOG_TRACE("List directory: %s", dirname);
484
485 paths = calloc(10, sizeof(*paths));
486 check_oom(paths);
487
488 if (!(dir = opendir(dirname))) {
489 free(paths);
490 return_error2(TSS2_FAPI_RC_IO_ERROR, "Could not open directory: %s",
491 dirname);
492 }
493
494 /* Iterating through the list of entries inside the directory. */
495 while ((entry = readdir(dir)) != NULL) {
496 LOG_TRACE("Looking at %s", entry->d_name);
497 if (entry->d_type != DT_REG)
498 continue;
499
500 if (numpaths % 10 == 9) {
501 #ifdef HAVE_REALLOCARRAY
502 paths = reallocarray(paths, numpaths + 10, sizeof(*paths));
503 #else /* HAVE_REALLOCARRAY */
504 paths = realloc(paths, (numpaths + 10) * sizeof(*paths));
505 #endif /* HAVE_REALLOCARRAY */
506 if (!paths)
507 closedir(dir);
508 check_oom(paths);
509 }
510
511 paths[numpaths] = strdup(entry->d_name);
512 if (!paths[numpaths])
513 goto error_oom;
514
515 LOG_TRACE("Added %s to the list at index %zi", paths[numpaths], numpaths);
516 numpaths += 1;
517 }
518 closedir(dir);
519
520 *files = paths;
521 *numfiles = numpaths;
522
523 return TSS2_RC_SUCCESS;
524
525 error_oom:
526 closedir(dir);
527 LOG_ERROR("Out of memory");
528 for (size_t i = 0; i < numpaths; i++)
529 free(paths[i]);
530 free(paths);
531 return TSS2_FAPI_RC_MEMORY;
532 }
533
534 /** Get a linked list of files in a directory and all sub directories.
535 *
536 * Enumerage the regular files (no directories, symlinks etc) from a given directory.
537 *
538 * @param[in] dir_name The directory to list files from.
539 * @param[out] list The linked list with the file names.
540 * @param[out] n The number of filesl
541 * @retval TSS2_RC_SUCCESS if the directories were successfully removed
542 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
543 */
544 static TSS2_RC
dirfiles_all(const char * dir_name,NODE_OBJECT_T ** list,size_t * n)545 dirfiles_all(const char *dir_name, NODE_OBJECT_T **list, size_t *n)
546 {
547 DIR *dir;
548 struct dirent *entry;
549 TSS2_RC r;
550 char *path;
551 NODE_OBJECT_T *second;
552
553 if (!(dir = opendir(dir_name))) {
554 return TSS2_RC_SUCCESS;
555 }
556
557 /* Iterating through the list of entries inside the directory. */
558 while ((entry = readdir(dir)) != NULL) {
559 path = NULL;
560 if (entry->d_type == DT_DIR) {
561 /* Recursive call for sub directories */
562 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
563 continue;
564 r = ifapi_asprintf(&path, "%s/%s", dir_name, entry->d_name);
565 if (r)
566 closedir(dir);
567 return_if_error(r, "Out of memory");
568
569 LOG_TRACE("Directory: %s", path);
570 r = dirfiles_all(path, list, n);
571 SAFE_FREE(path);
572 if (r)
573 closedir(dir);
574 return_if_error(r, "get_entities");
575
576 } else {
577 r = ifapi_asprintf(&path, "%s/%s", dir_name, entry->d_name);
578 if (r)
579 closedir(dir);
580 return_if_error(r, "Out of memory");
581
582 NODE_OBJECT_T *file_obj = calloc(sizeof(NODE_OBJECT_T), 1);
583 if (!file_obj) {
584 LOG_ERROR("Out of memory.");
585 SAFE_FREE(path);
586 closedir(dir);
587 return TSS2_FAPI_RC_MEMORY;
588 }
589
590 *n += 1;
591 /* Add file name to linked list */
592 file_obj->object = strdup(path);
593 if (file_obj->object == NULL) {
594 LOG_ERROR("Out of memory.");
595 SAFE_FREE(file_obj);
596 SAFE_FREE(path);
597 closedir(dir);
598 return TSS2_FAPI_RC_MEMORY;
599 }
600 if (*list != NULL) {
601 second = *list;
602 file_obj->next = second;
603 }
604 *list = file_obj;
605 LOG_TRACE("File: %s", path);
606 SAFE_FREE(path);
607 }
608 }
609 closedir(dir);
610 return TSS2_RC_SUCCESS;
611 }
612
613
614 /** Recursive enumerate the list of files in a directory.
615 *
616 * Enumerage the regular files (no directories, symlinks etc) from a given directory.
617 *
618 * @param[in] searchPath The directory to list files from.
619 * @param[out] pathlist The list of file names.
620 * @param[out] numPaths The size of files.
621 * @retval TSS2_RC_SUCCESS if the directories were successfully removed
622 * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error occurred
623 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
624 */
625 TSS2_RC
ifapi_io_dirfiles_all(const char * searchPath,char *** pathlist,size_t * numPaths)626 ifapi_io_dirfiles_all(
627 const char *searchPath,
628 char ***pathlist,
629 size_t *numPaths)
630 {
631 TSS2_RC r;
632 size_t n;
633 NODE_OBJECT_T *head;
634
635 *numPaths = 0;
636 char **pathlist2;
637
638 NODE_OBJECT_T *file_list = NULL;
639 r = dirfiles_all(searchPath, &file_list, numPaths);
640 goto_if_error(r, "get all sub files of directory", cleanup);
641
642 if (*numPaths > 0) {
643 size_t size_path_list = *numPaths * sizeof(char *);
644 pathlist2 = calloc(1, size_path_list);
645 goto_if_null2(pathlist2, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
646 cleanup);
647 n = *numPaths;
648
649 /* Move file names from list to array */
650 while (n > 0 && file_list) {
651 n -= 1;
652 pathlist2[n] = file_list->object;
653 head = file_list;
654 file_list = file_list->next;
655 SAFE_FREE(head);
656 }
657 *pathlist = pathlist2;
658 }
659 cleanup:
660 /* Free linked list with file names */
661 while (file_list) {
662 head = file_list;
663 file_list = file_list->next;
664 SAFE_FREE(head);
665 }
666 return r;
667 }
668
669 /** Determine whether a path exists.
670 *
671 * @param[in] path The absolute path of the file.
672 * @retval true The file exists.
673 * @retval false The file does not exist.
674 */
675 bool
ifapi_io_path_exists(const char * path)676 ifapi_io_path_exists(const char *path)
677 {
678 struct stat fbuffer;
679
680 if (stat(path, &fbuffer) == 0)
681 return true;
682 else
683 return false;
684 }
685
686
687 /** Wait for file I/O to be ready.
688 *
689 * If FAPI state automata are in a file I/O state it will be waited for an
690 * event on a file descriptor.
691 *
692 * @param[in] io The input/output context being used for file I/O.
693 * @retval TSS2_RC_SUCCESS After the end of the wait.
694 * @retval TSS2_FAPI_RC_IO_ERROR if the poll function returns an error.
695 * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
696 */
697 TSS2_RC
ifapi_io_poll(IFAPI_IO * io)698 ifapi_io_poll(IFAPI_IO * io) {
699 int rc;
700 /* Check for NULL parameters */
701 check_not_null(io);
702
703 if (io->pollevents) {
704 struct pollfd fds;
705 fds.events = io->pollevents;
706 fds.fd = fileno(io->stream);
707 LOG_TRACE("Waiting for fd %i with event %i", fds.fd, fds.events);
708 rc = poll(&fds, 1, -1);
709 if (rc < 0) {
710 LOG_ERROR("Poll failed with %d", errno);
711 return TSS2_FAPI_RC_IO_ERROR;
712 }
713 }
714 return TSS2_RC_SUCCESS;
715 }
716
717 /** Get a list of poll handles.
718 *
719 * @param[in] io The input/output context being used for file I/O.
720 * @param[out] handles The array with the poll handles.
721 * @param[out] num_handles The number of poll handles.
722 * @retval TSS2_RC_SUCCESS on success.
723 * @retval TSS2_FAPI_RC_NO_HANDLE In no poll events are stored in IO context.
724 * @retval TSS2_FAPI_RC_MEMORY If the output data cannot be allocated.
725 * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
726 */
727 TSS2_RC
ifapi_io_poll_handles(IFAPI_IO * io,FAPI_POLL_HANDLE ** handles,size_t * num_handles)728 ifapi_io_poll_handles(IFAPI_IO *io, FAPI_POLL_HANDLE **handles, size_t *num_handles) {
729 /* Check for NULL parameters */
730 check_not_null(io);
731 check_not_null(handles);
732 check_not_null(num_handles);
733
734 if (!io->pollevents) {
735 /* We're not spilling out error here, because this is called in the
736 functional path of Fapi_GetPollHandles(). */
737 LOG_DEBUG("No pollable operation in progress.");
738 return TSS2_FAPI_RC_NO_HANDLE;
739 }
740
741 *handles = calloc(1, sizeof(**handles));
742 check_oom(*handles);
743 (*handles)->events = io->pollevents;
744 (*handles)->fd = fileno(io->stream);
745 *num_handles = 1;
746
747 LOG_TRACE("Returning %zi poll handles for fd %i with event %i",
748 *num_handles, (*handles)->fd, (*handles)->events);
749
750 return TSS2_RC_SUCCESS;
751 }
752