rfs: Consistent coding style, cleanup and fresh new implementation
[libsamsung-ipc.git] / samsung-ipc / rfs.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr>
5  *
6  * libsamsung-ipc is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * libsamsung-ipc is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with libsamsung-ipc.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <sys/stat.h>
28
29 #include <openssl/md5.h>
30
31 #include <samsung-ipc.h>
32
33 #include "ipc.h"
34 #include "utils.h"
35
36 char *ipc_nv_data_md5_calculate(const char *path, const char *secret,
37     size_t size, size_t chunk_size)
38 {
39     void *data = NULL;
40     char *md5_string = NULL;
41     unsigned char md5_hash[MD5_DIGEST_LENGTH] = { 0 };
42     MD5_CTX ctx;
43     int rc;
44
45     if (secret == NULL)
46         return NULL;
47
48     data = file_data_read(path, size, chunk_size, 0);
49     if (data == NULL)
50         return NULL;
51
52     MD5_Init(&ctx);
53     MD5_Update(&ctx, data, size);
54     MD5_Update(&ctx, secret, strlen(secret));
55     MD5_Final((unsigned char *) &md5_hash, &ctx);
56
57     md5_string = data2string(&md5_hash, sizeof(md5_hash));
58
59     return md5_string;
60 }
61
62 int ipc_nv_data_path_check(struct ipc_client *client)
63 {
64     struct stat st;
65     char *path;
66     size_t size;
67     int rc;
68
69     if (client == NULL)
70         return -1;
71
72     path = ipc_client_nv_data_path(client);
73     size = ipc_client_nv_data_size(client);
74     if (path == NULL || size == 0)
75         return -1;
76
77     rc = stat(path, &st);
78     if (rc < 0) {
79         ipc_client_log(client, "Checking nv_data path failed");
80         return -1;
81     }
82
83     if (st.st_size != size) {
84         ipc_client_log(client, "Checking nv_data size failed");
85         return -1;
86     }
87
88     ipc_client_log(client, "Checked nv_data path");
89
90     return 0;
91 }
92
93 int ipc_nv_data_md5_path_check(struct ipc_client *client)
94 {
95     struct stat st;
96     char *md5_path;
97     int rc;
98
99     if (client == NULL)
100         return -1;
101
102     md5_path = ipc_client_nv_data_md5_path(client);
103     if (md5_path == NULL)
104         return -1;
105
106     rc = stat(md5_path, &st);
107     if (rc < 0) {
108         ipc_client_log(client, "Checking nv_data md5 path failed");
109         return -1;
110     }
111
112     if (st.st_size < 2 * sizeof(char) * MD5_DIGEST_LENGTH) {
113         ipc_client_log(client, "Checking nv_data md5 size failed");
114         return -1;
115     }
116
117     ipc_client_log(client, "Checked nv_data md5 path");
118
119     return 0;
120 }
121
122 int ipc_nv_data_backup_path_check(struct ipc_client *client)
123 {
124     struct stat st;
125     char *backup_path;
126     size_t size;
127     int rc;
128
129     if (client == NULL)
130         return -1;
131
132     backup_path = ipc_client_nv_data_backup_path(client);
133     size = ipc_client_nv_data_size(client);
134     if (backup_path == NULL || size == 0)
135         return -1;
136
137     rc = stat(backup_path, &st);
138     if (rc < 0) {
139         ipc_client_log(client, "Checking nv_data backup path failed");
140         return -1;
141     }
142
143     if (st.st_size != size) {
144         ipc_client_log(client, "Checking nv_data backup size failed");
145         return -1;
146     }
147
148     ipc_client_log(client, "Checked nv_data backup path");
149
150     return 0;
151 }
152
153 int ipc_nv_data_backup_md5_path_check(struct ipc_client *client)
154 {
155     struct stat st;
156     char *backup_md5_path;
157     int rc;
158
159     if (client == NULL)
160         return -1;
161
162     backup_md5_path = ipc_client_nv_data_backup_md5_path(client);
163     if (backup_md5_path == NULL)
164         return -1;
165
166     rc = stat(backup_md5_path, &st);
167     if (rc < 0) {
168         ipc_client_log(client, "Checking nv_data backup md5 path failed");
169         return -1;
170     }
171
172     if (st.st_size < 2 * sizeof(char) * MD5_DIGEST_LENGTH) {
173         ipc_client_log(client, "Checking nv_data backup md5 size failed");
174         return -1;
175     }
176
177     ipc_client_log(client, "Checked nv_data backup md5 path");
178
179     return 0;
180 }
181
182 int ipc_nv_data_check(struct ipc_client *client)
183 {
184     char *path;
185     char *md5_path;
186     char *secret;
187     size_t size;
188     size_t chunk_size;
189     char *md5_string = NULL;
190     void *buffer = NULL;
191     char *string = NULL;
192     size_t length;
193     int rc;
194
195     if (client == NULL)
196         return -1;
197
198     path = ipc_client_nv_data_path(client);
199     md5_path = ipc_client_nv_data_md5_path(client);
200     secret = ipc_client_nv_data_secret(client);
201     size = ipc_client_nv_data_size(client);
202     chunk_size = ipc_client_nv_data_chunk_size(client);
203     if (path == NULL || md5_path == NULL || secret == NULL || size == 0 || chunk_size == 0)
204         return -1;
205
206     rc = ipc_nv_data_path_check(client);
207     if (rc < 0) {
208         ipc_client_log(client, "Checking nv_data path failed");
209         goto error;
210     }
211
212     rc = ipc_nv_data_md5_path_check(client);
213     if (rc < 0) {
214         ipc_client_log(client, "Checking nv_data md5 path failed");
215         goto error;
216     }
217
218     md5_string = ipc_nv_data_md5_calculate(path, secret, size, chunk_size);
219     if (md5_string == NULL) {
220         ipc_client_log(client, "Calculating nv_data md5 failed");
221         goto error;
222     }
223     ipc_client_log(client, "Calculated nv_data md5: %s", md5_string);
224
225     length = strlen(md5_string);
226
227     buffer = file_data_read(md5_path, length, length, 0);
228     if (buffer == NULL) {
229         ipc_client_log(client, "Reading nv_data md5 failed");
230         goto error;
231     }
232
233     string = strndup(buffer, length);
234     ipc_client_log(client, "Read nv_data md5: %s", string);
235
236     rc = strncmp(md5_string, string, length);
237     if (rc != 0) {
238         ipc_client_log(client, "Matching nv_data md5 failed");
239         goto error;
240     }
241
242     rc = 0;
243     goto complete;
244
245 error:
246     rc = -1;
247
248 complete:
249     if (string != NULL)
250         free(string);
251
252     if (buffer != NULL)
253         free(buffer);
254
255     if (md5_string != NULL)
256         free(md5_string);
257
258     return rc;
259 }
260
261 int ipc_nv_data_backup_check(struct ipc_client *client)
262 {
263     char *backup_path;
264     char *backup_md5_path;
265     char *secret;
266     size_t size;
267     size_t chunk_size;
268     char *backup_md5_string = NULL;
269     void *buffer = NULL;
270     char *string = NULL;
271     size_t length;
272     int rc;
273
274     if (client == NULL)
275         return -1;
276
277     backup_path = ipc_client_nv_data_backup_path(client);
278     backup_md5_path = ipc_client_nv_data_backup_md5_path(client);
279     secret = ipc_client_nv_data_secret(client);
280     size = ipc_client_nv_data_size(client);
281     chunk_size = ipc_client_nv_data_chunk_size(client);
282     if (backup_path == NULL || backup_md5_path == NULL || secret == NULL || size == 0 || chunk_size == 0)
283         return -1;
284
285     rc = ipc_nv_data_backup_path_check(client);
286     if (rc < 0) {
287         ipc_client_log(client, "Checking nv_data backup path failed");
288         goto error;
289     }
290
291     rc = ipc_nv_data_backup_md5_path_check(client);
292     if (rc < 0) {
293         ipc_client_log(client, "Checking nv_data backup md5 path failed");
294         goto error;
295     }
296
297     backup_md5_string = ipc_nv_data_md5_calculate(backup_path, secret, size, chunk_size);
298     if (backup_md5_string == NULL) {
299         ipc_client_log(client, "Calculating nv_data backup md5 failed");
300         goto error;
301     }
302     ipc_client_log(client, "Calculated nv_data backup md5: %s", backup_md5_string);
303
304     length = strlen(backup_md5_string);
305
306     buffer = file_data_read(backup_md5_path, length, length, 0);
307     if (buffer == NULL) {
308         ipc_client_log(client, "Reading nv_data backup md5 failed");
309         goto error;
310     }
311
312     string = strndup(buffer, length);
313     ipc_client_log(client, "Read nv_data backup md5: %s", string);
314
315     rc = strncmp(backup_md5_string, string, length);
316     if (rc != 0) {
317         ipc_client_log(client, "Matching nv_data backup md5 failed");
318         goto error;
319     }
320
321     rc = 0;
322     goto complete;
323
324 error:
325     rc = -1;
326
327 complete:
328     if (string != NULL)
329         free(string);
330
331     if (buffer != NULL)
332         free(buffer);
333
334     if (backup_md5_string != NULL)
335         free(backup_md5_string);
336
337     return rc;
338 }
339
340 int ipc_nv_data_backup(struct ipc_client *client)
341 {
342     void *data = NULL;
343     char *path;
344     char *backup_path;
345     char *backup_md5_path;
346     char *secret;
347     size_t size;
348     size_t chunk_size;
349     char *md5_string = NULL;
350     size_t length;
351     int rc;
352
353     if (client == NULL)
354         return -1;
355
356     path = ipc_client_nv_data_path(client);
357     backup_path = ipc_client_nv_data_backup_path(client);
358     backup_md5_path = ipc_client_nv_data_backup_md5_path(client);
359     secret = ipc_client_nv_data_secret(client);
360     size = ipc_client_nv_data_size(client);
361     chunk_size = ipc_client_nv_data_chunk_size(client);
362     if (path == NULL || backup_path == NULL || backup_md5_path == NULL || secret == NULL || size == 0 || chunk_size == 0)
363         return -1;
364
365     rc = ipc_nv_data_path_check(client);
366     if (rc < 0) {
367         ipc_client_log(client, "Checking nv_data path failed");
368         goto error;
369     }
370
371     data = file_data_read(path, size, chunk_size, 0);
372     if (data == NULL) {
373         ipc_client_log(client, "Reading nv_data failed");
374         goto error;
375     }
376
377     md5_string = ipc_nv_data_md5_calculate(path, secret, size, chunk_size);
378     if (md5_string == NULL) {
379         ipc_client_log(client, "Calculating nv_data md5 failed");
380         goto error;
381     }
382
383     length = strlen(md5_string);
384
385     rc = unlink(backup_path);
386     if (rc < 0)
387         ipc_client_log(client, "Removing nv_data backup path failed");
388
389     rc = file_data_write(backup_path, data, size, chunk_size, 0);
390     if (rc < 0) {
391         ipc_client_log(client, "Writing nv_data backup failed");
392         goto error;
393     }
394
395     rc = unlink(backup_md5_path);
396     if (rc < 0)
397         ipc_client_log(client, "Removing nv_data backup md5 path failed");
398
399     rc = file_data_write(backup_md5_path, md5_string, length, length, 0);
400     if (rc < 0) {
401         ipc_client_log(client, "Writing nv_data backup md5 failed");
402         goto error;
403     }
404
405     ipc_client_log(client, "Backed up nv_data");
406
407     rc = 0;
408     goto complete;
409
410 error:
411     rc = -1;
412
413 complete:
414     if (md5_string != NULL)
415         free(md5_string);
416
417     if (data != NULL)
418         free(data);
419
420     return rc;
421 }
422
423 int ipc_nv_data_restore(struct ipc_client *client)
424 {
425     void *data = NULL;
426     char *path;
427     char *md5_path;
428     char *backup_path;
429     char *backup_md5_path;
430     char *secret;
431     size_t size;
432     size_t chunk_size;
433     size_t length;
434     int rc;
435
436     if (client == NULL)
437         return -1;
438
439     path = ipc_client_nv_data_path(client);
440     md5_path = ipc_client_nv_data_md5_path(client);
441     backup_path = ipc_client_nv_data_backup_path(client);
442     backup_md5_path = ipc_client_nv_data_backup_md5_path(client);
443     secret = ipc_client_nv_data_secret(client);
444     size = ipc_client_nv_data_size(client);
445     chunk_size = ipc_client_nv_data_chunk_size(client);
446     if (path == NULL || md5_path == NULL || backup_path == NULL || backup_md5_path == NULL || secret == NULL || size == 0 || chunk_size == 0)
447         return -1;
448
449     rc = ipc_nv_data_backup_check(client);
450     if (rc < 0) {
451         ipc_client_log(client, "Checking nv_data backup failed");
452         goto error;
453     }
454
455     data = file_data_read(backup_path, size, chunk_size, 0);
456     if (data == NULL) {
457         ipc_client_log(client, "Reading nv_data backup failed");
458         goto error;
459     }
460
461     rc = unlink(path);
462     if (rc < 0)
463         ipc_client_log(client, "Removing nv_data path failed");
464
465     rc = file_data_write(path, data, size, chunk_size, 0);
466     if (rc < 0) {
467         ipc_client_log(client, "Writing nv_data failed");
468         goto error;
469     }
470
471     free(data);
472     data = NULL;
473
474     length = 2 * sizeof(char) * MD5_DIGEST_LENGTH;
475
476     data = file_data_read(backup_md5_path, length, length, 0);
477     if (data == NULL) {
478         ipc_client_log(client, "Reading nv_data backup md5 failed");
479         goto error;
480     }
481
482     rc = unlink(md5_path);
483     if (rc < 0)
484         ipc_client_log(client, "Removing nv_data md5 path failed");
485
486     rc = file_data_write(md5_path, data, length, length, 0);
487     if (rc < 0) {
488         ipc_client_log(client, "Writing nv_data md5 failed");
489         goto error;
490     }
491
492     ipc_client_log(client, "Restored nv_data");
493
494     rc = 0;
495     goto complete;
496
497 error:
498     rc = -1;
499
500 complete:
501     if (data != NULL)
502         free(data);
503
504     return rc;
505 }
506
507 void *ipc_nv_data_load(struct ipc_client *client)
508 {
509     void *data;
510     char *path;
511     size_t size;
512     size_t chunk_size;
513     int rc;
514
515     if (client == NULL)
516         return NULL;
517
518     path = ipc_client_nv_data_path(client);
519     size = ipc_client_nv_data_size(client);
520     chunk_size = ipc_client_nv_data_chunk_size(client);
521     if (path == NULL || size == 0 || chunk_size == 0)
522         return NULL;
523
524     rc = ipc_nv_data_check(client);
525     if (rc < 0) {
526         ipc_client_log(client, "Checking nv_data failed");
527
528         rc = ipc_nv_data_restore(client);
529         if (rc < 0) {
530             ipc_client_log(client, "Restoring nv_data failed");
531             return NULL;
532         }
533
534         rc = ipc_nv_data_check(client);
535         if (rc < 0) {
536             ipc_client_log(client, "Checking nv_data failed");
537             return NULL;
538         }
539     }
540
541     rc = ipc_nv_data_backup_path_check(client);
542     if (rc < 0) {
543         ipc_client_log(client, "Checking nv_data backup path failed");
544
545         rc = ipc_nv_data_backup(client);
546         if (rc < 0)
547             ipc_client_log(client, "Backing up nv_data failed");
548     }
549
550     data = file_data_read(path, size, chunk_size, 0);
551     if (data == NULL) {
552         ipc_client_log(client, "Reading nv_data failed");
553         return NULL;
554     }
555
556     return data;
557 }
558
559 void *ipc_nv_data_read(struct ipc_client *client, size_t size, size_t offset)
560 {
561     void *data;
562     char *path;
563     size_t chunk_size;
564     int rc;
565
566     if (client == NULL)
567         return NULL;
568
569     path = ipc_client_nv_data_path(client);
570     chunk_size = ipc_client_nv_data_chunk_size(client);
571     if (path == NULL || chunk_size == 0)
572         return NULL;
573
574     rc = ipc_nv_data_path_check(client);
575     if (rc < 0) {
576         ipc_client_log(client, "Checking nv_data path failed");
577         return NULL;
578     }
579
580     data = file_data_read(path, size, chunk_size, offset);
581     if (data == NULL) {
582         ipc_client_log(client, "Reading nv_data failed");
583         return NULL;
584     }
585
586     return data;
587 }
588
589 int ipc_nv_data_write(struct ipc_client *client, const void *data, size_t size,
590     size_t offset)
591 {
592     char *path;
593     char *md5_path;
594     char *secret;
595     size_t chunk_size;
596     char *md5_string = NULL;
597     size_t length;
598     int rc;
599
600     if (client == NULL)
601         return -1;
602
603     path = ipc_client_nv_data_path(client);
604     md5_path = ipc_client_nv_data_md5_path(client);
605     secret = ipc_client_nv_data_secret(client);
606     chunk_size = ipc_client_nv_data_chunk_size(client);
607     if (path == NULL || md5_path == NULL || secret == NULL || chunk_size == 0)
608         return -1;
609
610     rc = ipc_nv_data_path_check(client);
611     if (rc < 0) {
612         ipc_client_log(client, "Checking nv_data path failed");
613         goto error;
614     }
615
616     rc = file_data_write(path, data, size, chunk_size, offset);
617     if (rc < 0) {
618         ipc_client_log(client, "Writing nv_data failed");
619         goto error;
620     }
621
622     size = ipc_client_nv_data_size(client);
623     if (size == 0)
624         goto error;
625
626     md5_string = ipc_nv_data_md5_calculate(path, secret, size, chunk_size);
627     if (md5_string == NULL) {
628         ipc_client_log(client, "Calculating nv_data md5 failed");
629         goto error;
630     }
631
632     length = strlen(md5_string);
633
634     rc = unlink(md5_path);
635     if (rc < 0) {
636         ipc_client_log(client, "Removing nv_data md5 path failed");
637         goto error;
638     }
639
640     rc = file_data_write(md5_path, md5_string, length, length, 0);
641     if (rc < 0) {
642         ipc_client_log(client, "Writing nv_data md5 failed");
643         goto error;
644     }
645
646     rc = 0;
647     goto complete;
648
649 error:
650     rc = -1;
651
652 complete:
653     if (md5_string != NULL)
654         free(md5_string);
655
656     return rc;
657 }
658
659 void *ipc_rfs_nv_read_item_response_setup(const void *data, size_t size,
660     size_t offset)
661 {
662     struct ipc_rfs_nv_read_item_response_header *header;
663     void *buffer;
664     size_t length;
665     unsigned char confirm;
666     unsigned char *p;
667
668     if (data != NULL && size > 0) {
669         length = sizeof(struct ipc_rfs_nv_read_item_response_header) + size;
670         confirm = 1;
671     } else {
672         length = sizeof(struct ipc_rfs_nv_read_item_response_header);
673         size = 0;
674         offset = 0;
675         confirm = 0;
676     }
677
678     buffer = calloc(1, length);
679
680     header = (struct ipc_rfs_nv_read_item_response_header *) buffer;
681     header->confirm = confirm;
682     header->offset = (unsigned int) offset;
683     header->length = (unsigned int) size;
684
685     if (data != NULL && size > 0) {
686         p = (unsigned char *) buffer;
687         p += sizeof(struct ipc_rfs_nv_read_item_response_header);
688
689         memcpy(p, data, size);
690     }
691
692     return buffer;
693 }
694
695 // vim:ts=4:sw=4:expandtab