nckernel  0.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fat.c
Go to the documentation of this file.
1 #include <sys/types.h>
2 #include <stdio.h>
3 #include <stddef.h>
4 #include <stdlib.h>
5 #include <fcntl.h>
6 #include <stdint.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <stdarg.h>
10 #include <errno.h>
11 #include <ctype.h>
12 #include <assert.h>
13 #include <pthread.h>
14 
15 #include <object.h>
16 #include <list.h>
17 #include <vfs.h>
18 #include <vfs0.h>
19 #include <fat0.h>
20 #include <fat.h>
21 
22 #include <fat_cache.h>
23 
24 #include <debug.h>
25 
26 #define NEXT_CLUSTER(fat, c) \
27 do { \
28  (c) = get_cluster_entry_value(&((fat)->bpb), (fat)->table, (c)); \
29 } while (0)
30 
34 struct fatfs {
35  char *node;
36  struct bpb bpb;
37  struct ninfo *root;
39 
40  struct fat_cache *cache;
41 
42  int fatsz;
43  char *table;
44 };
45 
50 struct ninfo_priv {
53 };
54 
55 #define IS_DOT_DOTDOT(lfname) \
56  lfname[0] == '.' && (!lfname[1] || (lfname[1] == '.' && !lfname[2]))
57 
58 static struct DSKSZTOSECPERCLUS s_DskTableFAT16[] __UNUSED = {
59  { 8400, 0 },
60  { 32680, 2 },
61  { 262144, 4 },
62  { 524288, 8 },
63  { 1048576, 16 },
64  /* The entries after this point aren't used unless FAT16 is forced */
65  { 2097152, 32 },
66  { 4194304, 64 },
67  { 0xFFFFFFFF, 0 },
68 };
69 
70 /*
71 static struct DSKSZTOSECPERCLUS s_DskTableFAT32[] __UNUSED = {
72  { 66600, 0 },
73  { 532480, 1 },
74  { 16777216, 8 },
75  { 33554432, 16 },
76  { 67108864, 32 },
77  { 0xFFFFFFFF, 64 },
78 };
79 */
80 
81 static inline unsigned char checksum(unsigned char *name)
82 {
83  short namelen;
84  unsigned char sum;
85 
86  sum = 0;
87  for (namelen = 11; namelen != 0; namelen--) {
88  sum = ((sum & 0x01)? 0x80 : 0) + (sum >> 1);
89  sum += (unsigned char)(*name++);
90  }
91 
92  return sum;
93 }
94 
95 static inline void from_fat12(unsigned char *fat, unsigned char *out)
96 {
97  int idx;
98  for (idx = 0; idx < 8 && fat[idx] != ' '; idx++, out++)
99  *out = tolower(fat[idx]);
100  *out++ = '.';
101 
102  idx = 8;
103  while (idx < 11 && fat[idx] != ' ' && fat[idx] != '\0') {
104  *out = tolower(fat[idx]);
105  idx++;
106  out++;
107  }
108 
109  if (idx == 8) {
110  out--;
111  }
112  *out = '\0';
113 }
114 
115 static inline int update_unicode(char *wstr)
116 {
117  unsigned short *wchar = (unsigned short *)wstr;
118 
119  while (*wchar) {
120  *wstr = (char)*wchar;
121  wchar++;
122  wstr++;
123  }
124  *wstr = '\0';
125  return 0;
126 }
127 
128 static int fat_file_open(struct ninfo *ninfo, struct nctx *ctx)
129 {
130  struct sinfo *si;
131  struct fatfs *fat;
132 
133  si = ninfo->si;
134  if (!si) {
135  return -EINVAL;
136  }
137 
138  fat = si->priv;
139  if (!fat) {
140  return -EINVAL;
141  }
142 
143  ctx->offset = 0;
144  ctx->priv = create_fat_cache(fat->node, BUFSIZ);
145  return ctx->priv ? 0 : -EIO;
146 }
147 
148 static int fat_file_close(struct ninfo *ninfo, struct nctx *ctx)
149 {
150  struct sinfo *si;
151  struct fatfs *fat;
152 
153  si = ninfo->si;
154  if (!si) {
155  return -EINVAL;
156  }
157 
158  fat = si->priv;
159  if (!fat) {
160  return -EINVAL;
161  }
162 
163  destroy_fat_cache(ctx->priv);
164  ctx->priv = NULL;
165  return 0;
166 }
167 
168 static int fat_file_read(struct ninfo *ninfo,
169  struct nctx *ctx, void *buf, size_t size)
170 {
171  struct sinfo *si;
172  struct fatfs *fat;
173  struct ninfo_priv *priv;
174  int block;
175  off_t off;
176  int sector;
177  int cluster;
178  int rsize;
179  char *ptr;
180  size_t filesize;
181  int ret;
182 
183  si = ninfo->si;
184  if (!si) {
185  return -EINVAL;
186  }
187 
188  fat = si->priv;
189  if (!fat) {
190  return -EINVAL;
191  }
192 
193  priv = ninfo->priv;
194  if (!priv) {
195  return -EINVAL;
196  }
197 
198  filesize = ninfo->size;
199  if (filesize <= ctx->offset) {
200  return EOF;
201  }
202 
203  block = ctx->offset / fat->bpb.sector_size;
204 
209  cluster = GET_FIRST_BLOCK(&priv->dentry);
210 
211  while (block-- > 0) {
212  filesize -= fat->bpb.sector_size;
213 
214  NEXT_CLUSTER(fat, cluster);
215  if (IS_EOF(&fat->bpb, cluster) || (filesize <= 0)) {
216  return EOF;
217  }
218  }
219 
220  ptr = buf;
221  rsize = 0;
222  while (filesize > 0 && size > 0 && !IS_EOF(&fat->bpb, cluster)) {
223  sector = FIRST_SECTOR_OF_CLUSTER(&fat->bpb, cluster);
224 
225  block = 0;
226  off = sector * fat->bpb.sector_size;
227  off += (ctx->offset % fat->bpb.sector_size);
228  while (block < fat->bpb.sector_per_cluster && size > 0 && filesize > 0) {
229  ret = update_fat_cache(ctx->priv, off);
230  if (ret < 0) {
231  return ret;
232  }
233 
234  ret = off % fat_cache_size(ctx->priv);
235 
236  rsize = fat_cache_size(ctx->priv) - ret;
237  rsize = rsize > filesize ? filesize : rsize;
238  rsize = rsize > size ? size : rsize;
239 
240  memcpy(ptr, fat_cache(ctx->priv) + ret, rsize);
241  ctx->offset += rsize;
242 
243  block++;
244  ptr += rsize;
245  size -= rsize;
246  filesize -= rsize;
247  off += rsize;
248  }
249 
250  NEXT_CLUSTER(fat, cluster);
251  }
252 
253  return (uint32_t)ptr - (uint32_t)buf;
254 }
255 
256 static int fat_file_write(struct ninfo *_this,
257  struct nctx *ctx, const void *buf, size_t size)
258 {
259  return -ENOSYS;
260 }
261 
262 static off_t fat_file_lseek(struct ninfo *ninfo,
263  struct nctx *ctx, off_t off, int whence)
264 {
265  switch (whence) {
266  case SEEK_SET:
267  ctx->offset = off;
268  break;
269  case SEEK_CUR:
270  ctx->offset += off;
271  break;
272  case SEEK_END:
273  ctx->offset = ninfo->size + off;
274  break;
275  default:
276  return (off_t)-1;
277  }
278 
279  return ctx->offset;
280 }
281 
282 static inline int load_fat(struct fatfs *fat)
283 {
284  int ret;
285  int off;
286  int rsize;
287  int size;
288  char *ptr;
289 
290  fat->fatsz = FAT_SIZE(&fat->bpb) * fat->bpb.sector_size;
291  fat->table = malloc(fat->fatsz);
292  if (!fat->table) {
293  return -ENOMEM;
294  }
295 
296  ptr = fat->table;
297  off = THIS_FAT_OFFSET(&fat->bpb, 0);
298  size = fat->fatsz;
299 
300  while (size > 0) {
301  ret = update_fat_cache(fat->cache, off);
302  if (ret < 0) {
303  free(fat->table);
304  return ret;
305  }
306 
307  ret = off % fat_cache_size(fat->cache);
308  rsize = fat_cache_size(fat->cache) - ret;
309  rsize = rsize > size ? size : rsize;
310 
311  memcpy(ptr, fat_cache(fat->cache) + ret, rsize);
312 
313  ptr += rsize;
314  off += rsize;
315  size -= rsize;
316  }
317 
318  return 0;
319 }
320 
321 static inline void read_slots(struct ninfo *root, int sector,
322  int *cont, unsigned char *chksum, unsigned char *lfname)
323 {
324  struct fat_dentry *dentry;
325  off_t offset;
326  struct fatfs *fat;
327  int nr_of_slots;
328 
329  fat = root->si->priv;
330  nr_of_slots = fat->bpb.sector_size / sizeof(*dentry);
331  offset = sector * fat->bpb.sector_size;
332 
333  update_fat_cache(fat->cache, offset);
334  offset %= fat_cache_size(fat->cache);
335 
336  dentry = (struct fat_dentry *)(fat_cache(fat->cache) + offset);
337  while (nr_of_slots-- > 0) {
338  if (IS_FREE_DENTRY(dentry)) {
339  if (*cont != 0) {
340  printf("Skip: cont isn't ZERO\n");
341  *cont = 0;
342  }
343  dentry++;
344  continue;
345  }
346 
347  if (dentry->attr == ATTR_EXT) {
348  struct fat_long_dirent *lentry;
349  unsigned char *tmp;
350 
351  lentry = (struct fat_long_dirent *)dentry;
352 
353  if (!*cont) {
354  if ((lentry->ord & 0x40) != 0x40) {
355  printf("Invalid slot\n");
356  *chksum = 0;
357  dentry++;
358  continue;
359  }
360  *cont = lentry->ord & 0x0F;
361  *chksum = lentry->checksum;
362  } else {
363  if ((lentry->ord & 0x40) != 0x0) {
364  printf("Invalid slot\n");
365  dentry++;
366  *chksum = 0;
367  continue;
368  }
369 
370  if (*cont != (lentry->ord & 0x0F)) {
371  printf("Invalid seq\n");
372  dentry++;
373  *chksum = 0;
374  continue;
375  }
376 
377  if (*chksum != lentry->checksum) {
378  printf("Invalid checksum\n");
379  dentry++;
380  *chksum = 0;
381  continue;
382  }
383  }
384 
385  (*cont)--;
386 
387  tmp = lfname + (*cont * 26);
388  memcpy(tmp, lentry->name1, 10);
389  tmp += 10;
390  memcpy(tmp, lentry->name2, 12);
391  tmp += 12;
392  memcpy(tmp, lentry->name3, 4);
393  tmp += 4;
394  } else {
395  struct ninfo *ninfo;
396 
397  if (*cont != 0) {
398  printf("lfn is invalid [%d]\n", *cont);
399  dentry++;
400  *cont = 0;
401  *chksum = 0;
402  continue;
403  }
404 
405  if (!*chksum || checksum(dentry->name) != *chksum) {
406  from_fat12(dentry->name, lfname);
407  } else {
408  update_unicode((char *)lfname);
409  }
410 
411  if (IS_DOT_DOTDOT(lfname)) {
412  dentry++;
413  continue;
414  }
415 
416  ninfo = vfs_new_ninfo(NULL, root, (char *)lfname, dentry);
417  if (!ninfo) {
418  printf("Create failed [%s]\n", lfname);
419  dentry++;
420  continue;
421  }
422  }
423  dentry++;
424  }
425 }
426 
427 static inline void load_rootdir(struct ninfo *parent)
428 {
429  int sector;
430  int nr_of_sectors;
431  struct fatfs *fat;
432  struct ninfo_priv *priv;
433  unsigned char chksum;
434  unsigned char lfname[PATH_MAX];
435  int cont;
436 
437  priv = parent->priv;
438  if (priv) {
439  priv->child_updated = 1;
440  }
441 
442  fat = parent->si->priv;
443  assert(fat && "fat is not valid");
444 
445  sector = FIRST_ROOTDIR_SECTOR(&fat->bpb);
446  nr_of_sectors = ROOT_DIR_SECTORS(&fat->bpb);
447  cont = 0;
448 
449  while (nr_of_sectors-- > 0) {
450  read_slots(parent, sector, &cont, &chksum, lfname);
451  sector++;
452  } /* while in parent dir sectors */
453 }
454 
455 static struct ninfo *get_ninfo(struct sinfo *this, unsigned long id)
456 {
457  if (id == ROOT_NINFO) {
458  struct fatfs *fat;
459  fat = this->priv;
460  if (!fat) {
461  return NULL;
462  }
463 
464  return fat->root;
465  }
466 
467  return NULL;
468 }
469 
470 static void refresh_children(struct sinfo *sinfo, struct ninfo *root)
471 {
472  int cluster;
473  int sector;
474  unsigned char chksum;
475  unsigned char lfname[PATH_MAX];
476  struct ninfo_priv *priv;
477  struct fatfs *fat;
478  int cont;
479  int block;
480 
481  if (root->type != NINFO_TYPE_FOLDER) {
482  return;
483  }
484 
485  priv = root->priv;
486  if (!priv || priv->child_updated) {
487  return;
488  }
489 
490  priv->child_updated = 1;
491  fat = root->si->priv;
492 
493  cluster = GET_FIRST_BLOCK(&priv->dentry);
494  cont = 0;
495 
496  while (!IS_EOF(&(fat->bpb), cluster)) {
497  sector = FIRST_SECTOR_OF_CLUSTER(&(fat->bpb), cluster);
498  for (block = 0; block < fat->bpb.sector_per_cluster; block++) {
499  read_slots(root, sector, &cont, &chksum, lfname);
500  sector++;
501  }
502 
503  NEXT_CLUSTER(fat, cluster);
504  }
505 }
506 
507 static int fill_ninfo(struct sinfo *this, struct ninfo *parent,
508  struct ninfo *ninfo, void *info)
509 {
510  struct ninfo_priv *priv;
511  struct fat_dentry *dentry = info;
512 
513  if (!ninfo) {
514  return -EINVAL;
515  }
516 
517  if (dentry->attr & ATTR_DIR) {
518  ninfo->type = NINFO_TYPE_FOLDER;
519  } else {
520  ninfo->type = NINFO_TYPE_FILE;
521  }
522 
523  ninfo->nops.open = fat_file_open;
524  ninfo->nops.read = fat_file_read;
525  ninfo->nops.write = fat_file_write;
526  ninfo->nops.close = fat_file_close;
527  ninfo->nops.lseek = fat_file_lseek;
528  ninfo->id = GET_FIRST_BLOCK(dentry);
529  ninfo->size = dentry->file_size;
530 
531  priv = malloc(sizeof(*priv));
532  if (!priv) {
533  return -ENOMEM;
534  }
535 
536  priv->child_updated = 0;
537  memcpy(&priv->dentry, dentry, sizeof(*dentry));
538  ninfo->priv = priv;
539 
540  return 0;
541 }
542 
543 static int del_ninfo(struct sinfo *this, struct ninfo *node)
544 {
545  /* TODO: Update FAT table */
546  return 0;
547 }
548 
549 inline static void dump_bpb(struct bpb *boot)
550 {
551  printf("Jump Instruction : [0x%x 0x%x]\n", boot->jmp[0], boot->jmp[1]);
552  printf("NOP Instructrion : [0x%x]\n", boot->nop);
553 // printf("OEM : [%.*s]\n", sizeof(boot->oem), boot->oem);
554  printf("Sector size : [%d]\n", boot->sector_size);
555  printf("Sector per cluster : [%d]\n", boot->sector_per_cluster);
556  printf("Reserved sector count : [%d]\n", boot->reserved_sector);
557  printf("Number of FATs : [%d]\n", boot->nr_fat);
558 
559  printf("Media type : 0x%x (? F0 : Removal)\n", boot->media_type);
560  printf("Size of a FAT : [%d]\n", boot->size_of_fat16);
561  printf("Sectors per a track : [%d]\n", boot->sector_per_track);
562  printf("Number of heads : [%d]\n", boot->nr_head);
563  printf("Hidden sectors : [%d]\n", boot->hidden_sector);
564  printf("Total sectors : [%d]\n", boot->total_sector16);
565  printf("Boot drive : [%d]\n", boot->type.fat16.boot_drive);
566  printf("Boot signature : [%x]\n", boot->type.fat16.boot_signature);
567  printf("Volume ID : [%x]\n", boot->type.fat16.volume_id);
568 // printf("Volume label : [%.*s]\n", sizeof(boot->type.fat16.volume_label), boot->type.fat16.volume_label);
569 // printf("FS type : [%.*s]\n", sizeof(boot->type.fat16.fs_type), boot->type.fat16.fs_type);
570 }
571 
572 struct ninfo *fat_load(struct ninfo *parent, const char *node)
573 {
574  struct sinfo *si;
575  struct fatfs *fat;
576  int ret;
577  struct ninfo *root;
578 
579  si = malloc(sizeof(*si));
580  if (!si) {
581  dbg_printf("malloc: si(%d)\n", sizeof(*si));
582  return NULL;
583  }
584 
585  INIT_LIST_HEAD(&si->head);
586  si->refcnt = 0;
587 
588  si->get_ninfo = get_ninfo;
589  si->fill_ninfo = fill_ninfo;
590  si->del_ninfo = del_ninfo;
591  si->refresh_children = refresh_children;
592 
593  root = vfs_new_ninfo(si, parent, "fat", NULL);
594  if (!root) {
595  free(si);
596  dbg_printf("Failed to create a fat node\n");
597  return NULL;
598  }
599 
600  root->type = NINFO_TYPE_FOLDER;
601 
602  fat = malloc(sizeof(*fat));
603  if (!fat) {
604  free(si);
605  vfs_del_ninfo(root);
606  dbg_printf("malloc: fat(%d)\n", sizeof(*fat));
607  return NULL;
608  }
609 
610  fat->node = strdup(node);
611  if (!fat->node) {
612  free(fat);
613  free(si);
614  vfs_del_ninfo(root);
615  dbg_printf("stdup: %s\n", node);
616  return NULL;
617  }
618 
619  fat->cache = create_fat_cache(fat->node, BUFSIZ);
620  if (!fat->cache) {
621  free(fat->node);
622  free(fat);
623  free(si);
624  vfs_del_ninfo(root);
625  dbg_printf("Failed to create cache\n");
626  return NULL;
627  }
628 
629  ret = update_fat_cache(fat->cache, 0);
630  if (ret < 0) {
631  destroy_fat_cache(fat->cache);
632  free(fat->node);
633  free(fat);
634  free(si);
635  vfs_del_ninfo(root);
636  dbg_printf("Failed to access FDD\n");
637  return NULL;
638  }
639 
640  memcpy(&fat->bpb, fat_cache(fat->cache), sizeof(fat->bpb));
641 
642  dump_bpb(&fat->bpb);
643 
644  fat->root = root;
645  si->priv = fat;
646 
647  ret = load_fat(fat);
648  if (ret < 0) {
649  destroy_fat_cache(fat->cache);
650  free(fat->node);
651  free(fat);
652  free(si);
653  vfs_del_ninfo(root);
654  dbg_printf("Failed to load FAT\n");
655  return NULL;
656  }
657 
658  load_rootdir(fat->root);
659  return root;
660 }
661 
662 /* End of a file */