a4130b79c0f54bac179d859576d7578c9a5df932
[fw/openocd] / src / helper / fileio.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4  *   Copyright (C) 2007 by Dominic Rath                                    *
5  *   Dominic.Rath@gmx.de                                                   *
6  *                                                                         *
7  *   Copyright (C) 2007,2008 Ã˜yvind Harboe                                 *
8  *   oyvind.harboe@zylin.com                                               *
9  *                                                                         *
10  *   Copyright (C) 2008 by Spencer Oliver                                  *
11  *   spen@spen-soft.co.uk                                                  *
12  ***************************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17
18 #include "log.h"
19 #include "configuration.h"
20 #include "fileio.h"
21 #include "replacements.h"
22
23 struct fileio {
24         char *url;
25         size_t size;
26         enum fileio_type type;
27         enum fileio_access access;
28         FILE *file;
29 };
30
31 static inline int fileio_close_local(struct fileio *fileio)
32 {
33         int retval = fclose(fileio->file);
34         if (retval != 0) {
35                 if (retval == EBADF)
36                         LOG_ERROR("BUG: fileio->file not a valid file descriptor");
37                 else
38                         LOG_ERROR("couldn't close %s: %s", fileio->url, strerror(errno));
39
40                 return ERROR_FILEIO_OPERATION_FAILED;
41         }
42
43         return ERROR_OK;
44 }
45
46 static inline int fileio_open_local(struct fileio *fileio)
47 {
48         char file_access[4];
49         ssize_t file_size;
50
51         switch (fileio->access) {
52                 case FILEIO_READ:
53                         strcpy(file_access, "r");
54                         break;
55                 case FILEIO_WRITE:
56                         strcpy(file_access, "w");
57                         break;
58                 case FILEIO_READWRITE:
59                         strcpy(file_access, "w+");
60                         break;
61                 case FILEIO_APPEND:
62                         strcpy(file_access, "a");
63                         break;
64                 case FILEIO_APPENDREAD:
65                         strcpy(file_access, "a+");
66                         break;
67                 default:
68                         LOG_ERROR("BUG: access neither read, write nor readwrite");
69                         return ERROR_COMMAND_SYNTAX_ERROR;
70         }
71
72         /* win32 always opens in binary mode */
73 #ifndef _WIN32
74         if (fileio->type == FILEIO_BINARY)
75 #endif
76                 strcat(file_access, "b");
77
78         fileio->file = open_file_from_path(fileio->url, file_access);
79         if (!fileio->file) {
80                 LOG_ERROR("couldn't open %s", fileio->url);
81                 return ERROR_FILEIO_OPERATION_FAILED;
82         }
83
84         file_size = 0;
85
86         if ((fileio->access != FILEIO_WRITE) || (fileio->access == FILEIO_READWRITE)) {
87                 /* NB! Here we use fseek() instead of stat(), since stat is a
88                  * more advanced operation that might not apply to e.g. a disk path
89                  * that refers to e.g. a tftp client */
90                 int result, result2;
91
92                 result = fseek(fileio->file, 0, SEEK_END);
93
94                 file_size = ftell(fileio->file);
95
96                 result2 = fseek(fileio->file, 0, SEEK_SET);
97
98                 if ((file_size < 0) || (result < 0) || (result2 < 0)) {
99                         fileio_close_local(fileio);
100                         return ERROR_FILEIO_OPERATION_FAILED;
101                 }
102         }
103
104         fileio->size = file_size;
105
106         return ERROR_OK;
107 }
108
109 int fileio_open(struct fileio **fileio, const char *url,
110                 enum fileio_access access_type, enum fileio_type type)
111 {
112         int retval;
113         struct fileio *tmp;
114
115         tmp = malloc(sizeof(struct fileio));
116
117         tmp->type = type;
118         tmp->access = access_type;
119         tmp->url = strdup(url);
120
121         retval = fileio_open_local(tmp);
122
123         if (retval != ERROR_OK) {
124                 free(tmp->url);
125                 free(tmp);
126                 return retval;
127         }
128
129         *fileio = tmp;
130
131         return ERROR_OK;
132 }
133
134 int fileio_close(struct fileio *fileio)
135 {
136         int retval;
137
138         retval = fileio_close_local(fileio);
139
140         free(fileio->url);
141         free(fileio);
142
143         return retval;
144 }
145
146 int fileio_feof(struct fileio *fileio)
147 {
148         return feof(fileio->file);
149 }
150
151 int fileio_seek(struct fileio *fileio, size_t position)
152 {
153         int retval;
154
155         retval = fseek(fileio->file, position, SEEK_SET);
156
157         if (retval != 0) {
158                 LOG_ERROR("couldn't seek file %s: %s", fileio->url, strerror(errno));
159                 return ERROR_FILEIO_OPERATION_FAILED;
160         }
161
162         return ERROR_OK;
163 }
164
165 static int fileio_local_read(struct fileio *fileio, size_t size, void *buffer,
166                 size_t *size_read)
167 {
168         ssize_t retval;
169
170         retval = fread(buffer, 1, size, fileio->file);
171         *size_read = (retval >= 0) ? retval : 0;
172
173         return (retval < 0) ? retval : ERROR_OK;
174 }
175
176 int fileio_read(struct fileio *fileio, size_t size, void *buffer,
177                 size_t *size_read)
178 {
179         return fileio_local_read(fileio, size, buffer, size_read);
180 }
181
182 int fileio_read_u32(struct fileio *fileio, uint32_t *data)
183 {
184         int retval;
185         uint8_t buf[4];
186         size_t size_read;
187
188         retval = fileio_local_read(fileio, sizeof(uint32_t), buf, &size_read);
189
190         if (retval == ERROR_OK && sizeof(uint32_t) != size_read)
191                 retval = -EIO;
192         if (retval == ERROR_OK)
193                 *data = be_to_h_u32(buf);
194
195         return retval;
196 }
197
198 static int fileio_local_fgets(struct fileio *fileio, size_t size, void *buffer)
199 {
200         if (!fgets(buffer, size, fileio->file))
201                 return ERROR_FILEIO_OPERATION_FAILED;
202
203         return ERROR_OK;
204 }
205
206 int fileio_fgets(struct fileio *fileio, size_t size, void *buffer)
207 {
208         return fileio_local_fgets(fileio, size, buffer);
209 }
210
211 static int fileio_local_write(struct fileio *fileio, size_t size,
212                 const void *buffer, size_t *size_written)
213 {
214         ssize_t retval;
215
216         retval = fwrite(buffer, 1, size, fileio->file);
217         *size_written = (retval >= 0) ? retval : 0;
218
219         return (retval < 0) ? retval : ERROR_OK;
220 }
221
222 int fileio_write(struct fileio *fileio, size_t size, const void *buffer,
223                 size_t *size_written)
224 {
225         int retval;
226
227         retval = fileio_local_write(fileio, size, buffer, size_written);
228
229         if (retval == ERROR_OK)
230                 fileio->size += *size_written;
231
232         return retval;
233 }
234
235 int fileio_write_u32(struct fileio *fileio, uint32_t data)
236 {
237         int retval;
238         uint8_t buf[4];
239         h_u32_to_be(buf, data);
240         size_t size_written;
241
242         retval = fileio_write(fileio, 4, buf, &size_written);
243
244         if (retval == ERROR_OK && size_written != sizeof(uint32_t))
245                 retval = -EIO;
246
247         return retval;
248 }
249
250 /**
251  * FIX!!!!
252  *
253  * For now this can not fail, but that's because a seek was executed
254  * on startup.
255  *
256  * Avoiding the seek on startup opens up for using streams.
257  *
258  */
259 int fileio_size(struct fileio *fileio, size_t *size)
260 {
261         *size = fileio->size;
262
263         return ERROR_OK;
264 }