diff options
Diffstat (limited to 'lib/x1000-installer/src/xf_update.c')
-rw-r--r-- | lib/x1000-installer/src/xf_update.c | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/lib/x1000-installer/src/xf_update.c b/lib/x1000-installer/src/xf_update.c new file mode 100644 index 0000000000..5a7c3b0430 --- /dev/null +++ b/lib/x1000-installer/src/xf_update.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "xf_update.h" | ||
23 | #include "xf_error.h" | ||
24 | #include "file.h" | ||
25 | #include "md5.h" | ||
26 | #include <string.h> | ||
27 | |||
28 | static int process_stream(struct xf_nandio* nio, | ||
29 | struct xf_map* map, | ||
30 | struct xf_stream* stream) | ||
31 | { | ||
32 | void* buffer; | ||
33 | size_t count; | ||
34 | int rc; | ||
35 | |||
36 | /* calculate MD5 on the fly if taking a backup */ | ||
37 | md5_context md5_ctx; | ||
38 | if(nio->mode == XF_NANDIO_READ) | ||
39 | md5_starts(&md5_ctx); | ||
40 | |||
41 | /* first deal with the file data */ | ||
42 | size_t bytes_left = map->length; | ||
43 | while(bytes_left > 0) { | ||
44 | count = bytes_left; | ||
45 | rc = xf_nandio_get_buffer(nio, &buffer, &count); | ||
46 | if(rc) | ||
47 | return rc; | ||
48 | |||
49 | if(nio->mode == XF_NANDIO_READ) { | ||
50 | md5_update(&md5_ctx, buffer, count); | ||
51 | rc = xf_stream_write(stream, buffer, count); | ||
52 | } else { | ||
53 | rc = xf_stream_read(stream, buffer, count); | ||
54 | } | ||
55 | |||
56 | bytes_left -= count; | ||
57 | |||
58 | if(rc < 0 || (size_t)rc > count) | ||
59 | return XF_E_IO; | ||
60 | |||
61 | if((size_t)rc < count) { | ||
62 | /* backup - we could not write all the data */ | ||
63 | if(nio->mode == XF_NANDIO_READ) | ||
64 | return XF_E_IO; | ||
65 | |||
66 | /* update - clear rest of buffer to 0xff */ | ||
67 | memset(buffer + rc, 0xff, count - rc); | ||
68 | break; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | /* if updating - write blanks to the remainder of the region */ | ||
73 | while(bytes_left > 0) { | ||
74 | count = bytes_left; | ||
75 | rc = xf_nandio_get_buffer(nio, &buffer, &count); | ||
76 | if(rc) | ||
77 | return rc; | ||
78 | |||
79 | memset(buffer, 0xff, count); | ||
80 | bytes_left -= count; | ||
81 | } | ||
82 | |||
83 | /* finalize the MD5 sum */ | ||
84 | if(nio->mode == XF_NANDIO_READ) { | ||
85 | md5_finish(&md5_ctx, map->md5); | ||
86 | map->file_length = map->length; | ||
87 | map->flags |= XF_MAP_HAS_MD5 | XF_MAP_HAS_FILE_LENGTH; | ||
88 | } | ||
89 | |||
90 | return XF_E_SUCCESS; | ||
91 | } | ||
92 | |||
93 | static int process_map(struct xf_nandio* nio, struct xf_map* map, int map_size, | ||
94 | xf_update_open_stream_cb open_stream, void* os_arg) | ||
95 | { | ||
96 | int rc, rc2; | ||
97 | struct xf_stream stream; | ||
98 | |||
99 | /* ensure the map is sequential and non-overlapping before continuing */ | ||
100 | if(xf_map_validate(map, map_size) != 0) | ||
101 | return XF_E_INVALID_PARAMETER; | ||
102 | |||
103 | for(int i = 0; i < map_size; ++i) { | ||
104 | /* seek to initial offset */ | ||
105 | rc = xf_nandio_seek(nio, map[i].offset); | ||
106 | if(rc) | ||
107 | return rc; | ||
108 | |||
109 | rc = open_stream(os_arg, map[i].name, &stream); | ||
110 | if(rc) | ||
111 | return XF_E_CANNOT_OPEN_FILE; | ||
112 | |||
113 | /* process the stream and be sure to close it even on error */ | ||
114 | rc = process_stream(nio, &map[i], &stream); | ||
115 | rc2 = xf_stream_close(&stream); | ||
116 | |||
117 | /* bail if either operation raised an error */ | ||
118 | if(rc) | ||
119 | return rc; | ||
120 | if(rc2) | ||
121 | return rc2; | ||
122 | } | ||
123 | |||
124 | /* now flush to ensure all data was written */ | ||
125 | rc = xf_nandio_flush(nio); | ||
126 | if(rc) | ||
127 | return rc; | ||
128 | |||
129 | return XF_E_SUCCESS; | ||
130 | } | ||
131 | |||
132 | static const enum xf_nandio_mode update_mode_to_nandio[] = { | ||
133 | [XF_UPDATE] = XF_NANDIO_PROGRAM, | ||
134 | [XF_BACKUP] = XF_NANDIO_READ, | ||
135 | [XF_VERIFY] = XF_NANDIO_VERIFY, | ||
136 | }; | ||
137 | |||
138 | int xf_updater_run(enum xf_update_mode mode, struct xf_nandio* nio, | ||
139 | struct xf_map* map, int map_size, | ||
140 | xf_update_open_stream_cb open_stream, void* arg) | ||
141 | { | ||
142 | /* Switch NAND I/O into the correct mode */ | ||
143 | int rc = xf_nandio_set_mode(nio, update_mode_to_nandio[mode]); | ||
144 | if(rc) | ||
145 | return rc; | ||
146 | |||
147 | /* This does all the real work */ | ||
148 | return process_map(nio, map, map_size, open_stream, arg); | ||
149 | } | ||