1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2020 Robert Manner <robert.manner@oneidentity.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * This is an open source non-commercial project. Dear PVS-Studio, please check it.
21  * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
22  */
23 
24 #include "iohelpers.h"
25 
26 int
rmdir_recursive(const char * path)27 rmdir_recursive(const char *path)
28 {
29     char *cmd = NULL;
30     int success = false;
31 
32     if (asprintf(&cmd, "rm -rf \"%s\"", path) < 0)
33         return false;
34 
35     if (system(cmd) == 0)
36         success = true;
37 
38     free(cmd);
39 
40     return success;
41 }
42 
43 int
fwriteall(const char * file_path,const char * string)44 fwriteall(const char *file_path, const char *string)
45 {
46     int success = false;
47 
48     FILE *file = fopen(file_path, "w+");
49     if (file == NULL)
50         goto cleanup;
51 
52     size_t size = strlen(string);
53     if (fwrite(string, 1, size, file) < size) {
54         goto cleanup;
55     }
56 
57     success = true;
58 
59 cleanup:
60     if (file)
61         fclose(file);
62 
63     return success;
64 }
65 
66 int
freadall(const char * file_path,char * output,size_t max_len)67 freadall(const char *file_path, char *output, size_t max_len)
68 {
69     int rc = false;
70     FILE *file = fopen(file_path, "rb");
71     if (file == NULL) {
72         printf("Failed to open file '%s'\n", file_path);
73         goto cleanup;
74     }
75 
76     size_t len = fread(output, 1, max_len - 1, file);
77     output[len] = '\0';
78 
79     if (ferror(file) != 0) {
80         printf("Failed to read file '%s' (Error %d)\n", file_path, ferror(file));
81         goto cleanup;
82     }
83 
84     if (!feof(file)) {
85         printf("File '%s' was bigger than allocated buffer %zu", file_path, max_len);
86         goto cleanup;
87     }
88 
89     rc = true;
90 
91 cleanup:
92     if (file)
93         fclose(file);
94 
95     return rc;
96 }
97 
98 int
vsnprintf_append(char * output,size_t max_output_len,const char * fmt,va_list args)99 vsnprintf_append(char *output, size_t max_output_len, const char *fmt, va_list args)
100 {
101     va_list args2;
102     va_copy(args2, args);
103 
104     size_t output_len = strlen(output);
105     int rc = vsnprintf(output + output_len, max_output_len - output_len, fmt, args2);
106 
107     va_end(args2);
108     return rc;
109 }
110 
111 int
snprintf_append(char * output,size_t max_output_len,const char * fmt,...)112 snprintf_append(char *output, size_t max_output_len, const char *fmt, ...)
113 {
114     va_list args;
115     va_start(args, fmt);
116     int rc = vsnprintf_append(output, max_output_len, fmt, args);
117     va_end(args);
118     return rc;
119 }
120 
121 int
str_array_count(char ** str_array)122 str_array_count(char **str_array)
123 {
124     int result = 0;
125     for (; str_array[result] != NULL; ++result) {}
126     return result;
127 }
128 
129 void
str_array_snprint(char * out_str,size_t max_len,char ** str_array,int array_len)130 str_array_snprint(char *out_str, size_t max_len, char **str_array, int array_len)
131 {
132     if (array_len < 0)
133         array_len = str_array_count(str_array);
134 
135     for (int pos = 0; pos < array_len; ++pos) {
136         snprintf_append(out_str, max_len, "%s%s", pos > 0 ? ", " : "", str_array[pos]);
137     }
138 }
139 
140 char *
str_replaced(const char * source,size_t dest_len,const char * old,const char * new)141 str_replaced(const char *source, size_t dest_len, const char *old, const char *new)
142 {
143     char *result = calloc(1, dest_len);
144     char *dest = result;
145     char *pos = NULL;
146     size_t old_len = strlen(old);
147 
148     while ((pos = strstr(source, old)) != NULL) {
149         size_t len = snprintf(dest, dest_len,
150             "%.*s%s", (int)(pos - source), source, new);
151         if (len >= dest_len)
152             goto fail;
153 
154         dest_len -= len;
155         dest += len;
156         source = pos + old_len;
157     }
158 
159     if (strlcpy(dest, source, dest_len) >= dest_len)
160         goto fail;
161 
162     return result;
163 
164 fail:
165     free(result);
166     return strdup("str_replace_all failed, string too long");
167 }
168 
169 void
str_replace_in_place(char * string,size_t max_length,const char * old,const char * new)170 str_replace_in_place(char *string, size_t max_length, const char *old, const char *new)
171 {
172     char *replaced = str_replaced(string, max_length, old, new);
173     strlcpy(string, replaced, max_length);
174     free(replaced);
175 }
176