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