~ubuntu-branches/ubuntu/trusty/util-linux/trusty-proposed

« back to all changes in this revision

Viewing changes to libblkid/src/superblocks/exfat.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones
  • Date: 2011-11-03 15:38:23 UTC
  • mto: (4.5.5 sid) (1.6.4)
  • mto: This revision was merged to the branch mainline in revision 85.
  • Revision ID: package-import@ubuntu.com-20111103153823-10sx16jprzxlhkqf
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010 Andrew Nayenko <resver@gmail.com>
 
3
 *
 
4
 * This file may be redistributed under the terms of the
 
5
 * GNU Lesser General Public License.
 
6
 */
 
7
#include "superblocks.h"
 
8
 
 
9
struct exfat_super_block {
 
10
        uint8_t jump[3];
 
11
        uint8_t oem_name[8];
 
12
        uint8_t __unused1[53];
 
13
        uint64_t block_start;
 
14
        uint64_t block_count;
 
15
        uint32_t fat_block_start;
 
16
        uint32_t fat_block_count;
 
17
        uint32_t cluster_block_start;
 
18
        uint32_t cluster_count;
 
19
        uint32_t rootdir_cluster;
 
20
        uint8_t volume_serial[4];
 
21
        struct {
 
22
                uint8_t minor;
 
23
                uint8_t major;
 
24
        } version;
 
25
        uint16_t volume_state;
 
26
        uint8_t block_bits;
 
27
        uint8_t bpc_bits;
 
28
        uint8_t fat_count;
 
29
        uint8_t drive_no;
 
30
        uint8_t allocated_percent;
 
31
} __attribute__((__packed__));
 
32
 
 
33
struct exfat_entry_label {
 
34
        uint8_t type;
 
35
        uint8_t length;
 
36
        uint8_t name[30];
 
37
} __attribute__((__packed__));
 
38
 
 
39
#define BLOCK_SIZE(sb) (1 << (sb)->block_bits)
 
40
#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb)->bpc_bits)
 
41
#define EXFAT_FIRST_DATA_CLUSTER 2
 
42
#define EXFAT_LAST_DATA_CLUSTER 0xffffff6
 
43
#define EXFAT_ENTRY_SIZE 32
 
44
 
 
45
#define EXFAT_ENTRY_EOD         0x00
 
46
#define EXFAT_ENTRY_LABEL       0x83
 
47
 
 
48
static blkid_loff_t block_to_offset(const struct exfat_super_block *sb,
 
49
                blkid_loff_t block)
 
50
{
 
51
        return (blkid_loff_t) block << sb->block_bits;
 
52
}
 
53
 
 
54
static blkid_loff_t cluster_to_block(const struct exfat_super_block *sb,
 
55
                uint32_t cluster)
 
56
{
 
57
        return le32_to_cpu(sb->cluster_block_start) +
 
58
                        ((blkid_loff_t) (cluster - EXFAT_FIRST_DATA_CLUSTER)
 
59
                                        << sb->bpc_bits);
 
60
}
 
61
 
 
62
static blkid_loff_t cluster_to_offset(const struct exfat_super_block *sb,
 
63
                uint32_t cluster)
 
64
{
 
65
        return block_to_offset(sb, cluster_to_block(sb, cluster));
 
66
}
 
67
 
 
68
static uint32_t next_cluster(blkid_probe pr,
 
69
                const struct exfat_super_block *sb, uint32_t cluster)
 
70
{
 
71
        uint32_t *next;
 
72
        blkid_loff_t fat_offset;
 
73
 
 
74
        fat_offset = block_to_offset(sb, le32_to_cpu(sb->fat_block_start))
 
75
                + (blkid_loff_t) cluster * sizeof(cluster);
 
76
        next = (uint32_t *) blkid_probe_get_buffer(pr, fat_offset,
 
77
                        sizeof(uint32_t));
 
78
        if (!next)
 
79
                return 0;
 
80
        return le32_to_cpu(*next);
 
81
}
 
82
 
 
83
static struct exfat_entry_label *find_label(blkid_probe pr,
 
84
                const struct exfat_super_block *sb)
 
85
{
 
86
        uint32_t cluster = le32_to_cpu(sb->rootdir_cluster);
 
87
        blkid_loff_t offset = cluster_to_offset(sb, cluster);
 
88
        uint8_t *entry;
 
89
 
 
90
        for (;;) {
 
91
                entry = (uint8_t *) blkid_probe_get_buffer(pr, offset,
 
92
                                EXFAT_ENTRY_SIZE);
 
93
                if (!entry)
 
94
                        return NULL;
 
95
                if (entry[0] == EXFAT_ENTRY_EOD)
 
96
                        return NULL;
 
97
                if (entry[0] == EXFAT_ENTRY_LABEL)
 
98
                        return (struct exfat_entry_label *) entry;
 
99
                offset += EXFAT_ENTRY_SIZE;
 
100
                if (offset % CLUSTER_SIZE(sb) == 0) {
 
101
                        cluster = next_cluster(pr, sb, cluster);
 
102
                        if (cluster < EXFAT_FIRST_DATA_CLUSTER)
 
103
                                return NULL;
 
104
                        if (cluster > EXFAT_LAST_DATA_CLUSTER)
 
105
                                return NULL;
 
106
                        offset = cluster_to_offset(sb, cluster);
 
107
                }
 
108
        }
 
109
}
 
110
 
 
111
static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag)
 
112
{
 
113
        struct exfat_super_block *sb;
 
114
        struct exfat_entry_label *label;
 
115
 
 
116
        sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block);
 
117
        if (!sb)
 
118
                return -1;
 
119
 
 
120
        label = find_label(pr, sb);
 
121
        if (label)
 
122
                blkid_probe_set_utf8label(pr, label->name,
 
123
                                min(label->length * 2, 30), BLKID_ENC_UTF16LE);
 
124
 
 
125
        blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4,
 
126
                        "%02hhX%02hhX-%02hhX%02hhX",
 
127
                        sb->volume_serial[3], sb->volume_serial[2],
 
128
                        sb->volume_serial[1], sb->volume_serial[0]);
 
129
 
 
130
        blkid_probe_sprintf_version(pr, "%hu.%hu",
 
131
                        sb->version.major, sb->version.minor);
 
132
 
 
133
        return 0;
 
134
}
 
135
 
 
136
const struct blkid_idinfo exfat_idinfo =
 
137
{
 
138
        .name           = "exfat",
 
139
        .usage          = BLKID_USAGE_FILESYSTEM,
 
140
        .probefunc      = probe_exfat,
 
141
        .magics         =
 
142
        {
 
143
                { .magic = "EXFAT   ", .len = 8, .sboff = 3 },
 
144
                { NULL }
 
145
        }
 
146
};