sms: Use __ofono_atom_find
[platform/upstream/ofono.git] / src / simfs.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program 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 this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #define _GNU_SOURCE
27 #include <string.h>
28 #include <stdio.h>
29
30 #include <glib.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <dirent.h>
37
38 #include "ofono.h"
39
40 #include "simfs.h"
41 #include "simutil.h"
42 #include "storage.h"
43
44 #define SIM_CACHE_MODE 0600
45 #define SIM_CACHE_BASEPATH STORAGEDIR "/%s-%i"
46 #define SIM_CACHE_VERSION SIM_CACHE_BASEPATH "/version"
47 #define SIM_CACHE_PATH SIM_CACHE_BASEPATH "/%04x"
48 #define SIM_CACHE_HEADER_SIZE 39
49 #define SIM_FILE_INFO_SIZE 7
50 #define SIM_IMAGE_CACHE_BASEPATH STORAGEDIR "/%s-%i/images"
51 #define SIM_IMAGE_CACHE_PATH SIM_IMAGE_CACHE_BASEPATH "/%d.xpm"
52
53 #define SIM_FS_VERSION 2
54
55 static gboolean sim_fs_op_next(gpointer user_data);
56 static gboolean sim_fs_op_read_record(gpointer user);
57 static gboolean sim_fs_op_read_block(gpointer user_data);
58
59 struct sim_fs_op {
60         int id;
61         unsigned char *buffer;
62         enum ofono_sim_file_structure structure;
63         unsigned short offset;
64         gboolean info_only;
65         int num_bytes;
66         int length;
67         int record_length;
68         int current;
69         gconstpointer cb;
70         gboolean is_read;
71         void *userdata;
72         struct ofono_sim_context *context;
73 };
74
75 static void sim_fs_op_free(struct sim_fs_op *node)
76 {
77         g_free(node->buffer);
78         g_free(node);
79 }
80
81 struct sim_fs {
82         GQueue *op_q;
83         gint op_source;
84         unsigned char bitmap[32];
85         int fd;
86         struct ofono_sim *sim;
87         const struct ofono_sim_driver *driver;
88         GSList *contexts;
89 };
90
91 void sim_fs_free(struct sim_fs *fs)
92 {
93         if (fs == NULL)
94                 return;
95
96         if (fs->op_source) {
97                 g_source_remove(fs->op_source);
98                 fs->op_source = 0;
99         }
100
101         /*
102          * Note: users of sim_fs must not assume that the callback happens
103          * for operations still in progress
104          */
105         if (fs->op_q) {
106                 g_queue_foreach(fs->op_q, (GFunc) sim_fs_op_free, NULL);
107                 g_queue_free(fs->op_q);
108                 fs->op_q = NULL;
109         }
110
111         while (fs->contexts)
112                 sim_fs_context_free(fs->contexts->data);
113
114         g_free(fs);
115 }
116
117 struct file_watch {
118         struct ofono_watchlist_item item;
119         int ef;
120 };
121
122 struct ofono_sim_context {
123         struct sim_fs *fs;
124         struct ofono_watchlist *file_watches;
125 };
126
127 struct sim_fs *sim_fs_new(struct ofono_sim *sim,
128                                 const struct ofono_sim_driver *driver)
129 {
130         struct sim_fs *fs;
131
132         fs = g_try_new0(struct sim_fs, 1);
133         if (fs == NULL)
134                 return NULL;
135
136         fs->sim = sim;
137         fs->driver = driver;
138         fs->fd = -1;
139
140         return fs;
141 }
142
143 struct ofono_sim_context *sim_fs_context_new(struct sim_fs *fs)
144 {
145         struct ofono_sim_context *context =
146                 g_try_new0(struct ofono_sim_context, 1);
147
148         if (context == NULL)
149                 return NULL;
150
151         context->fs = fs;
152         fs->contexts = g_slist_prepend(fs->contexts, context);
153
154         return context;
155 }
156
157 void sim_fs_context_free(struct ofono_sim_context *context)
158 {
159         struct sim_fs *fs = context->fs;
160         int n = 0;
161         struct sim_fs_op *op;
162
163         if (fs->op_q) {
164                 while ((op = g_queue_peek_nth(fs->op_q, n)) != NULL) {
165                         if (op->context != context) {
166                                 n += 1;
167                                 continue;
168                         }
169
170                         if (n == 0) {
171                                 op->cb = NULL;
172
173                                 n += 1;
174                                 continue;
175                         }
176
177                         sim_fs_op_free(op);
178                         g_queue_remove(fs->op_q, op);
179                 }
180         }
181
182         if (context->file_watches)
183                 __ofono_watchlist_free(context->file_watches);
184
185         fs->contexts = g_slist_remove(fs->contexts, context);
186         g_free(context);
187 }
188
189 unsigned int sim_fs_file_watch_add(struct ofono_sim_context *context, int id,
190                                         ofono_sim_file_changed_cb_t cb,
191                                         void *userdata,
192                                         ofono_destroy_func destroy)
193 {
194         struct file_watch *watch;
195
196         if (cb == NULL)
197                 return 0;
198
199         if (context->file_watches == NULL)
200                 context->file_watches = __ofono_watchlist_new(g_free);
201
202         watch = g_new0(struct file_watch, 1);
203
204         watch->ef = id;
205         watch->item.notify = cb;
206         watch->item.notify_data = userdata;
207         watch->item.destroy = destroy;
208
209         return __ofono_watchlist_add_item(context->file_watches,
210                                         (struct ofono_watchlist_item *) watch);
211 }
212
213 void sim_fs_file_watch_remove(struct ofono_sim_context *context,
214                                 unsigned int id)
215 {
216         __ofono_watchlist_remove_item(context->file_watches, id);
217 }
218
219 void sim_fs_notify_file_watches(struct sim_fs *fs, int id)
220 {
221         GSList *l;
222
223         for (l = fs->contexts; l; l = l->next) {
224                 struct ofono_sim_context *context = l->data;
225                 GSList *k;
226
227                 for (k = context->file_watches->items; k; k = k->next) {
228                         struct file_watch *w = k->data;
229                         ofono_sim_file_changed_cb_t notify = w->item.notify;
230
231                         if (id == -1 || w->ef == id)
232                                 notify(w->ef, w->item.notify_data);
233                 }
234         }
235
236 }
237
238 static void sim_fs_end_current(struct sim_fs *fs)
239 {
240         struct sim_fs_op *op = g_queue_pop_head(fs->op_q);
241
242         if (g_queue_get_length(fs->op_q) > 0)
243                 fs->op_source = g_idle_add(sim_fs_op_next, fs);
244
245         if (fs->fd != -1) {
246                 TFR(close(fs->fd));
247                 fs->fd = -1;
248         }
249
250         memset(fs->bitmap, 0, sizeof(fs->bitmap));
251
252         sim_fs_op_free(op);
253 }
254
255 static void sim_fs_op_error(struct sim_fs *fs)
256 {
257         struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
258
259         if (op->cb == NULL) {
260                 sim_fs_end_current(fs);
261                 return;
262         }
263
264         if (op->info_only == TRUE)
265                 ((sim_fs_read_info_cb_t) op->cb)
266                         (0, 0, 0, 0, op->userdata);
267         else if (op->is_read == TRUE)
268                 ((ofono_sim_file_read_cb_t) op->cb)
269                         (0, 0, 0, 0, 0, op->userdata);
270         else
271                 ((ofono_sim_file_write_cb_t) op->cb)
272                         (0, op->userdata);
273
274         sim_fs_end_current(fs);
275 }
276
277 static gboolean cache_block(struct sim_fs *fs, int block, int block_len,
278                                 const unsigned char *data, int num_bytes)
279 {
280         int offset;
281         int bit;
282         ssize_t r;
283         unsigned char b;
284
285         if (fs->fd == -1)
286                 return FALSE;
287
288         if (lseek(fs->fd, block * block_len +
289                                 SIM_CACHE_HEADER_SIZE, SEEK_SET) == (off_t) -1)
290                 return FALSE;
291
292         r = TFR(write(fs->fd, data, num_bytes));
293
294         if (r != num_bytes)
295                 return FALSE;
296
297         /* update present bit for this block */
298         offset = block / 8;
299         bit = block % 8;
300
301         /* lseek to correct byte (skip file info) */
302         lseek(fs->fd, offset + SIM_FILE_INFO_SIZE, SEEK_SET);
303
304         b = fs->bitmap[offset];
305         b |= 1 << bit;
306
307         r = TFR(write(fs->fd, &b, sizeof(b)));
308
309         if (r != sizeof(b))
310                 return FALSE;
311
312         fs->bitmap[offset] = b;
313
314         return TRUE;
315 }
316
317 static void sim_fs_op_write_cb(const struct ofono_error *error, void *data)
318 {
319         struct sim_fs *fs = data;
320         struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
321         ofono_sim_file_write_cb_t cb = op->cb;
322
323         if (cb == NULL) {
324                 sim_fs_end_current(fs);
325                 return;
326         }
327
328         if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
329                 cb(1, op->userdata);
330         else
331                 cb(0, op->userdata);
332
333         sim_fs_end_current(fs);
334 }
335
336 static void sim_fs_op_read_block_cb(const struct ofono_error *error,
337                                         const unsigned char *data, int len,
338                                         void *user)
339 {
340         struct sim_fs *fs = user;
341         struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
342         int start_block;
343         int end_block;
344         int bufoff;
345         int dataoff;
346         int tocopy;
347
348         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
349                 sim_fs_op_error(fs);
350                 return;
351         }
352
353         start_block = op->offset / 256;
354         end_block = (op->offset + (op->num_bytes - 1)) / 256;
355
356         if (op->current == start_block) {
357                 bufoff = 0;
358                 dataoff = op->offset % 256;
359                 tocopy = MIN(256 - op->offset % 256,
360                                 op->num_bytes - op->current * 256);
361         } else {
362                 bufoff = (op->current - start_block - 1) * 256 +
363                                 op->offset % 256;
364                 dataoff = 0;
365                 tocopy = MIN(256, op->num_bytes - op->current * 256);
366         }
367
368         DBG("bufoff: %d, dataoff: %d, tocopy: %d",
369                                 bufoff, dataoff, tocopy);
370
371         memcpy(op->buffer + bufoff, data + dataoff, tocopy);
372         cache_block(fs, op->current, 256, data, len);
373
374         if (op->cb == NULL) {
375                 sim_fs_end_current(fs);
376                 return;
377         }
378
379         op->current++;
380
381         if (op->current > end_block) {
382                 ofono_sim_file_read_cb_t cb = op->cb;
383
384                 cb(1, op->num_bytes, 0, op->buffer,
385                                 op->record_length, op->userdata);
386
387                 sim_fs_end_current(fs);
388         } else {
389                 fs->op_source = g_idle_add(sim_fs_op_read_block, fs);
390         }
391 }
392
393 static gboolean sim_fs_op_read_block(gpointer user_data)
394 {
395         struct sim_fs *fs = user_data;
396         struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
397         int start_block;
398         int end_block;
399         unsigned short read_bytes;
400
401         fs->op_source = 0;
402
403         if (op->cb == NULL) {
404                 sim_fs_end_current(fs);
405                 return FALSE;
406         }
407
408         start_block = op->offset / 256;
409         end_block = (op->offset + (op->num_bytes - 1)) / 256;
410
411         if (op->current == start_block) {
412                 op->buffer = g_try_new0(unsigned char, op->num_bytes);
413
414                 if (op->buffer == NULL) {
415                         sim_fs_op_error(fs);
416                         return FALSE;
417                 }
418         }
419
420         while (fs->fd != -1 && op->current <= end_block) {
421                 int offset = op->current / 8;
422                 int bit = 1 << op->current % 8;
423                 int bufoff;
424                 int seekoff;
425                 int toread;
426
427                 if ((fs->bitmap[offset] & bit) == 0)
428                         break;
429
430                 if (op->current == start_block) {
431                         bufoff = 0;
432                         seekoff = SIM_CACHE_HEADER_SIZE + op->current * 256 +
433                                 op->offset % 256;
434                         toread = MIN(256 - op->offset % 256,
435                                         op->num_bytes - op->current * 256);
436                 } else {
437                         bufoff = (op->current - start_block - 1) * 256 +
438                                         op->offset % 256;
439                         seekoff = SIM_CACHE_HEADER_SIZE + op->current * 256;
440                         toread = MIN(256, op->num_bytes - op->current * 256);
441                 }
442
443                 DBG("bufoff: %d, seekoff: %d, toread: %d",
444                                 bufoff, seekoff, toread);
445
446                 if (lseek(fs->fd, seekoff, SEEK_SET) == (off_t) -1)
447                         break;
448
449                 if (TFR(read(fs->fd, op->buffer + bufoff, toread)) != toread)
450                         break;
451
452                 op->current += 1;
453         }
454
455         if (op->current > end_block) {
456                 ofono_sim_file_read_cb_t cb = op->cb;
457
458                 cb(1, op->num_bytes, 0, op->buffer,
459                                 op->record_length, op->userdata);
460
461                 sim_fs_end_current(fs);
462
463                 return FALSE;
464         }
465
466         if (fs->driver->read_file_transparent == NULL) {
467                 sim_fs_op_error(fs);
468                 return FALSE;
469         }
470
471         read_bytes = MIN(op->length - op->current * 256, 256);
472         fs->driver->read_file_transparent(fs->sim, op->id,
473                                                 op->current * 256,
474                                                 read_bytes,
475                                                 sim_fs_op_read_block_cb, fs);
476
477         return FALSE;
478 }
479
480 static void sim_fs_op_retrieve_cb(const struct ofono_error *error,
481                                         const unsigned char *data, int len,
482                                         void *user)
483 {
484         struct sim_fs *fs = user;
485         struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
486         int total = op->length / op->record_length;
487         ofono_sim_file_read_cb_t cb = op->cb;
488
489         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
490                 sim_fs_op_error(fs);
491                 return;
492         }
493
494         cache_block(fs, op->current - 1, op->record_length,
495                         data, op->record_length);
496
497         if (cb == NULL) {
498                 sim_fs_end_current(fs);
499                 return;
500         }
501
502         cb(1, op->length, op->current, data, op->record_length, op->userdata);
503
504         if (op->current < total) {
505                 op->current += 1;
506                 fs->op_source = g_idle_add(sim_fs_op_read_record, fs);
507         } else {
508                 sim_fs_end_current(fs);
509         }
510 }
511
512 static gboolean sim_fs_op_read_record(gpointer user)
513 {
514         struct sim_fs *fs = user;
515         struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
516         const struct ofono_sim_driver *driver = fs->driver;
517         int total = op->length / op->record_length;
518         unsigned char buf[256];
519
520         fs->op_source = 0;
521
522         if (op->cb == NULL) {
523                 sim_fs_end_current(fs);
524                 return FALSE;
525         }
526
527         while (fs->fd != -1 && op->current <= total) {
528                 int offset = (op->current - 1) / 8;
529                 int bit = 1 << ((op->current - 1) % 8);
530                 ofono_sim_file_read_cb_t cb = op->cb;
531
532                 if ((fs->bitmap[offset] & bit) == 0)
533                         break;
534
535                 if (lseek(fs->fd, (op->current - 1) * op->record_length +
536                                 SIM_CACHE_HEADER_SIZE, SEEK_SET) == (off_t) -1)
537                         break;
538
539                 if (TFR(read(fs->fd, buf, op->record_length)) !=
540                                 op->record_length)
541                         break;
542
543                 cb(1, op->length, op->current,
544                                 buf, op->record_length, op->userdata);
545
546                 op->current += 1;
547         }
548
549         if (op->current > total) {
550                 sim_fs_end_current(fs);
551
552                 return FALSE;
553         }
554
555         switch (op->structure) {
556         case OFONO_SIM_FILE_STRUCTURE_FIXED:
557                 if (driver->read_file_linear == NULL) {
558                         sim_fs_op_error(fs);
559                         return FALSE;
560                 }
561
562                 driver->read_file_linear(fs->sim, op->id, op->current,
563                                                 op->record_length,
564                                                 sim_fs_op_retrieve_cb, fs);
565                 break;
566         case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
567                 if (driver->read_file_cyclic == NULL) {
568                         sim_fs_op_error(fs);
569                         return FALSE;
570                 }
571
572                 driver->read_file_cyclic(fs->sim, op->id, op->current,
573                                                 op->record_length,
574                                                 sim_fs_op_retrieve_cb, fs);
575                 break;
576         default:
577                 ofono_error("Unrecognized file structure, this can't happen");
578         }
579
580         return FALSE;
581 }
582
583 static void sim_fs_op_cache_fileinfo(struct sim_fs *fs,
584                                         const struct ofono_error *error,
585                                         int length,
586                                         enum ofono_sim_file_structure structure,
587                                         int record_length,
588                                         const unsigned char access[3],
589                                         unsigned char file_status)
590 {
591         struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
592         const char *imsi = ofono_sim_get_imsi(fs->sim);
593         enum ofono_sim_phase phase = ofono_sim_get_phase(fs->sim);
594         enum sim_file_access update;
595         enum sim_file_access invalidate;
596         enum sim_file_access rehabilitate;
597         unsigned char fileinfo[SIM_CACHE_HEADER_SIZE];
598         gboolean cache;
599         char *path;
600
601         /* TS 11.11, Section 9.3 */
602         update = file_access_condition_decode(access[0] & 0xf);
603         rehabilitate = file_access_condition_decode((access[2] >> 4) & 0xf);
604         invalidate = file_access_condition_decode(access[2] & 0xf);
605
606         /* Never cache card holder writable files */
607         cache = (update == SIM_FILE_ACCESS_ADM ||
608                         update == SIM_FILE_ACCESS_NEVER) &&
609                         (invalidate == SIM_FILE_ACCESS_ADM ||
610                                 invalidate == SIM_FILE_ACCESS_NEVER) &&
611                         (rehabilitate == SIM_FILE_ACCESS_ADM ||
612                                 rehabilitate == SIM_FILE_ACCESS_NEVER);
613
614         if (imsi == NULL || phase == OFONO_SIM_PHASE_UNKNOWN || cache == FALSE)
615                 return;
616
617         memset(fileinfo, 0, SIM_CACHE_HEADER_SIZE);
618
619         fileinfo[0] = error->type;
620         fileinfo[1] = length >> 8;
621         fileinfo[2] = length & 0xff;
622         fileinfo[3] = structure;
623         fileinfo[4] = record_length >> 8;
624         fileinfo[5] = record_length & 0xff;
625         fileinfo[6] = file_status;
626
627         path = g_strdup_printf(SIM_CACHE_PATH, imsi, phase, op->id);
628         fs->fd = TFR(open(path, O_WRONLY | O_CREAT | O_TRUNC, SIM_CACHE_MODE));
629         g_free(path);
630
631         if (fs->fd == -1)
632                 return;
633
634         if (TFR(write(fs->fd, fileinfo, SIM_CACHE_HEADER_SIZE)) ==
635                         SIM_CACHE_HEADER_SIZE)
636                 return;
637
638         TFR(close(fs->fd));
639         fs->fd = -1;
640 }
641
642 static void sim_fs_op_info_cb(const struct ofono_error *error, int length,
643                                 enum ofono_sim_file_structure structure,
644                                 int record_length,
645                                 const unsigned char access[3],
646                                 unsigned char file_status,
647                                 void *data)
648 {
649         struct sim_fs *fs = data;
650         struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
651
652         if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
653                 sim_fs_op_error(fs);
654                 return;
655         }
656
657         sim_fs_op_cache_fileinfo(fs, error, length, structure, record_length,
658                                         access, file_status);
659
660         if (structure != op->structure) {
661                 ofono_error("Requested file structure differs from SIM: %x",
662                                 op->id);
663                 sim_fs_op_error(fs);
664                 return;
665         }
666
667         if (op->cb == NULL) {
668                 sim_fs_end_current(fs);
669                 return;
670         }
671
672         op->structure = structure;
673         op->length = length;
674
675         if (structure == OFONO_SIM_FILE_STRUCTURE_TRANSPARENT) {
676                 if (op->num_bytes == 0)
677                         op->num_bytes = op->length;
678
679                 op->record_length = length;
680                 op->current = op->offset / 256;
681
682                 if (op->info_only == FALSE)
683                         fs->op_source = g_idle_add(sim_fs_op_read_block, fs);
684         } else {
685                 op->record_length = record_length;
686                 op->current = 1;
687
688                 if (op->info_only == FALSE)
689                         fs->op_source = g_idle_add(sim_fs_op_read_record, fs);
690         }
691
692         if (op->info_only == TRUE) {
693                 /*
694                  * It's an info-only request, so there is no need to request
695                  * actual contents of the EF. Just return the EF-info.
696                  */
697                 sim_fs_read_info_cb_t cb = op->cb;
698
699                 cb(1, file_status, op->length,
700                         op->record_length, op->userdata);
701
702                 sim_fs_end_current(fs);
703         }
704 }
705
706 static gboolean sim_fs_op_check_cached(struct sim_fs *fs)
707 {
708         const char *imsi = ofono_sim_get_imsi(fs->sim);
709         enum ofono_sim_phase phase = ofono_sim_get_phase(fs->sim);
710         struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
711         char *path;
712         int fd;
713         ssize_t len;
714         unsigned char fileinfo[SIM_CACHE_HEADER_SIZE];
715         int error_type;
716         int file_length;
717         enum ofono_sim_file_structure structure;
718         int record_length;
719         unsigned char file_status;
720
721         if (imsi == NULL || phase == OFONO_SIM_PHASE_UNKNOWN)
722                 return FALSE;
723
724         path = g_strdup_printf(SIM_CACHE_PATH, imsi, phase, op->id);
725
726         if (path == NULL)
727                 return FALSE;
728
729         fd = TFR(open(path, O_RDWR));
730         g_free(path);
731
732         if (fd == -1) {
733                 if (errno != ENOENT)
734                         DBG("Error %i opening cache file for "
735                                         "fileid %04x, IMSI %s",
736                                         errno, op->id, imsi);
737
738                 return FALSE;
739         }
740
741         len = TFR(read(fd, fileinfo, SIM_CACHE_HEADER_SIZE));
742
743         if (len != SIM_CACHE_HEADER_SIZE)
744                 goto error;
745
746         error_type = fileinfo[0];
747         file_length = (fileinfo[1] << 8) | fileinfo[2];
748         structure = fileinfo[3];
749         record_length = (fileinfo[4] << 8) | fileinfo[5];
750         file_status = fileinfo[6];
751
752         if (structure == OFONO_SIM_FILE_STRUCTURE_TRANSPARENT)
753                 record_length = file_length;
754
755         if (record_length == 0 || file_length < record_length)
756                 goto error;
757
758         op->length = file_length;
759         op->record_length = record_length;
760         memcpy(fs->bitmap, fileinfo + SIM_FILE_INFO_SIZE,
761                         SIM_CACHE_HEADER_SIZE - SIM_FILE_INFO_SIZE);
762         fs->fd = fd;
763
764         if (error_type != OFONO_ERROR_TYPE_NO_ERROR ||
765                         structure != op->structure) {
766                 sim_fs_op_error(fs);
767                 return TRUE;
768         }
769
770         if (op->info_only == TRUE) {
771                 /*
772                  * It's an info-only request, so there is no need to request
773                  * actual contents of the EF. Just return the EF-info.
774                  */
775                 sim_fs_read_info_cb_t cb = op->cb;
776
777                 cb(1, file_status, op->length,
778                         op->record_length, op->userdata);
779
780                 sim_fs_end_current(fs);
781         } else if (structure == OFONO_SIM_FILE_STRUCTURE_TRANSPARENT) {
782                 if (op->num_bytes == 0)
783                         op->num_bytes = op->length;
784
785                 op->current = op->offset / 256;
786                 fs->op_source = g_idle_add(sim_fs_op_read_block, fs);
787         } else {
788                 op->current = 1;
789                 fs->op_source = g_idle_add(sim_fs_op_read_record, fs);
790         }
791
792         return TRUE;
793
794 error:
795         TFR(close(fd));
796         return FALSE;
797 }
798
799 static gboolean sim_fs_op_next(gpointer user_data)
800 {
801         struct sim_fs *fs = user_data;
802         const struct ofono_sim_driver *driver = fs->driver;
803         struct sim_fs_op *op;
804
805         fs->op_source = 0;
806
807         if (fs->op_q == NULL)
808                 return FALSE;
809
810         op = g_queue_peek_head(fs->op_q);
811
812         if (op->cb == NULL) {
813                 sim_fs_end_current(fs);
814                 return FALSE;
815         }
816
817         if (op->is_read == TRUE) {
818                 if (sim_fs_op_check_cached(fs))
819                         return FALSE;
820
821                 driver->read_file_info(fs->sim, op->id, sim_fs_op_info_cb, fs);
822         } else {
823                 switch (op->structure) {
824                 case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT:
825                         driver->write_file_transparent(fs->sim, op->id, 0,
826                                         op->length, op->buffer,
827                                         sim_fs_op_write_cb, fs);
828                         break;
829                 case OFONO_SIM_FILE_STRUCTURE_FIXED:
830                         driver->write_file_linear(fs->sim, op->id, op->current,
831                                         op->length, op->buffer,
832                                         sim_fs_op_write_cb, fs);
833                         break;
834                 case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
835                         driver->write_file_cyclic(fs->sim, op->id,
836                                         op->length, op->buffer,
837                                         sim_fs_op_write_cb, fs);
838                         break;
839                 default:
840                         ofono_error("Unrecognized file structure, "
841                                         "this can't happen");
842                 }
843
844                 g_free(op->buffer);
845                 op->buffer = NULL;
846         }
847
848         return FALSE;
849 }
850
851 int sim_fs_read_info(struct ofono_sim_context *context, int id,
852                         enum ofono_sim_file_structure expected_type,
853                         sim_fs_read_info_cb_t cb, void *data)
854 {
855         struct sim_fs *fs = context->fs;
856         struct sim_fs_op *op;
857
858         if (cb == NULL)
859                 return -EINVAL;
860
861         if (fs->driver == NULL)
862                 return -EINVAL;
863
864         if (fs->driver->read_file_info == NULL)
865                 return -ENOSYS;
866
867         if (fs->op_q == NULL)
868                 fs->op_q = g_queue_new();
869
870         op = g_try_new0(struct sim_fs_op, 1);
871         if (op == NULL)
872                 return -ENOMEM;
873
874         op->id = id;
875         op->structure = expected_type;
876         op->cb = cb;
877         op->userdata = data;
878         op->is_read = TRUE;
879         op->info_only = TRUE;
880         op->context = context;
881
882         g_queue_push_tail(fs->op_q, op);
883
884         if (g_queue_get_length(fs->op_q) == 1)
885                 fs->op_source = g_idle_add(sim_fs_op_next, fs);
886
887         return 0;
888 }
889
890 int sim_fs_read(struct ofono_sim_context *context, int id,
891                 enum ofono_sim_file_structure expected_type,
892                 unsigned short offset, unsigned short num_bytes,
893                 ofono_sim_file_read_cb_t cb, void *data)
894 {
895         struct sim_fs *fs = context->fs;
896         struct sim_fs_op *op;
897
898         if (cb == NULL)
899                 return -EINVAL;
900
901         if (fs->driver == NULL)
902                 return -EINVAL;
903
904         if (fs->driver->read_file_info == NULL) {
905                 cb(0, 0, 0, NULL, 0, data);
906                 return -ENOSYS;
907         }
908
909         if (fs->op_q == NULL)
910                 fs->op_q = g_queue_new();
911
912         op = g_try_new0(struct sim_fs_op, 1);
913         if (op == NULL)
914                 return -ENOMEM;
915
916         op->id = id;
917         op->structure = expected_type;
918         op->cb = cb;
919         op->userdata = data;
920         op->is_read = TRUE;
921         op->offset = offset;
922         op->num_bytes = num_bytes;
923         op->info_only = FALSE;
924         op->context = context;
925
926         g_queue_push_tail(fs->op_q, op);
927
928         if (g_queue_get_length(fs->op_q) == 1)
929                 fs->op_source = g_idle_add(sim_fs_op_next, fs);
930
931         return 0;
932 }
933
934 int sim_fs_write(struct ofono_sim_context *context, int id,
935                         ofono_sim_file_write_cb_t cb,
936                         enum ofono_sim_file_structure structure, int record,
937                         const unsigned char *data, int length, void *userdata)
938 {
939         struct sim_fs *fs = context->fs;
940         struct sim_fs_op *op;
941         gconstpointer fn = NULL;
942
943         if (cb == NULL)
944                 return -EINVAL;
945
946         if (fs->driver == NULL)
947                 return -EINVAL;
948
949         switch (structure) {
950         case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT:
951                 fn = fs->driver->write_file_transparent;
952                 break;
953         case OFONO_SIM_FILE_STRUCTURE_FIXED:
954                 fn = fs->driver->write_file_linear;
955                 break;
956         case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
957                 fn = fs->driver->write_file_cyclic;
958                 break;
959         default:
960                 ofono_error("Unrecognized file structure, this can't happen");
961         }
962
963         if (fn == NULL)
964                 return -ENOSYS;
965
966         if (fs->op_q == NULL)
967                 fs->op_q = g_queue_new();
968
969         op = g_try_new0(struct sim_fs_op, 1);
970         if (op == NULL)
971                 return -ENOMEM;
972
973         op->id = id;
974         op->cb = cb;
975         op->userdata = userdata;
976         op->is_read = FALSE;
977         op->buffer = g_memdup(data, length);
978         op->structure = structure;
979         op->length = length;
980         op->current = record;
981         op->context = context;
982
983         g_queue_push_tail(fs->op_q, op);
984
985         if (g_queue_get_length(fs->op_q) == 1)
986                 fs->op_source = g_idle_add(sim_fs_op_next, fs);
987
988         return 0;
989 }
990
991 void sim_fs_cache_image(struct sim_fs *fs, const char *image, int id)
992 {
993         const char *imsi;
994         enum ofono_sim_phase phase;
995
996         if (fs == NULL || image == NULL)
997                 return;
998
999         imsi = ofono_sim_get_imsi(fs->sim);
1000         if (imsi == NULL)
1001                 return;
1002
1003         phase = ofono_sim_get_phase(fs->sim);
1004         if (phase == OFONO_SIM_PHASE_UNKNOWN)
1005                 return;
1006
1007         write_file((const unsigned char *) image, strlen(image),
1008                         SIM_CACHE_MODE, SIM_IMAGE_CACHE_PATH, imsi,
1009                         phase, id);
1010 }
1011
1012 char *sim_fs_get_cached_image(struct sim_fs *fs, int id)
1013 {
1014         const char *imsi;
1015         enum ofono_sim_phase phase;
1016         unsigned short image_length;
1017         int fd;
1018         char *buffer;
1019         char *path;
1020         int len;
1021         struct stat st_buf;
1022
1023         if (fs == NULL)
1024                 return NULL;
1025
1026         imsi = ofono_sim_get_imsi(fs->sim);
1027         if (imsi == NULL)
1028                 return NULL;
1029
1030         phase = ofono_sim_get_phase(fs->sim);
1031         if (phase == OFONO_SIM_PHASE_UNKNOWN)
1032                 return NULL;
1033
1034         path = g_strdup_printf(SIM_IMAGE_CACHE_PATH, imsi, phase, id);
1035
1036         TFR(stat(path, &st_buf));
1037         fd = TFR(open(path, O_RDONLY));
1038         g_free(path);
1039
1040         if (fd < 0)
1041                 return NULL;
1042
1043         image_length = st_buf.st_size;
1044         buffer = g_try_new0(char, image_length + 1);
1045
1046         if (buffer == NULL) {
1047                 TFR(close(fd));
1048                 return NULL;
1049         }
1050
1051         len = TFR(read(fd, buffer, image_length));
1052         TFR(close(fd));
1053
1054         if (len != image_length) {
1055                 g_free(buffer);
1056                 return NULL;
1057         }
1058
1059         return buffer;
1060 }
1061
1062 static void remove_cachefile(const char *imsi, enum ofono_sim_phase phase,
1063                                 const struct dirent *file)
1064 {
1065         int id;
1066         char *path;
1067
1068         if (file->d_type != DT_REG)
1069                 return;
1070
1071         if (sscanf(file->d_name, "%4x", &id) != 1)
1072                 return;
1073
1074         path = g_strdup_printf(SIM_CACHE_PATH, imsi, phase, id);
1075         remove(path);
1076         g_free(path);
1077 }
1078
1079 static void remove_imagefile(const char *imsi, enum ofono_sim_phase phase,
1080                                 const struct dirent *file)
1081 {
1082         int id;
1083         char *path;
1084
1085         if (file->d_type != DT_REG)
1086                 return;
1087
1088         if (sscanf(file->d_name, "%d", &id) != 1)
1089                 return;
1090
1091         path = g_strdup_printf(SIM_IMAGE_CACHE_PATH, imsi, phase, id);
1092         remove(path);
1093         g_free(path);
1094 }
1095
1096 void sim_fs_check_version(struct sim_fs *fs)
1097 {
1098         const char *imsi = ofono_sim_get_imsi(fs->sim);
1099         enum ofono_sim_phase phase = ofono_sim_get_phase(fs->sim);
1100         unsigned char version;
1101
1102         if (imsi == NULL || phase == OFONO_SIM_PHASE_UNKNOWN)
1103                 return;
1104
1105         if (read_file(&version, 1, SIM_CACHE_VERSION, imsi, phase) == 1)
1106                 if (version == SIM_FS_VERSION)
1107                         return;
1108
1109         sim_fs_cache_flush(fs);
1110
1111         version = SIM_FS_VERSION;
1112         write_file(&version, 1, SIM_CACHE_MODE, SIM_CACHE_VERSION, imsi, phase);
1113 }
1114
1115 void sim_fs_cache_flush(struct sim_fs *fs)
1116 {
1117         const char *imsi = ofono_sim_get_imsi(fs->sim);
1118         enum ofono_sim_phase phase = ofono_sim_get_phase(fs->sim);
1119         char *path = g_strdup_printf(SIM_CACHE_BASEPATH, imsi, phase);
1120         struct dirent **entries;
1121         int len = scandir(path, &entries, NULL, alphasort);
1122
1123         g_free(path);
1124
1125         if (len > 0) {
1126                 /* Remove all file ids */
1127                 while (len--) {
1128                         remove_cachefile(imsi, phase, entries[len]);
1129                         g_free(entries[len]);
1130                 }
1131
1132                 g_free(entries);
1133         }
1134
1135         sim_fs_image_cache_flush(fs);
1136 }
1137
1138 void sim_fs_cache_flush_file(struct sim_fs *fs, int id)
1139 {
1140         const char *imsi = ofono_sim_get_imsi(fs->sim);
1141         enum ofono_sim_phase phase = ofono_sim_get_phase(fs->sim);
1142         char *path = g_strdup_printf(SIM_CACHE_PATH, imsi, phase, id);
1143
1144         remove(path);
1145         g_free(path);
1146 }
1147
1148 void sim_fs_image_cache_flush(struct sim_fs *fs)
1149 {
1150         const char *imsi = ofono_sim_get_imsi(fs->sim);
1151         enum ofono_sim_phase phase = ofono_sim_get_phase(fs->sim);
1152         char *path = g_strdup_printf(SIM_IMAGE_CACHE_BASEPATH, imsi, phase);
1153         struct dirent **entries;
1154         int len = scandir(path, &entries, NULL, alphasort);
1155
1156         g_free(path);
1157
1158         if (len <= 0)
1159                 return;
1160
1161         /* Remove everything */
1162         while (len--) {
1163                 remove_imagefile(imsi, phase, entries[len]);
1164                 g_free(entries[len]);
1165         }
1166
1167         g_free(entries);
1168 }
1169
1170 void sim_fs_image_cache_flush_file(struct sim_fs *fs, int id)
1171 {
1172         const char *imsi = ofono_sim_get_imsi(fs->sim);
1173         enum ofono_sim_phase phase = ofono_sim_get_phase(fs->sim);
1174         char *path = g_strdup_printf(SIM_IMAGE_CACHE_PATH, imsi, phase, id);
1175
1176         remove(path);
1177         g_free(path);
1178 }