source: rtems/cpukit/libfs/src/dosfs/msdos_format.c @ b34665f8

4.104.114.84.95
Last change on this file since b34665f8 was b34665f8, checked in by Ralf Corsepius <ralf.corsepius@…>, on Nov 20, 2004 at 3:02:54 AM

2004-11-20 Ralf Corsepius <ralf.corsepiu@…>

PR 720/filesystem:

  • libfs/src/dosfs/msdos_format.c: New (From Thomas Doerfler <Thomas.Doerfler@…>).
  • libfs/Makefile.am: Reflect changes above:
  • Property mode set to 100644
File size: 33.5 KB
Line 
1/*===============================================================*\
2| Project: RTEMS msdos format functionality                       |
3+-----------------------------------------------------------------+
4| File: msdos_format.c                                            |
5+-----------------------------------------------------------------+
6|                    Copyright (c) 2004 IMD                       |
7|      Ingenieurbuero fuer Microcomputertechnik Th. Doerfler      |
8|               <Thomas.Doerfler@imd-systems.de>                  |
9|                       all rights reserved                       |
10+-----------------------------------------------------------------+
11| this file contains msdos_format function. This function         |
12| formats a disk partition conforming to MS-DOS conventions       |
13|                                                                 |
14|  The license and distribution terms for this file may be        |
15|  found in the file LICENSE in this distribution or at           |
16|  http://www.rtems.com/license/LICENSE.                          |
17|                                                                 |
18+-----------------------------------------------------------------+
19|   date                      history                        ID   |
20| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
21| 29.10.04  creation                                         doe  |
22\*===============================================================*/
23
24#if HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <fcntl.h>
31#include <unistd.h>
32#include <errno.h>
33#include <stdlib.h>
34#include <ctype.h>
35#include <assert.h>
36
37#include <rtems/libio_.h>
38
39#include "fat.h"
40#include "fat_fat_operations.h"
41#include "msdos.h"
42#include "dosfs.h"
43
44typedef struct {
45  unsigned32 bytes_per_sector;
46  unsigned32 totl_sector_cnt;
47  unsigned32 rsvd_sector_cnt;
48
49  unsigned32 sectors_per_cluster;
50  unsigned32 sectors_per_fat;
51
52  unsigned32 fat_start_sec;
53  unsigned32 files_per_root_dir;
54  unsigned32 root_dir_sectors;
55  unsigned32 root_dir_start_sec;
56  unsigned32 root_dir_fmt_sec_cnt;
57  unsigned32 mbr_copy_sec; /* location of copy of mbr or 0 */
58  unsigned32 fsinfo_sec;   /* location of fsinfo sector or 0 */
59  unsigned8  fat_num;
60  unsigned8  media_code;
61  unsigned8  fattype;
62  char       OEMName[FAT_BR_OEMNAME_SIZE+1];
63  char       VolLabel[FAT_BR_VOLLAB_SIZE+1];
64  boolean    VolLabel_present;
65  unsigned32 vol_id;
66}  msdos_format_param_t;
67
68/*=========================================================================*\
69| Function:                                                                 |
70\*-------------------------------------------------------------------------*/
71static int msdos_format_write_sec
72(
73/*-------------------------------------------------------------------------*\
74| Purpose:                                                                  |
75|     function to write to a sector                                         |
76+---------------------------------------------------------------------------+
77| Input Parameters:                                                         |
78\*-------------------------------------------------------------------------*/
79 int         fd,                       /* file descriptor index            */
80 unsigned32  start_sector,             /* sector number to write to        */
81 unsigned32  sector_size,              /* size of sector                   */
82 const char *buffer                    /* buffer with write data           */
83 )
84/*-------------------------------------------------------------------------*\
85| Return Value:                                                             |
86|    0, if success, -1 and errno if failed                                  |
87\*=========================================================================*/
88{
89  int ret_val = 0;
90
91  if (0 > lseek(fd,((off_t)start_sector)*sector_size,SEEK_SET)) {
92    ret_val = -1;
93  }
94  if (ret_val == 0) {
95    if (0 > write(fd,buffer,sector_size)) {
96      ret_val = -1;
97    }
98  }
99
100  return ret_val;
101}
102
103/*=========================================================================*\
104| Function:                                                                 |
105\*-------------------------------------------------------------------------*/
106static int msdos_format_fill_sectors
107(
108/*-------------------------------------------------------------------------*\
109| Purpose:                                                                  |
110|     function to fill sectors with byte                                    |
111+---------------------------------------------------------------------------+
112| Input Parameters:                                                         |
113\*-------------------------------------------------------------------------*/
114 int         fd,                       /* file descriptor index            */
115 unsigned32  start_sector,             /* sector number to fill to         */
116 unsigned32  sector_cnt,               /* number of sectors to fill to     */
117 unsigned32  sector_size,              /* size of sector                   */
118 const char  fill_byte                 /* byte to fill into sectors        */
119 )
120/*-------------------------------------------------------------------------*\
121| Return Value:                                                             |
122|    0, if success, -1 and errno if failed                                  |
123\*=========================================================================*/
124{
125  int ret_val = 0;
126  char *fill_buffer = NULL;
127
128  /*
129   * allocate and fill buffer
130   */
131  if (ret_val == 0) {
132    fill_buffer = malloc(sector_size);
133    if (fill_buffer == NULL) {
134      errno = ENOMEM;
135      ret_val = -1;
136    }
137    else {
138      memset(fill_buffer,fill_byte,sector_size);
139    }
140  }
141  /*
142   * write to consecutive sectors
143   */
144  while ((ret_val == 0) && 
145         (sector_cnt > 0)) {
146    ret_val = msdos_format_write_sec(fd,start_sector,sector_size,fill_buffer);
147    start_sector++;
148    sector_cnt--;
149  }
150  /*
151   * cleanup
152   */
153  if (fill_buffer != NULL) {
154    free(fill_buffer);
155    fill_buffer = NULL;
156  }
157  return ret_val;
158}
159
160
161/*=========================================================================*\
162| Function:                                                                 |
163\*-------------------------------------------------------------------------*/
164static int msdos_format_gen_volid
165(
166/*-------------------------------------------------------------------------*\
167| Purpose:                                                                  |
168|     function to generate a pseudo-random volume id                        |
169+---------------------------------------------------------------------------+
170| Input Parameters:                                                         |
171\*-------------------------------------------------------------------------*/
172 unsigned32 *volid_ptr                 /* volume ID return pointer         */
173 )
174/*-------------------------------------------------------------------------*\
175| Return Value:                                                             |
176|    0, if success, -1 and errno if failed                                  |
177\*=========================================================================*/
178{
179  int ret_val = 0;
180  int rc;
181  rtems_clock_time_value time_value;
182
183  rc = rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE,&time_value);
184  if (rc == RTEMS_SUCCESSFUL) {
185    *volid_ptr = time_value.seconds + time_value.microseconds;
186  }
187  else {
188    *volid_ptr = rand();
189  }
190
191  return ret_val;
192}
193
194
195/*=========================================================================*\
196| Function:                                                                 |
197\*-------------------------------------------------------------------------*/
198static int msdos_format_eval_sectors_per_cluster
199(
200/*-------------------------------------------------------------------------*\
201| Purpose:                                                                  |
202|     function to check/adjust sectors_per_cluster to legal values          |
203+---------------------------------------------------------------------------+
204| Input Parameters:                                                         |
205\*-------------------------------------------------------------------------*/
206 int         fattype,                  /* type code of FAT (FAT_FAT12 ...) */
207 unsigned32  bytes_per_sector,         /* byte count per sector (512)      */
208 unsigned32  fatdata_sec_cnt,          /* sectors available for FAT and data */
209 unsigned8   fat_num,                  /* number of fat copies             */
210 unsigned32  sectors_per_cluster,      /* sectors per cluster (requested)  */
211 unsigned32 *sectors_per_cluster_adj,  /* ret: sec per cluster (granted)   */
212 unsigned32 *sectors_per_fat_ptr       /* ret: sectors needed for one FAT  */
213 )
214/*-------------------------------------------------------------------------*\
215| Return Value:                                                             |
216|    0, if success, -1 and errno if failed                                  |
217\*=========================================================================*/
218{
219
220  boolean finished = FALSE;
221  int ret_val = 0;
222  unsigned32 fatdata_cluster_cnt;
223  unsigned32 fat_capacity;
224  unsigned32 sectors_per_fat;
225  unsigned32 data_cluster_cnt;
226  /*
227   * ensure, that maximum cluster size (32KByte) is not exceeded
228   */
229  while (MS_BYTES_PER_CLUSTER_LIMIT / bytes_per_sector < sectors_per_cluster) {
230    sectors_per_cluster /= 2;
231  }
232 
233  do {
234    /*
235     * compute number of data clusters for current data:
236     * - compute cluster count for data AND fat
237     * - compute storage size for FAT
238     * - subtract from total cluster count
239     */
240    fatdata_cluster_cnt = fatdata_sec_cnt/sectors_per_cluster;
241    if (fattype == FAT_FAT12) {
242      fat_capacity = fatdata_cluster_cnt * 3 / 2;
243    }
244    else if (fattype == FAT_FAT16) {
245      fat_capacity = fatdata_cluster_cnt * 2;
246    }
247    else { /* FAT32 */
248      fat_capacity = fatdata_cluster_cnt * 4;
249    }
250
251    sectors_per_fat = ((fat_capacity
252                        + (bytes_per_sector - 1))
253                       / bytes_per_sector);
254
255    data_cluster_cnt = (fatdata_cluster_cnt -
256                        (((sectors_per_fat * fat_num)
257                          + (sectors_per_cluster - 1))
258                         / sectors_per_cluster));
259    /*
260     * data cluster count too big? then make sectors bigger
261     */
262    if (((fattype == FAT_FAT12) && (data_cluster_cnt > FAT_FAT12_MAX_CLN)) ||
263        ((fattype == FAT_FAT16) && (data_cluster_cnt > FAT_FAT16_MAX_CLN))) {
264      sectors_per_cluster *= 2;
265    }
266    else {
267      finished = TRUE;
268    }
269    /*
270     * when maximum cluster size is exceeded, we have invalid data, abort...
271     */
272    if ((sectors_per_cluster * bytes_per_sector) 
273        > MS_BYTES_PER_CLUSTER_LIMIT) {
274      ret_val = EINVAL;
275      finished = TRUE;
276    }
277  } while (!finished);
278
279  if (ret_val != 0) {
280    set_errno_and_return_minus_one(ret_val);
281  }
282  else {
283    *sectors_per_cluster_adj = sectors_per_cluster;
284    *sectors_per_fat_ptr     = sectors_per_fat;
285    return 0;
286  }
287}
288
289
290/*=========================================================================*\
291| Function:                                                                 |
292\*-------------------------------------------------------------------------*/
293static int msdos_format_determine_fmt_params
294(
295/*-------------------------------------------------------------------------*\
296| Purpose:                                                                  |
297|     determine parameters for formatting                                   |
298+---------------------------------------------------------------------------+
299| Input Parameters:                                                         |
300\*-------------------------------------------------------------------------*/
301 const disk_device            *dd,       /* disk device structure          */
302 const msdos_format_request_param_t *rqdata,   /* requested fmt parameters */
303 msdos_format_param_t         *fmt_params/* computed fmt parameters        */
304 )
305/*-------------------------------------------------------------------------*\
306| Return Value:                                                             |
307|    0, if success, -1 and errno if failed                                  |
308\*=========================================================================*/
309{
310  int ret_val = 0;
311  unsigned32 fatdata_sect_cnt;
312  unsigned32 onebit;
313  unsigned32 sectors_per_cluster_adj;
314
315  memset(fmt_params,0,sizeof(*fmt_params));
316  /*
317   * this one is fixed in this implementation.
318   * At least one thing we don't have to magically guess...
319   */
320  if (ret_val == 0) {
321    fmt_params->bytes_per_sector = dd->block_size;
322    fmt_params->totl_sector_cnt  = dd->size;
323  }
324  /*
325   * determine number of FATs
326   */
327  if (ret_val == 0) {
328    if ((rqdata == NULL) || 
329        (rqdata->fat_num == 0)) {
330      fmt_params->fat_num = 2;
331    }
332    else if (rqdata->fat_num <= 6) {
333      fmt_params->fat_num = rqdata->fat_num;
334    }
335    else {
336      ret_val = EINVAL;
337    }
338  }
339  /*
340   * Now we get sort of a loop when determining things:
341   * The FAT type (FAT12/16/32) is determined ONLY from the
342   * data cluster count:
343   * Disks with data cluster count <  4085 are FAT12.
344   * Disks with data cluster count < 65525 are FAT16.
345   * The rest is FAT32 (no FAT128 available yet :-)
346   *
347   * The number of data clusters is the
348   * total capacity
349   * minus reserved sectors
350   * minus root directory ares
351   * minus storage needed for the FAT (and its copy/copies).
352   *
353   * The last item once again depends on the FAT type and the cluster count.
354   *
355   * So here is what we do in this formatter:
356   * - If a FAT type is requested from the caller, we try to modify
357   * the cluster size, until the data cluster count is in range
358   * - If no FAT type is given, we estimate a useful FAT type from
359   * the disk capacity and then adapt the cluster size
360   */ 
361
362  /*
363   * determine characteristic values:
364   * - number of sectors
365   * - number of reserved sectors
366   * - number of used sectors
367   * - sectors per cluster
368   */
369  /*
370   * determine FAT type and sectors per cluster
371   * depends on
372   */
373  if (ret_val == 0) {
374    fmt_params->sectors_per_cluster = 1;
375    if ((rqdata != NULL) && 
376        (rqdata->fattype == MSDOS_FMT_FAT12)) {
377      fmt_params->fattype = FAT_FAT12;
378    }
379    else if ((rqdata != NULL) && 
380             (rqdata->fattype == MSDOS_FMT_FAT16)) {
381      fmt_params->fattype = FAT_FAT16;
382    }
383    else if ((rqdata != NULL) && 
384             (rqdata->fattype == MSDOS_FMT_FAT32)) {
385      fmt_params->fattype = FAT_FAT32;
386    }
387    else if ((rqdata != NULL) &&
388             (rqdata->fattype != MSDOS_FMT_FATANY)) {
389      ret_val = -1;
390      errno = EINVAL;
391    }
392    else {
393      /*
394       * limiting values for disk size, fat type, sectors per cluster
395       * NOTE: maximum sect_per_clust is arbitrarily choosen with values that
396       * are a compromise concerning capacity and efficency
397       */
398      if (fmt_params->totl_sector_cnt
399          < ((unsigned32)FAT_FAT12_MAX_CLN)*8) {
400        fmt_params->fattype = FAT_FAT12;
401        /* start trying with small clusters */
402        fmt_params->sectors_per_cluster = 2; 
403      }
404      else if (fmt_params->totl_sector_cnt
405               < ((unsigned32)FAT_FAT16_MAX_CLN)*32) {
406        fmt_params->fattype = FAT_FAT16;
407        /* start trying with small clusters */
408        fmt_params->sectors_per_cluster = 2; 
409      }
410      else {
411        fmt_params->fattype = FAT_FAT32;
412        /* start trying with small clusters... */
413        fmt_params->sectors_per_cluster = 1; 
414      }
415    }
416    /*
417     * try to use user requested cluster size
418     */
419    if ((rqdata != NULL) && 
420        (rqdata->sectors_per_cluster > 0)) {
421      fmt_params->sectors_per_cluster = 
422        rqdata->sectors_per_cluster;   
423    }
424    /*
425     * check sectors per cluster.
426     * must be power of 2
427     * must be smaller than or equal to 128
428     * sectors_per_cluster*bytes_per_sector must not be bigger than 32K
429     */
430    for (onebit = 128;onebit >= 1;onebit = onebit>>1) {
431      if (fmt_params->sectors_per_cluster > onebit) {
432        fmt_params->sectors_per_cluster = onebit;
433        if (fmt_params->sectors_per_cluster
434            <= 32768L/fmt_params->bytes_per_sector) {
435          /* value is small enough so this value is ok */
436          onebit = 1;
437        }
438      }
439    }
440  }
441
442  if (ret_val == 0) {
443    if (fmt_params->fattype == FAT_FAT32) {
444      /* recommended: for FAT32, always set reserved sector count to 32 */
445      fmt_params->rsvd_sector_cnt = 32;
446      /* for FAT32, always set files per root directory 0 */
447      fmt_params->files_per_root_dir = 0;
448      /* location of copy of MBR */
449      fmt_params->mbr_copy_sec = 6;
450      /* location of fsinfo sector */
451      fmt_params->fsinfo_sec = 1;
452
453    }
454    else {
455      /* recommended: for FAT12/FAT16, always set reserved sector count to 1 */
456      fmt_params->rsvd_sector_cnt = 1;
457      /* recommended: for FAT16, set files per root directory to 512 */
458      /* for FAT12/FAT16, set files per root directory */
459      /* must fill up an even count of sectors         */
460      if ((rqdata != NULL) && 
461          (rqdata->files_per_root_dir > 0)) {
462        fmt_params->files_per_root_dir = rqdata->files_per_root_dir;
463      }
464      else {
465        if (fmt_params->fattype == FAT_FAT16) {
466          fmt_params->files_per_root_dir = 512;
467        }
468        else {
469          fmt_params->files_per_root_dir = 64;
470        }
471      }
472      fmt_params->files_per_root_dir = (fmt_params->files_per_root_dir + 
473                            (2*fmt_params->bytes_per_sector/
474                             FAT_DIRENTRY_SIZE-1));
475      fmt_params->files_per_root_dir -= (fmt_params->files_per_root_dir % 
476                             (2*fmt_params->bytes_per_sector
477                              /FAT_DIRENTRY_SIZE));
478    }
479    fmt_params->root_dir_sectors = 
480      (((fmt_params->files_per_root_dir * FAT_DIRENTRY_SIZE)
481        + fmt_params->bytes_per_sector - 1) 
482       / fmt_params->bytes_per_sector);
483  }
484  if (ret_val == 0) {
485    fatdata_sect_cnt = (fmt_params->totl_sector_cnt - 
486                        fmt_params->rsvd_sector_cnt - 
487                        fmt_params->root_dir_sectors);
488                       
489    /*
490     * check values to get legal arrangement of FAT type and cluster count
491     */
492
493    ret_val = msdos_format_eval_sectors_per_cluster
494      (fmt_params->fattype,
495       fmt_params->bytes_per_sector,
496       fatdata_sect_cnt,
497       fmt_params->fat_num,
498       fmt_params->sectors_per_cluster,
499       &sectors_per_cluster_adj,
500       &(fmt_params->sectors_per_fat));
501    fmt_params->sectors_per_cluster = sectors_per_cluster_adj;
502  }
503
504  /*
505   * determine media code
506   */
507  if (ret_val == 0) {
508    if ((rqdata != NULL) && 
509        (rqdata->media != 0)) {
510      const char valid_media_codes[] = 
511        {0xF0,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF};
512      if (NULL==memchr(valid_media_codes,
513                       rqdata->media,
514                       sizeof(valid_media_codes))) {
515        ret_val = -1;
516        errno = EINVAL;
517      }
518      else {
519        fmt_params->media_code = rqdata->media;
520      }
521    }
522    else {
523      fmt_params->media_code = FAT_BR_MEDIA_FIXED;
524    }
525  }
526  /*
527   * determine location and size of root directory
528   * for formatting
529   */
530  if (fmt_params->root_dir_sectors > 0) {
531    fmt_params->root_dir_start_sec = 
532      fmt_params->rsvd_sector_cnt
533      + (fmt_params-> fat_num*fmt_params->sectors_per_fat); 
534    fmt_params->root_dir_fmt_sec_cnt = fmt_params->root_dir_sectors;
535  }
536  else {
537    /*
538     * for FAT32: root directory is in cluster 2
539     */
540    fmt_params->root_dir_start_sec = 
541      fmt_params->rsvd_sector_cnt
542      + (fmt_params-> fat_num*fmt_params->sectors_per_fat); 
543    fmt_params->root_dir_fmt_sec_cnt = fmt_params->sectors_per_cluster;
544  }
545  /*
546   * determine usable OEMName
547   */
548  if (ret_val == 0) {
549      const char *from;
550      char        *to = fmt_params->OEMName;
551      int          cnt;
552      from = "RTEMS"; /* default: make "from" point to OS Name */
553    if ((rqdata != NULL) &&
554        (rqdata->OEMName != NULL)) {
555      from = rqdata->OEMName;
556    }
557    for (cnt = 0;
558         cnt < (sizeof(fmt_params->OEMName)-1);
559         cnt++) {
560      if (isprint(*from)) {
561        *to++ = *from++;
562      }
563      else {
564        /*
565         * non-printable character in given name, so keep stuck
566         * at that character and replace all following characters
567         * with a ' '
568         */
569        *to++=' ';
570      }
571      *to = '\0';
572    }
573  }
574
575  /*
576   * determine usable Volume Label
577   */
578  if (ret_val == 0) {
579      const char *from;
580      char        *to = fmt_params->VolLabel;
581      int          cnt;
582      from = ""; /* default: make "from" point to empty string */
583    if ((rqdata != NULL) &&
584        (rqdata->VolLabel != NULL)) {
585      from = rqdata->VolLabel;
586      fmt_params->VolLabel_present = TRUE;
587    }
588    for (cnt = 0;
589         cnt < (sizeof(fmt_params->VolLabel)-1);
590         cnt++) {
591      if (isprint(*from)) {
592        *to++ = *from++;
593      }
594      else {
595        /*
596         * non-printable character in given name, so keep stuck
597         * at that character and replace all following characters
598         * with a ' '
599         */
600        *to++=' ';
601      }
602      *to = '\0';
603    }
604  }
605     
606  /*
607   * determine usable Volume ID
608   */
609  if (ret_val == 0) {
610    msdos_format_gen_volid(&(fmt_params->vol_id));
611  }
612  /*
613   * Phuuu.... That's it.
614   */
615  if (ret_val != 0) {
616    set_errno_and_return_minus_one(ret_val);
617  }
618  else {
619    return 0;
620  }
621}
622/*=========================================================================*\
623| Function:                                                                 |
624\*-------------------------------------------------------------------------*/
625static int msdos_format_gen_mbr
626(
627/*-------------------------------------------------------------------------*\
628| Purpose:                                                                  |
629|     create master boot record content from parameter set                  |
630+---------------------------------------------------------------------------+
631| Input Parameters:                                                         |
632\*-------------------------------------------------------------------------*/
633 char mbr[],                           /* sector buffer                    */
634 const msdos_format_param_t *fmt_params/* computed fmt parameters          */
635 )
636/*-------------------------------------------------------------------------*\
637| Return Value:                                                             |
638|    0, if success, -1 and errno if failed                                  |
639\*=========================================================================*/
640{
641  unsigned32  total_sectors_num16 = 0;
642  unsigned32  total_sectors_num32 = 0;
643
644  /* store total sector count in either 16 or 32 bit field in mbr */
645  if (fmt_params->totl_sector_cnt < 0x10000) {
646    total_sectors_num16 = fmt_params->totl_sector_cnt;
647  }
648  else {
649    total_sectors_num32 = fmt_params->totl_sector_cnt;
650  }
651  /*
652   * finally we are there: let's fill in the values into the MBR
653   */
654  memset(mbr,0,FAT_TOTAL_MBR_SIZE);
655  /*
656   * FIXME: fill jmpBoot and Boot code...
657   * with 0xEB,....
658   */
659  /*
660   * fill OEMName
661   */
662  memcpy(FAT_GET_ADDR_BR_OEMNAME(mbr),
663         fmt_params->OEMName,
664         FAT_BR_OEMNAME_SIZE);
665  FAT_SET_BR_BYTES_PER_SECTOR(mbr    , fmt_params->bytes_per_sector);
666  FAT_SET_BR_SECTORS_PER_CLUSTER(mbr , fmt_params->sectors_per_cluster);
667  FAT_SET_BR_RESERVED_SECTORS_NUM(mbr, fmt_params->rsvd_sector_cnt);
668 
669  /* number of FATs on medium */
670  FAT_SET_BR_FAT_NUM(mbr             , 2); /* standard/recommended value */
671  FAT_SET_BR_FILES_PER_ROOT_DIR(mbr  , fmt_params->files_per_root_dir);
672  FAT_SET_BR_TOTAL_SECTORS_NUM16(mbr , total_sectors_num16);
673  FAT_SET_BR_MEDIA(mbr               , fmt_params->media_code);
674
675  FAT_SET_BR_SECTORS_PER_TRACK(mbr   , 0); /* only needed for INT13... */
676  FAT_SET_BR_NUMBER_OF_HEADS(mbr     , 0); /* only needed for INT13... */
677  FAT_SET_BR_HIDDEN_SECTORS(mbr      , 0); /* only needed for INT13... */
678
679  FAT_SET_BR_TOTAL_SECTORS_NUM32(mbr , total_sectors_num32);
680  if (fmt_params->fattype != FAT_FAT32) {
681    FAT_SET_BR_SECTORS_PER_FAT(mbr   ,fmt_params->sectors_per_fat);
682    FAT_SET_BR_DRVNUM(mbr            , 0); /* only needed for INT13... */
683    FAT_SET_BR_RSVD1(mbr             , 0); /* fill with zero */
684    FAT_SET_BR_BOOTSIG(mbr           , FAT_BR_BOOTSIG_VAL); 
685    FAT_SET_BR_VOLID(mbr             , fmt_params->vol_id); /* volume id */
686  memcpy(FAT_GET_ADDR_BR_VOLLAB(mbr),
687         fmt_params->VolLabel,
688         FAT_BR_VOLLAB_SIZE);
689    memcpy(FAT_GET_ADDR_BR_FILSYSTYPE(mbr),
690           (fmt_params->fattype == FAT_FAT12) 
691           ? "FAT12   "
692           : "FAT16   ",
693           FAT_BR_FILSYSTYPE_SIZE);
694  }
695  else {
696    FAT_SET_BR_SECTORS_PER_FAT32(mbr   ,fmt_params->sectors_per_fat);
697    FAT_SET_BR_EXT_FLAGS(mbr           , 0);
698    FAT_SET_BR_FSVER(mbr               , 0); /* FAT32 Version:0.0 */
699    FAT_SET_BR_FAT32_ROOT_CLUSTER(mbr  , 2); /* put root dir to cluster 2 */
700    FAT_SET_BR_FAT32_FS_INFO_SECTOR(mbr, 1); /* Put fsinfo  to rsrvd sec 1*/
701    FAT_SET_BR_FAT32_BK_BOOT_SECTOR(mbr, fmt_params->mbr_copy_sec ); /* Put MBR copy to rsrvd sec */
702    memset(FAT_GET_ADDR_BR_FAT32_RESERVED(mbr),0,FAT_BR_FAT32_RESERVED_SIZE);
703
704    FAT_SET_BR_FAT32_DRVNUM(mbr      , 0); /* only needed for INT13... */
705    FAT_SET_BR_FAT32_RSVD1(mbr       , 0); /* fill with zero */
706    FAT_SET_BR_FAT32_BOOTSIG(mbr     ,FAT_BR_FAT32_BOOTSIG_VAL); 
707    FAT_SET_BR_FAT32_VOLID(mbr       , 0); /* not set */
708    memset(FAT_GET_ADDR_BR_FAT32_VOLLAB(mbr)   ,0,FAT_BR_VOLLAB_SIZE);
709    memcpy(FAT_GET_ADDR_BR_FAT32_FILSYSTYPE(mbr),
710           "FAT32   ",
711           FAT_BR_FILSYSTYPE_SIZE);
712  }
713  /*
714   * add boot record signature
715   */
716  FAT_SET_BR_SIGNATURE(mbr,      FAT_BR_SIGNATURE_VAL);
717
718  /*
719   * add jump to boot loader at start of sector
720   */
721  FAT_SET_VAL8(mbr,0,0xeb);
722  FAT_SET_VAL8(mbr,1,0x3c);
723  FAT_SET_VAL8(mbr,2,0x90);
724  /*
725   * FIXME: a nice little PC boot loader would be nice here.
726   * but where can I get one for free?
727   */
728  /*
729   * Phuuu.... That's it.
730   */
731  return 0;
732}
733
734/*=========================================================================*\
735| Function:                                                                 |
736\*-------------------------------------------------------------------------*/
737static int msdos_format_gen_fsinfo
738(
739/*-------------------------------------------------------------------------*\
740| Purpose:                                                                  |
741|     create FAT32 fsinfo sector                                            |
742+---------------------------------------------------------------------------+
743| Input Parameters:                                                         |
744\*-------------------------------------------------------------------------*/
745 char fsinfo[]                         /* sector buffer                    */
746 )
747/*-------------------------------------------------------------------------*\
748| Return Value:                                                             |
749|    0, if success, -1 and errno if failed                                  |
750\*=========================================================================*/
751{
752
753  /*
754   * clear fsinfo sector data
755   */
756  memset(fsinfo,0,FAT_TOTAL_FSINFO_SIZE);
757  /*
758   * write LEADSIG, STRUCTSIG, TRAILSIG
759   */
760  FAT_SET_FSINFO_LEAD_SIGNATURE (fsinfo,FAT_FSINFO_LEAD_SIGNATURE_VALUE );
761  FAT_SET_FSINFO_STRUC_SIGNATURE(fsinfo,FAT_FSINFO_STRUC_SIGNATURE_VALUE);
762  FAT_SET_FSINFO_TRAIL_SIGNATURE(fsinfo,FAT_FSINFO_TRAIL_SIGNATURE_VALUE);
763/*
764 * write "empty" values for free cluster count and next cluster number
765 */
766  FAT_SET_FSINFO_FREE_CLUSTER_COUNT(fsinfo+FAT_FSI_INFO,
767                                    0xffffffff);
768  FAT_SET_FSINFO_NEXT_FREE_CLUSTER (fsinfo+FAT_FSI_INFO,
769                                    0xffffffff);
770  return 0;
771}
772
773/*=========================================================================*\
774| Function:                                                                 |
775\*-------------------------------------------------------------------------*/
776int msdos_format
777(
778/*-------------------------------------------------------------------------*\
779| Purpose:                                                                  |
780|     format device with msdos filesystem                                   |
781+---------------------------------------------------------------------------+
782| Input Parameters:                                                         |
783\*-------------------------------------------------------------------------*/
784 const char *devname,                  /* device name                      */
785 const msdos_format_request_param_t *rqdata  /* requested fmt parameters   */
786                                             /* set to NULL for automatic  */
787                                             /* determination              */
788 )
789/*-------------------------------------------------------------------------*\
790| Return Value:                                                             |
791|    0, if success, -1 and errno if failed                                  |
792\*=========================================================================*/
793{
794  char         tmp_sec[FAT_TOTAL_MBR_SIZE];
795  int          rc;
796  disk_device *dd        = NULL; 
797  struct stat  stat_buf;
798  int          ret_val   = 0;
799  int          fd        = -1;
800  int          i;
801  msdos_format_param_t fmt_params;
802
803  /*
804   * sanity check on device
805   */
806  if (ret_val == 0) {
807    rc = stat(devname, &stat_buf);
808    ret_val = rc;
809  }
810 
811  /* rtems feature: no block devices, all are character devices */   
812  if ((ret_val == 0) &&
813      (!S_ISCHR(stat_buf.st_mode))) {
814    errno = ENOTBLK;
815    ret_val = -1;
816  }
817 
818  /* check that  device is registered as block device and lock it */
819  if (ret_val == 0) {
820    dd = rtems_disk_lookup(stat_buf.st_dev);
821    if (dd == NULL) {
822      errno = ENOTBLK;
823      ret_val = -1;
824    }
825  }
826
827  /*
828   * open device for writing
829   */
830  if (ret_val == 0) {
831    fd = open(devname, O_WRONLY);
832    if (fd == -1)
833    {
834      ret_val= -1;
835    }   
836  } 
837
838  /*
839   * compute formatting parameters
840   */
841  if (ret_val == 0) {
842    ret_val = msdos_format_determine_fmt_params(dd,rqdata,&fmt_params);
843  }
844  /*
845   * if requested, write whole disk/partition with 0xe5
846   */
847  if ((ret_val == 0) &&
848      (rqdata != NULL) &&
849      !(rqdata->quick_format)) {
850    ret_val = msdos_format_fill_sectors
851      (fd,
852       0,                            /* start sector */
853       fmt_params.totl_sector_cnt,   /* sector count */
854       fmt_params.bytes_per_sector,
855       0xe5);
856  }
857  /*
858   * create master boot record
859   */
860  if (ret_val == 0) {
861    ret_val = msdos_format_gen_mbr(tmp_sec,&fmt_params);
862  }
863  /*
864   * write master boot record to disk
865   * also write copy of MBR to disk
866   */
867  if (ret_val == 0) {
868    ret_val = msdos_format_write_sec(fd, 
869                                     0, 
870                                     fmt_params.bytes_per_sector,
871                                     (void *)tmp_sec);
872  }
873  if ((ret_val == 0) && 
874      (fmt_params.mbr_copy_sec != 0)) {
875    /*
876     * write copy of MBR
877     */
878    ret_val = msdos_format_write_sec(fd, 
879                                     fmt_params.mbr_copy_sec , 
880                                     fmt_params.bytes_per_sector,
881                                     (void *)tmp_sec);
882  }
883  /*
884   * for FAT32: initialize info sector on disk
885   */
886  if ((ret_val == 0) && 
887      (fmt_params.fsinfo_sec != 0)) {
888      ret_val = msdos_format_gen_fsinfo(tmp_sec);
889  }
890  /*
891   * write fsinfo sector
892   */
893  if ((ret_val == 0) &&
894      (fmt_params.fsinfo_sec != 0)) {
895    ret_val = msdos_format_write_sec(fd, 
896                                     fmt_params.fsinfo_sec,
897                                     fmt_params.bytes_per_sector,
898                                     (void *)tmp_sec);
899  }
900  /*
901   * write FAT as all empty
902   * -> write all FAT sectors as zero
903   */
904  if (ret_val == 0) {
905    ret_val = msdos_format_fill_sectors
906      (fd,
907       fmt_params.rsvd_sector_cnt,                   /* start sector */
908       fmt_params.fat_num*fmt_params.sectors_per_fat,/* sector count */
909       fmt_params.bytes_per_sector,
910       0x00);
911  }
912  /*
913   * clear/init root directory
914   * -> write all directory sectors as 0x00
915   */
916  if (ret_val == 0) {
917    ret_val = msdos_format_fill_sectors
918      (fd,
919       fmt_params.root_dir_start_sec,        /* start sector */
920       fmt_params.root_dir_fmt_sec_cnt,      /* sector count */
921       fmt_params.bytes_per_sector,
922       0x00);
923  }
924  /*
925   * write volume label to first entry of directory
926   */
927  if ((ret_val == 0) && fmt_params.VolLabel_present) {
928    memset(tmp_sec,0,sizeof(tmp_sec));
929    memcpy(MSDOS_DIR_NAME(tmp_sec),fmt_params.VolLabel,MSDOS_SHORT_NAME_LEN);
930    *MSDOS_DIR_ATTR(tmp_sec) = MSDOS_ATTR_VOLUME_ID;
931    ret_val = msdos_format_write_sec
932      (fd,
933       fmt_params.root_dir_start_sec,
934       fmt_params.bytes_per_sector,
935       tmp_sec);
936  }
937  /*
938   * write FAT entry 0 as (0xffffff00|Media_type)EOC,
939   * write FAT entry 1 as EOC
940   * allocate directory in a FAT32 FS
941   */
942  if ((ret_val == 0) && fmt_params.VolLabel_present){
943    /*
944     * empty sector: all clusters are free/do not link further on
945     */
946    memset(tmp_sec,0,sizeof(tmp_sec));
947
948    switch(fmt_params.fattype) {
949    case FAT_FAT12:
950      /* LSBits of FAT entry 0: media_type */
951      FAT_SET_VAL8(tmp_sec,0,(fmt_params.media_code));
952      /* MSBits of FAT entry 0:0xf, LSBits of FAT entry 1: LSB of EOC */
953      FAT_SET_VAL8(tmp_sec,1,(0x0f | (FAT_FAT12_EOC << 4)));
954      /* MSBits of FAT entry 1: MSBits of EOC */
955      FAT_SET_VAL8(tmp_sec,2,(FAT_FAT12_EOC >> 4));
956      break;
957
958    case FAT_FAT16:
959      /* FAT entry 0: 0xff00|media_type */
960      FAT_SET_VAL16(tmp_sec,0,0xff00|fmt_params.media_code);
961      /* FAT entry 1: EOC */
962      FAT_SET_VAL16(tmp_sec,2,FAT_FAT16_EOC);
963      break;
964
965    case FAT_FAT32:
966      /* FAT entry 0: 0xffffff00|media_type */
967      FAT_SET_VAL32(tmp_sec,0,0xffffff00|fmt_params.media_code);
968      /* FAT entry 1: EOC */
969      FAT_SET_VAL32(tmp_sec,4,FAT_FAT32_EOC);
970      break;
971
972    default:
973      ret_val = -1;
974      errno = EINVAL;
975    }
976    if (fmt_params.fattype == FAT_FAT32) {
977      /*
978       * only first valid cluster (cluster number 2) belongs
979       * to root directory, and is end of chain
980       * mark this in every copy of the FAT
981       */
982      FAT_SET_VAL32(tmp_sec,8,FAT_FAT32_EOC);
983    }
984    for (i = 0;
985         (i < fmt_params.fat_num) && (ret_val == 0);
986         i++) {
987      ret_val = msdos_format_write_sec
988        (fd,
989         fmt_params.rsvd_sector_cnt
990         + (i * fmt_params.sectors_per_fat),
991         fmt_params.bytes_per_sector,
992         tmp_sec);
993    }
994  }
995  /*
996   * cleanup:
997   * sync and unlock disk
998   * free any data structures (not needed now)
999   */
1000  if (fd != -1) {
1001    close(fd);
1002  }
1003  if (dd != NULL) {
1004    rtems_disk_release(dd);
1005  }
1006  return ret_val;
1007}
Note: See TracBrowser for help on using the repository browser.