Subversion Repositories QNX 8.QNX8 utilities

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. // doslabel.c -- read/set the volume labels of DOS partitions by Pierre-Marie Baty <pm@pmbaty.com>
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <ctype.h>
  8.  
  9.  
  10. int main (int argc, char **argv)
  11. {
  12.         // program entrypoint
  13.  
  14.         typedef struct __attribute__((packed)) fatfs_header_s
  15.         {
  16.                 unsigned char bootstrap_code[3]; // offset 0
  17.                 char oem_name_and_version[8]; // offset 3
  18.                 unsigned short bytes_per_sector; // offset 11
  19.                 unsigned char sectors_per_cluster; // offset 13
  20.                 unsigned short reserved_sectors; // offset 14
  21.                 unsigned char fat_copies; // offset 16
  22.                 unsigned short rootdir_entries; // offset 17
  23.                 unsigned short total_sectors; // offset 19
  24.                 unsigned char media_type; // offset 21
  25.                 unsigned short sectors_per_fat; // offset 22
  26.                 unsigned short sectors_per_track; // offset 24
  27.                 unsigned short heads; // offset 26
  28.                 unsigned short hidden_sectors; // offset 28;
  29.         } fatfs_header_t;
  30.  
  31.         unsigned char first_sector[512];
  32.         fatfs_header_t *fat_header;
  33.         const char *dev_pathname;
  34.         size_t label_offset;
  35.         size_t char_index;
  36.         char *new_label;
  37.         char label[12];
  38.         FILE *fp;
  39.  
  40.         // consistency checks
  41.         if ((argc < 2) || (*(argv[1]) == '-'))
  42.         {
  43.                 fprintf (stderr, "usage: doslabel <device> [new-label]\n");
  44.                 exit (1);
  45.         }
  46.  
  47.         dev_pathname = argv[1]; // read arguments
  48.         new_label = (argc > 2 ? argv[2] : NULL);
  49.  
  50.         // open and read the first sector of the passed device pathname
  51.         if (((fp = fopen (dev_pathname, "r+b")) == NULL) || (fread (first_sector, 512, 1, fp) != 1))
  52.         {
  53.                 fprintf (stderr, "error: can't read first sector of %s: %s\n", dev_pathname, strerror (errno));
  54.                 exit (1);
  55.         }
  56.  
  57.         // consistency checks
  58.         fat_header = (fatfs_header_t *) first_sector;
  59.  
  60.         // is it a FAT12/FAT16 or FAT32 BPB ?
  61.         if ((memcmp (&first_sector[510], "\x55\xaa", 2) == 0)
  62.             && (   (fat_header->bytes_per_sector == 512)
  63.                 || (fat_header->bytes_per_sector == 1024)
  64.                 || (fat_header->bytes_per_sector == 2048)
  65.                 || (fat_header->bytes_per_sector == 4096))
  66.             && (   (fat_header->sectors_per_cluster == 1)
  67.                 || (fat_header->sectors_per_cluster == 2)
  68.                 || (fat_header->sectors_per_cluster == 4)
  69.                 || (fat_header->sectors_per_cluster == 8)
  70.                 || (fat_header->sectors_per_cluster == 16)
  71.                 || (fat_header->sectors_per_cluster == 32)
  72.                 || (fat_header->sectors_per_cluster == 64)
  73.                 || (fat_header->sectors_per_cluster == 128))
  74.             && (   (fat_header->reserved_sectors == 1)
  75.                 || (fat_header->reserved_sectors == 32)))
  76.                 label_offset = (fat_header->sectors_per_fat != 0 ? 43 : 71);
  77.         else
  78.         {
  79.                 // volume labels in exFAT filesystems are actually directory entries with a special flag
  80.                 // we don't support that at the moment (FIXME)
  81.                 // that's fine, because EFI partitions can't be exFAT -- only FAT12/16.
  82.                 fprintf (stderr, "error: only FAT12/FAT16/FAT32 filesystems are supported\n");
  83.                 exit (1);
  84.         }
  85.  
  86.         // do we want to read or set the volume label ?
  87.         if (new_label == NULL)
  88.         {
  89.                 // read the label and strip it from trailing spaces
  90.                 memcpy (label, &first_sector[label_offset], 11);
  91.                 label[11] = 0;
  92.                 for (char_index = 10; char_index > 0; char_index--)
  93.                         if (label[char_index] == ' ')
  94.                                 label[char_index] = 0;
  95.                         else
  96.                                 break;
  97.                 if (label[char_index] == ' ')
  98.                         label[char_index] = 0;
  99.  
  100.                 // print it to the standard output
  101.                 printf ("%s\n", label);
  102.         }
  103.         else if (argc == 3)
  104.         {
  105.                 // write a new DOS partition label
  106.                 fseek (fp, label_offset, SEEK_SET); // can't fail
  107.                 memset (label, ' ', sizeof (label));
  108.                 memcpy (label, new_label, strlen (new_label));
  109.                 if (fwrite (label, 11, 1, fp) != 1)
  110.                 {
  111.                         fprintf (stderr, "error: can't write new volume label to %s: %s\n", dev_pathname, strerror (errno));
  112.                         exit (1);
  113.                 }
  114.         }
  115.  
  116.         fclose (fp);
  117.         exit (0);
  118. }
  119.