5b56e6c67d2b36cac654222927a9c4c4827be8f0
[libsamsung-ipc.git] / samsung-ipc / rfs.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2011 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 #define MD5_STRING_SIZE                         MD5_DIGEST_LENGTH * 2 + 1
37
38 void md5hash2string(char *out, unsigned char *in)
39 {
40     int i;
41
42     for (i = 0; i < MD5_DIGEST_LENGTH; i++)
43     {
44         /* After the first iteration, we override \0. */
45         if (*in < 0x10)
46             sprintf(out, "0%x", *in);
47         else
48             sprintf(out, "%x", *in);
49
50         in++;
51         out += 2;
52     }
53 }
54
55 void nv_data_generate(struct ipc_client *client)
56 {
57     return;
58 }
59
60 void nv_data_md5_compute(void *data_p, int size, char *secret, void *hash)
61 {
62     MD5_CTX ctx;
63
64     MD5_Init(&ctx);
65     MD5_Update(&ctx, data_p, size);
66     MD5_Update(&ctx, secret, strlen(secret));
67     MD5_Final(hash, &ctx);
68 }
69
70 void nv_data_md5_generate(struct ipc_client *client)
71 {
72     uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
73     char *nv_data_md5_hash_string = NULL;
74     void *nv_data_p = NULL;
75     int fd;
76     int rc;
77
78     ipc_client_log(client, "nv_data_md5_generate: enter");
79
80     ipc_client_log(client, "nv_data_md5_generate: generating MD5 hash");
81     nv_data_p = file_data_read(ipc_client_nv_data_path(client),
82         ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
83     nv_data_md5_compute(nv_data_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
84     free(nv_data_p);
85
86     /* Alloc the memory for the md5 hash string. */
87     nv_data_md5_hash_string = malloc(MD5_STRING_SIZE);
88     memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
89
90     md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
91
92     ipc_client_log(client, "nv_data_md5_generate: new MD5 hash is %s", nv_data_md5_hash_string);
93
94     ipc_client_log(client, "nv_data_md5_generate: writing MD5 hash");
95
96     /* Write the MD5 hash in nv_data.bin.md5. */
97     fd = open(ipc_client_nv_data_md5_path(client), O_RDWR | O_CREAT | O_TRUNC, 0644);
98     if (fd < 0)
99     {
100         ipc_client_log(client, "nv_data_md5_generate: fd open failed");
101         goto exit;
102     }
103
104     rc = write(fd, nv_data_md5_hash_string, MD5_STRING_SIZE);
105     if (rc < 0)
106     {
107         ipc_client_log(client, "nv_data_md5_generate: failed to write MD5 hash to file");
108         close(fd);
109         goto exit;
110     }
111
112     close(fd);
113
114 exit:
115     if (nv_data_md5_hash_string != NULL)
116         free(nv_data_md5_hash_string);
117
118     ipc_client_log(client, "nv_data_md5_generate: exit");
119 }
120
121 void nv_data_backup_create(struct ipc_client *client)
122 {
123     uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
124     char *nv_data_md5_hash_string = NULL;
125     char *nv_data_md5_hash_read = NULL;
126     int nv_data_write_tries = 0;
127
128     struct stat nv_stat;
129     void *nv_data_p = NULL;
130     void *nv_data_bak_p = NULL;
131     uint8_t data;
132
133     int fd;
134     int rc;
135     int i;
136
137     ipc_client_log(client, "nv_data_backup_create: enter");
138
139     if (stat(ipc_client_nv_data_path(client), &nv_stat) < 0)
140     {
141         ipc_client_log(client, "nv_data_backup_create: nv_data.bin missing");
142         nv_data_generate(client);
143     }
144
145     if (nv_stat.st_size != ipc_client_nv_data_size(client))
146     {
147         ipc_client_log(client, "nv_data_backup_create: wrong nv_data.bin size");
148         nv_data_generate(client);
149         return;
150     }
151
152     if (stat(ipc_client_nv_data_md5_path(client), &nv_stat) < 0)
153     {
154         ipc_client_log(client, "nv_data_backup_create: nv_data.bin.md5 missing");
155         nv_data_generate(client);
156         return;
157     }
158
159     /* Alloc the memory for the md5 hashes strings. */
160     nv_data_md5_hash_string = malloc(MD5_STRING_SIZE);
161     nv_data_md5_hash_read = malloc(MD5_STRING_SIZE);
162
163     memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE);
164     memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
165
166     /* Read the content of the backup file. */
167     nv_data_p = file_data_read(ipc_client_nv_data_path(client),
168         ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
169
170     /* Compute the backup file MD5 hash. */
171     nv_data_md5_compute(nv_data_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
172     md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
173
174     /* Read the stored backup file MD5 hash. */
175     fd = open(ipc_client_nv_data_md5_path(client), O_RDONLY);
176     if (fd < 0)
177     {
178         ipc_client_log(client, "nv_data_backup_create: failed to openstored backup file with MD5 hash");
179         goto exit;
180     }
181
182     rc = read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
183     if (rc < 0)
184     {
185         ipc_client_log(client, "nv_data_backup_create: failed to read MD5 hash from backup file");
186         close(fd);
187         goto exit;
188     }
189
190     close(fd);
191
192     /* Add 0x0 to end the string: not sure this is always part of the file. */
193     nv_data_md5_hash_read[MD5_STRING_SIZE - 1] = '\0';
194
195     ipc_client_log(client, "nv_data_backup_create: backup file computed MD5: %s read MD5: %s",
196         nv_data_md5_hash_string, nv_data_md5_hash_read);
197
198     if (strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
199     {
200         ipc_client_log(client, "nv_data_backup_create: MD5 hash mismatch on backup file");
201         ipc_client_log(client, "nv_data_backup_create: Consider the computed one as correct");
202
203         fd = open(ipc_client_nv_data_md5_path(client), O_WRONLY);
204         if (fd < 0)
205         {
206             ipc_client_log(client, "nv_data_backup_create: failed to open file with MD5 hash of data file");
207             goto exit;
208         }
209
210         rc = read(fd, nv_data_md5_hash_string, MD5_STRING_SIZE);
211         if (rc < 0)
212         {
213             ipc_client_log(client, "nv_data_backup_create: failed to read MD5 hash for data file from file");
214             goto exit;
215         }
216
217         close(fd);
218
219         /*
220         nv_data_backup_generate(client);
221         nv_data_backup_create(client);
222         return;
223         */
224     }
225
226     /* Assume the read string is the computated one */
227     memcpy(nv_data_md5_hash_read, nv_data_md5_hash_string, MD5_STRING_SIZE);
228     memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
229
230 nv_data_backup_create_write:
231    while (nv_data_write_tries < 5)
232     {
233         ipc_client_log(client, "nv_data_backup_create: .nv_data.bak write try #%d", nv_data_write_tries + 1);
234
235         fd = open(ipc_client_nv_data_backup_path(client), O_RDWR | O_CREAT | O_TRUNC, 0644);
236         if (fd < 0)
237         {
238             ipc_client_log(client, "nv_data_backup_create: negative fd while opening /efs/.nv_data.bak, error: %s", strerror(errno));
239             nv_data_write_tries++;
240             continue;
241         }
242
243         rc = write(fd, nv_data_p, ipc_client_nv_data_size(client));
244         if (rc < ipc_client_nv_data_size(client))
245         {
246             ipc_client_log(client, "nv_data_backup_create: wrote less (%d) than what we expected (%d) on /efs/.nv_data.bak, error: %s", strerror(errno));
247             close(fd);
248             nv_data_write_tries++;
249             continue;
250         }
251
252         close(fd);
253         break;
254     }
255
256     if (nv_data_write_tries == 5)
257     {
258         ipc_client_log(client, "nv_data_backup_create: writing nv_data.bin to .nv_data.bak failed too many times");
259         unlink(ipc_client_nv_data_backup_path(client));
260         goto exit;
261     }
262
263     /* Read the newly-written .nv_data.bak. */
264     nv_data_bak_p = file_data_read(ipc_client_nv_data_backup_path(client), 
265         ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
266
267     /* Compute the MD5 hash for nv_data.bin. */
268     nv_data_md5_compute(nv_data_bak_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
269     md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
270
271     if (nv_data_bak_p != NULL)
272         free(nv_data_bak_p);
273
274     ipc_client_log(client, "nv_data_backup_create: written file computed MD5: %s read MD5: %s",
275         nv_data_md5_hash_string, nv_data_md5_hash_read);
276
277     /* Make sure both hashes are the same. */
278     if (strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
279     {
280         ipc_client_log(client, "nv_data_backup_create: MD5 hash mismatch on written file");
281         ipc_client_log(client, "nv_data_backup_create: Writing again");
282
283         goto nv_data_backup_create_write;
284     }
285
286     /* Write the MD5 hash in .nv_data.bak.md5. */
287     fd = open(ipc_client_nv_data_backup_md5_path(client), O_WRONLY | O_CREAT | O_TRUNC, 0644);
288     if (fd < 0)
289     {
290         ipc_client_log(client, "nv_data_backup_create: failed to open MD5 hash file");
291         goto exit;
292     }
293
294     rc = write(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
295     if (rc < 0)
296     {
297         ipc_client_log(client, "nv_data_backup_create: failed to write MD5 hash to file");
298         close(fd);
299         goto exit;
300     }
301     close(fd);
302
303 exit:
304     if (nv_data_p != NULL)
305         free(nv_data_p);
306     if (nv_data_md5_hash_string != NULL)
307         free(nv_data_md5_hash_string);
308     if (nv_data_md5_hash_read)
309         free(nv_data_md5_hash_read);
310
311     ipc_client_log(client, "nv_data_backup_create: exit");
312 }
313
314 void nv_data_backup_restore(struct ipc_client *client)
315 {
316     uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
317     char *nv_data_md5_hash_string = NULL;
318     char *nv_data_md5_hash_read = NULL;
319     int nv_data_write_tries = 0;
320
321     struct stat nv_stat;
322     void *nv_data_p = NULL;
323     void *nv_data_bak_p = NULL;
324     uint8_t data;
325
326     int fd;
327     int rc;
328     int i;
329
330     ipc_client_log(client, "nv_data_backup_restore: enter");
331
332     if (stat(ipc_client_nv_data_backup_path(client), &nv_stat) < 0)
333     {
334         ipc_client_log(client, "nv_data_backup_restore: .nv_data.bak missing");
335         nv_data_generate(client);
336         nv_data_backup_create(client);
337         return;
338     }
339
340     if (nv_stat.st_size != ipc_client_nv_data_size(client))
341     {
342         ipc_client_log(client, "nv_data_backup_restore: wrong .nv_data.bak size");
343         nv_data_generate(client);
344         nv_data_backup_create(client);
345         return;
346     }
347
348     if (stat(ipc_client_nv_data_backup_md5_path(client), &nv_stat) < 0)
349     {
350         ipc_client_log(client, "nv_data_backup_restore: .nv_data.bak.md5 missing");
351         nv_data_generate(client);
352         nv_data_backup_create(client);
353         return;
354     }
355
356     /* Alloc the memory for the md5 hashes strings. */
357     nv_data_md5_hash_string = malloc(MD5_STRING_SIZE);
358     nv_data_md5_hash_read = malloc(MD5_STRING_SIZE);
359
360     memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE);
361     memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
362
363     /* Read the content of the backup file. */
364     nv_data_bak_p = file_data_read(ipc_client_nv_data_backup_path(client),
365         ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
366
367     /* Compute the backup file MD5 hash. */
368     nv_data_md5_compute(nv_data_bak_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
369     md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
370
371     /* Read the stored backup file MD5 hash. */
372     fd = open(ipc_client_nv_data_backup_md5_path(client), O_RDONLY);
373     rc = read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
374     if (rc < 0)
375     {
376         ipc_client_log(client, "nv_data_backup_restore: Failed to read md5 hash for stored back file");
377         close(fd);
378         goto exit;
379     }
380
381     close(fd);
382
383     /* Add 0x0 to end the string: not sure this is always part of the file. */
384     nv_data_md5_hash_read[MD5_STRING_SIZE - 1] = '\0';
385
386     ipc_client_log(client, "nv_data_backup_restore: backup file computed MD5: %s read MD5: %s",
387         nv_data_md5_hash_string, nv_data_md5_hash_read);
388
389     if (strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
390     {
391         ipc_client_log(client, "nv_data_backup_restore: MD5 hash mismatch on backup file");
392         ipc_client_log(client, "nv_data_backup_restore: Consider the computed one as correct");
393
394         fd = open(ipc_client_nv_data_backup_md5_path(client), O_WRONLY);
395         if (fd < 0)
396         {
397             ipc_client_log(client, "nv_data_backup_restore: failed to open MD5 hash backup file");
398             goto exit;
399         }
400
401         rc = read(fd, nv_data_md5_hash_string, MD5_STRING_SIZE);
402         if (rc < 0)
403         {
404             ipc_client_log(client, "nv_data_backup_restore: failed to read MD5 hash from backup file");
405             close(fd);
406             goto exit;
407         }
408
409         close(fd);
410
411         /*
412         nv_data_backup_generate(client);
413         nv_data_backup_create(client);
414         return;
415         */
416     }
417
418     /* Assume the read string is the computated one */
419     memcpy(nv_data_md5_hash_read, nv_data_md5_hash_string, MD5_STRING_SIZE);
420     memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
421
422 nv_data_backup_restore_write:
423    while (nv_data_write_tries < 5)
424     {
425         ipc_client_log(client, "nv_data_backup_restore: nv_data.bin write try #%d", nv_data_write_tries + 1);
426
427         fd = open(ipc_client_nv_data_path(client), O_RDWR | O_CREAT | O_TRUNC, 0644);
428         if (fd < 0)
429         {
430             ipc_client_log(client, "nv_data_backup_restore: negative fd while opening /efs/nv_data.bin, error: %s", strerror(errno));
431             nv_data_write_tries++;
432             continue;
433         }
434
435         rc = write(fd, nv_data_bak_p, ipc_client_nv_data_size(client));
436         if (rc < ipc_client_nv_data_size(client))
437         {
438             ipc_client_log(client, "nv_data_backup_restore: wrote less (%d) than what we expected (%d) on /efs/nv_data.bin, error: %s", strerror(errno));
439             close(fd);
440             nv_data_write_tries++;
441             continue;
442         }
443
444         close(fd);
445         break;
446     }
447
448     if (nv_data_write_tries == 5)
449     {
450         ipc_client_log(client, "nv_data_backup_restore: writing the backup to nv_data.bin failed too many times");
451         unlink(ipc_client_nv_data_path(client));
452         goto exit;
453     }
454
455     /* Read the newly-written nv_data.bin. */
456     nv_data_p = file_data_read(ipc_client_nv_data_path(client),
457         ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
458
459     /* Compute the MD5 hash for nv_data.bin. */
460     nv_data_md5_compute(nv_data_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
461     md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
462
463     if (nv_data_p != NULL)
464     {
465         free(nv_data_p);
466         nv_data_p = NULL;
467     }
468
469     ipc_client_log(client, "nv_data_backup_restore: written file computed MD5: %s read MD5: %s",
470         nv_data_md5_hash_string, nv_data_md5_hash_read);
471
472     /* Make sure both hashes are the same. */
473     if (strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
474     {
475         ipc_client_log(client, "nv_data_backup_restore: MD5 hash mismatch on written file");
476         ipc_client_log(client, "nv_data_backup_restore: Writing again");
477
478         goto nv_data_backup_restore_write;
479     }
480
481     /* Write the MD5 hash in nv_data.bin.md5. */
482     fd = open(ipc_client_nv_data_md5_path(client), O_WRONLY | O_CREAT | O_TRUNC, 0644);
483     if (fd < 0)
484     {
485         ipc_client_log(client, "nv_data_backup_restore: failed to open file with MD5 hash");
486         goto exit;
487     }
488
489     rc = write(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
490     if (rc < 0)
491     {
492         ipc_client_log(client, "nv_data_backup_restore: failed to write MD5 hash to file");
493         close(fd);
494         goto exit;
495     }
496     close(fd);
497
498 exit:
499     if (nv_data_bak_p != NULL)
500         free(nv_data_bak_p);
501     if (nv_data_md5_hash_string != NULL)
502         free(nv_data_md5_hash_string);
503     if (nv_data_md5_hash_read != NULL)
504         free(nv_data_md5_hash_read);
505
506     ipc_client_log(client, "nv_data_backup_restore: exit");
507 }
508
509 int nv_data_check(struct ipc_client *client)
510 {
511     struct stat nv_stat;
512     int rc;
513
514     ipc_client_log(client, "nv_data_check: enter");
515
516     if (stat(ipc_client_nv_data_path(client), &nv_stat) < 0)
517     {
518         ipc_client_log(client, "nv_data_check: nv_data.bin missing");
519         nv_data_backup_restore(client);
520         stat(ipc_client_nv_data_path(client), &nv_stat);
521     }
522
523     if (nv_stat.st_size != ipc_client_nv_data_size(client))
524     {
525         ipc_client_log(client, "nv_data_check: wrong nv_data.bin size");
526         nv_data_backup_restore(client);
527     }
528
529     if (stat(ipc_client_nv_data_md5_path(client), &nv_stat) < 0)
530     {
531         ipc_client_log(client, "nv_data_check: nv_data.bin.md5 missing");
532         nv_data_backup_restore(client);
533     }
534
535     if (stat(ipc_client_nv_data_backup_path(client), &nv_stat) < 0 || stat(ipc_client_nv_data_backup_md5_path(client), &nv_stat) < 0)
536     {
537         ipc_client_log(client, "nv_data_check: .nv_data.bak or .nv_data.bak.md5 missing");
538         nv_data_backup_create(client);
539     }
540
541     ipc_client_log(client, "nv_data_check: everything should be alright");
542     ipc_client_log(client, "nv_data_check: exit");
543
544     return 0;
545 }
546
547 int nv_data_md5_check(struct ipc_client *client)
548 {
549     struct stat nv_stat;
550     uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
551     char *nv_data_md5_hash_string = NULL;
552     char *nv_data_md5_hash_read = NULL;
553     void *nv_data_p = NULL;
554     int fd;
555     int rc;
556     uint8_t *data_p;
557
558     ipc_client_log(client, "nv_data_md5_check: enter");
559
560     nv_data_md5_hash_string = malloc(MD5_STRING_SIZE);
561     nv_data_md5_hash_read = malloc(MD5_STRING_SIZE);
562
563     memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE);
564     memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
565
566     nv_data_p = file_data_read(ipc_client_nv_data_path(client),
567         ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
568     data_p = nv_data_p;
569
570     nv_data_md5_compute(data_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
571
572     md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
573
574     free(nv_data_p);
575
576     fd = open(ipc_client_nv_data_md5_path(client), O_RDONLY);
577
578     /* Read the md5 stored in the file. */
579     rc = read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
580     if (rc < 0)
581     {
582         ipc_client_log(client, "nv_data_md5_check: Can't read md5 hash from file");
583         return -1;
584     }
585
586     /* Add 0x0 to end the string: not sure this is part of the file. */
587     nv_data_md5_hash_read[MD5_STRING_SIZE - 1] = '\0';
588
589     ipc_client_log(client, "nv_data_md5_check: computed MD5: %s read MD5: %s", 
590         nv_data_md5_hash_string, nv_data_md5_hash_read);
591
592     if (strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
593     {
594         ipc_client_log(client, "nv_data_md5_check: MD5 hash mismatch");
595         nv_data_backup_restore(client);
596     }
597
598     if (nv_data_md5_hash_string != NULL)
599         free(nv_data_md5_hash_string);
600     if (nv_data_md5_hash_read != NULL)
601         free(nv_data_md5_hash_read);
602
603     ipc_client_log(client, "nv_data_md5_check: exit");
604
605     return 0;
606 }
607
608 int nv_data_read(struct ipc_client *client, int offset, int length, char *buf)
609 {
610     int fd;
611     int rc;
612
613     ipc_client_log(client, "nv_data_read: enter");
614
615     if (offset < 0 || length <= 0) {
616         ipc_client_log(client, "nv_data_read: offset < 0 or length <= 0");
617         return -1;
618     }
619
620     if (buf == NULL) {
621         ipc_client_log(client, "nv_data_read: provided output buf is NULL");
622         return -1;
623     }
624
625     if (nv_data_check(client) < 0)
626         return -1;
627
628     fd = open(ipc_client_nv_data_path(client), O_RDONLY);
629     if (fd < 0) {
630         ipc_client_log(client, "nv_data_read: nv_data file fd is negative");
631         return -1;
632     }
633
634     lseek(fd, offset, SEEK_SET);
635
636     rc = read(fd, buf, length);
637     if (rc < length) {
638         ipc_client_log(client, "nv_data_read: read less than what we expected");
639         return -1;
640     }
641
642     ipc_client_log(client, "nv_data_read: exit");
643
644     return 0;
645 }
646
647 int nv_data_write(struct ipc_client *client, int offset, int length, char *buf)
648 {
649     int fd;
650     int rc;
651
652     ipc_client_log(client, "nv_data_write: enter");
653
654     if (offset < 0 || length <= 0) {
655         ipc_client_log(client, "nv_data_write: offset or length <= 0");
656         return -1;
657     }
658
659     if (buf == NULL) {
660         ipc_client_log(client, "nv_data_write: provided input buf is NULL");
661         return -1;
662     }
663
664     if (nv_data_check(client) < 0)
665         return -1;
666
667     fd = open(ipc_client_nv_data_path(client), O_WRONLY);
668     if (fd < 0) {
669         ipc_client_log(client, "nv_data_write: nv_data file fd is negative");
670         return -1;
671     }
672
673     lseek(fd, offset, SEEK_SET);
674
675     rc = write(fd, buf, length);
676
677     close(fd);
678
679     if (rc < length) {
680         ipc_client_log(client, "nv_data_write: wrote less (%d) than what we expected (%d), error: %s, restoring backup", rc, length, strerror(errno));
681         nv_data_backup_restore(client);
682         return -1;
683     }
684
685     ipc_client_log(client, "nv_data_write: writing new md5sum");
686     nv_data_md5_generate(client);
687
688     ipc_client_log(client, "nv_data_write: exit");
689
690     return 0;
691 }
692
693 void ipc_rfs_send_io_confirm_for_nv_read_item(struct ipc_client *client,
694     struct ipc_message_info *info)
695 {
696     struct ipc_rfs_nv_read_item_data *rfs_io = (struct ipc_rfs_nv_read_item_data *) info->data;
697     struct ipc_rfs_nv_read_item_confirm_header *rfs_io_conf;
698     void *rfs_data;
699     int rc;
700
701     if (rfs_io == NULL)
702     {
703         ipc_client_log(client, "ERROR: Request message is invalid: aseq = %i", info->aseq);
704         return;
705     }
706
707     rfs_io_conf = malloc(rfs_io->length + sizeof(struct ipc_rfs_nv_read_item_confirm_header));
708     memset(rfs_io_conf, 0, rfs_io->length + sizeof(struct ipc_rfs_nv_read_item_confirm_header));
709     rfs_data = rfs_io_conf + sizeof(struct ipc_rfs_nv_read_item_confirm_header);
710
711     ipc_client_log(client, "Asked to read 0x%x bytes at offset 0x%x", rfs_io->length, rfs_io->offset);
712     rc = nv_data_read(client, rfs_io->offset, rfs_io->length, rfs_data);
713
714 #ifdef DEBUG
715     ipc_client_log(client, "Read rfs_data dump:");
716     ipc_client_hex_dump(client, rfs_data, rfs_io->length);
717 #endif
718
719     ipc_client_log(client, "Preparing RFS IO Confirm message (rc is %d)", rc);
720     rfs_io_conf->confirm = rc < 0 ? 0 : 1;
721     rfs_io_conf->offset = rfs_io->offset;
722     rfs_io_conf->length = rfs_io->length;
723
724     ipc_client_send(client, IPC_RFS_NV_READ_ITEM, 0, (unsigned char *) rfs_io_conf,
725                     rfs_io->length + sizeof(struct ipc_rfs_nv_read_item_confirm_header), info->aseq);
726     free(rfs_io_conf);
727 }
728
729 void ipc_rfs_send_io_confirm_for_nv_write_item(struct ipc_client *client,
730     struct ipc_message_info *info)
731 {
732     struct ipc_rfs_nv_read_item_confirm_header *rfs_io = (struct ipc_rfs_nv_read_item_confirm_header *) info->data;
733     struct ipc_rfs_nv_write_item_confirm_data *rfs_io_conf;
734     void *rfs_data;
735     int rc;
736
737     if (rfs_io == NULL)
738     {
739         ipc_client_log(client, "ERROR: Request message is invalid: aseq = %i", info->aseq);
740         return;
741     }
742
743     rfs_data = info->data + sizeof(struct ipc_rfs_nv_read_item_confirm_header);
744
745 #ifdef DEBUG
746     ipc_client_log(client, "Write rfs_data dump:");
747     ipc_client_hex_dump(client, rfs_data, rfs_io->length);
748 #endif
749
750     ipc_client_log(client, "Asked to write 0x%x bytes at offset 0x%x", rfs_io->length, rfs_io->offset);
751     rc = nv_data_write(client, rfs_io->offset, rfs_io->length, rfs_data);
752
753     ipc_client_log(client, "Sending RFS IO Confirm message (rc is %d)", rc);
754     rfs_io_conf = (struct ipc_rfs_nv_write_item_confirm_data *) malloc(sizeof(struct ipc_rfs_nv_write_item_confirm_data));
755     rfs_io_conf->confirm = rc < 0 ? 0 : 1;
756     rfs_io_conf->offset = rfs_io->offset;
757     rfs_io_conf->length = rfs_io->length;
758
759     ipc_client_send(client, IPC_RFS_NV_WRITE_ITEM, 0, (unsigned char *) rfs_io_conf,
760                     sizeof(struct ipc_rfs_nv_write_item_confirm_data), info->aseq);
761     free(rfs_io_conf);
762 }
763
764 // vim:ts=4:sw=4:expandtab