OSDN Git Service

Fixed options string parsing.
[android-x86/external-exfat.git] / libexfat / mount.c
1 /*
2  *  mount.c
3  *  exFAT file system implementation library.
4  *
5  *  Created by Andrew Nayenko on 22.10.09.
6  *  This software is distributed under the GNU General Public License 
7  *  version 3 or any later.
8  */
9
10 #include "exfat.h"
11 #include <string.h>
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #define _XOPEN_SOURCE /* for tzset() in Linux */
19 #include <time.h>
20
21 static uint64_t rootdir_size(const struct exfat* ef)
22 {
23         uint64_t clusters = 0;
24         cluster_t rootdir_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
25
26         while (!CLUSTER_INVALID(rootdir_cluster))
27         {
28                 clusters++;
29                 /* root directory cannot be contiguous because there is no flag
30                    to indicate this */
31                 rootdir_cluster = exfat_next_cluster(ef, ef->root, rootdir_cluster);
32         }
33         return clusters * CLUSTER_SIZE(*ef->sb);
34 }
35
36 static const char* get_option(const char* options, const char* option_name)
37 {
38         const char* p;
39         size_t length = strlen(option_name);
40
41         for (p = strstr(options, option_name); p; p = strstr(p + 1, option_name))
42                 if ((p == options || p[-1] == ',') && p[length] == '=')
43                         return p + length + 1;
44         return NULL;
45 }
46
47 static int get_int_option(const char* options, const char* option_name,
48                 int base, int default_value)
49 {
50         const char* p = get_option(options, option_name);
51
52         if (p == NULL)
53                 return default_value;
54         return strtol(p, NULL, base);
55 }
56
57 static void parse_options(struct exfat* ef, const char* options)
58 {
59         int sys_umask = umask(0);
60         int opt_umask;
61
62         umask(sys_umask); /* restore umask */
63         opt_umask = get_int_option(options, "umask", 8, sys_umask);
64         ef->dmask = get_int_option(options, "dmask", 8, opt_umask) & 0777;
65         ef->fmask = get_int_option(options, "fmask", 8, opt_umask) & 0777;
66 }
67
68 int exfat_mount(struct exfat* ef, const char* spec, const char* options)
69 {
70         tzset();
71         memset(ef, 0, sizeof(struct exfat));
72
73         ef->sb = malloc(sizeof(struct exfat_super_block));
74         if (ef->sb == NULL)
75         {
76                 exfat_error("memory allocation failed");
77                 return -ENOMEM;
78         }
79         memset(ef->sb, 0, sizeof(struct exfat_super_block));
80
81         parse_options(ef, options);
82
83         ef->fd = open(spec, O_RDWR);
84         if (ef->fd < 0)
85         {
86                 free(ef->sb);
87                 exfat_error("failed to open `%s'", spec);
88                 return -EIO;
89         }
90
91         exfat_read_raw(ef->sb, sizeof(struct exfat_super_block), 0, ef->fd);
92         if (memcmp(ef->sb->oem_name, "EXFAT   ", 8) != 0)
93         {
94                 close(ef->fd);
95                 free(ef->sb);
96                 exfat_error("exFAT file system is not found");
97                 return -EIO;
98         }
99
100         ef->zero_block = malloc(BLOCK_SIZE(*ef->sb));
101         if (ef->zero_block == NULL)
102         {
103                 close(ef->fd);
104                 free(ef->sb);
105                 exfat_error("failed to allocate zero block");
106                 return -ENOMEM;
107         }
108         memset(ef->zero_block, 0, BLOCK_SIZE(*ef->sb));
109
110         ef->root = malloc(sizeof(struct exfat_node));
111         if (ef->root == NULL)
112         {
113                 free(ef->zero_block);
114                 close(ef->fd);
115                 free(ef->sb);
116                 exfat_error("failed to allocate root node");
117                 return -ENOMEM;
118         }
119         memset(ef->root, 0, sizeof(struct exfat_node));
120         ef->root->flags = EXFAT_ATTRIB_DIR;
121         ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
122         ef->root->fptr_cluster = ef->root->start_cluster;
123         ef->root->name[0] = cpu_to_le16('\0');
124         ef->root->size = rootdir_size(ef);
125         /* exFAT does not have time attributes for the root directory */
126         ef->root->mtime = 0;
127         ef->root->atime = 0;
128         /* always keep at least 1 reference to the root node */
129         exfat_get_node(ef->root);
130
131         return 0;
132 }
133
134 void exfat_unmount(struct exfat* ef)
135 {
136         exfat_put_node(ef, ef->root);
137         exfat_reset_cache(ef);
138         free(ef->root);
139         ef->root = NULL;
140         free(ef->zero_block);
141         ef->zero_block = NULL;
142         free(ef->cmap.chunk);
143         ef->cmap.chunk = NULL;
144         close(ef->fd);
145         ef->fd = 0;
146         free(ef->sb);
147         ef->sb = NULL;
148         free(ef->upcase);
149         ef->upcase = NULL;
150         ef->upcase_chars = 0;
151 }