OSDN Git Service

56b78ab56d53c665d8686be3c97fdcaa73477c92
[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 = strstr(options, option_name);
39         size_t length = strlen(option_name);
40
41         if (p == NULL)
42                 return NULL;
43         if ((p != options && p[-1] != ',') || p[length] != '=')
44                 return NULL;
45         return p + length + 1;
46 }
47
48 static int get_int_option(const char* options, const char* option_name,
49                 int base, int default_value)
50 {
51         const char* p = get_option(options, option_name);
52
53         if (p == NULL)
54                 return default_value;
55         return strtol(p, NULL, base);
56 }
57
58 static void parse_options(struct exfat* ef, const char* options)
59 {
60         int sys_umask = umask(0);
61         int opt_umask;
62
63         umask(sys_umask); /* restore umask */
64         opt_umask = get_int_option(options, "umask", 8, sys_umask);
65         ef->dmask = get_int_option(options, "dmask", 8, opt_umask) & 0777;
66         ef->fmask = get_int_option(options, "fmask", 8, opt_umask) & 0777;
67 }
68
69 int exfat_mount(struct exfat* ef, const char* spec, const char* options)
70 {
71         tzset();
72         memset(ef, 0, sizeof(struct exfat));
73
74         ef->sb = malloc(sizeof(struct exfat_super_block));
75         if (ef->sb == NULL)
76         {
77                 exfat_error("memory allocation failed");
78                 return -ENOMEM;
79         }
80         memset(ef->sb, 0, sizeof(struct exfat_super_block));
81
82         parse_options(ef, options);
83
84         ef->fd = open(spec, O_RDWR);
85         if (ef->fd < 0)
86         {
87                 free(ef->sb);
88                 exfat_error("failed to open `%s'", spec);
89                 return -EIO;
90         }
91
92         exfat_read_raw(ef->sb, sizeof(struct exfat_super_block), 0, ef->fd);
93         if (memcmp(ef->sb->oem_name, "EXFAT   ", 8) != 0)
94         {
95                 close(ef->fd);
96                 free(ef->sb);
97                 exfat_error("exFAT file system is not found");
98                 return -EIO;
99         }
100
101         ef->zero_block = malloc(BLOCK_SIZE(*ef->sb));
102         if (ef->zero_block == NULL)
103         {
104                 close(ef->fd);
105                 free(ef->sb);
106                 exfat_error("failed to allocate zero block");
107                 return -ENOMEM;
108         }
109         memset(ef->zero_block, 0, BLOCK_SIZE(*ef->sb));
110
111         ef->root = malloc(sizeof(struct exfat_node));
112         if (ef->root == NULL)
113         {
114                 free(ef->zero_block);
115                 close(ef->fd);
116                 free(ef->sb);
117                 exfat_error("failed to allocate root node");
118                 return -ENOMEM;
119         }
120         memset(ef->root, 0, sizeof(struct exfat_node));
121         ef->root->flags = EXFAT_ATTRIB_DIR;
122         ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
123         ef->root->fptr_cluster = ef->root->start_cluster;
124         ef->root->name[0] = cpu_to_le16('\0');
125         ef->root->size = rootdir_size(ef);
126         /* exFAT does not have time attributes for the root directory */
127         ef->root->mtime = 0;
128         ef->root->atime = 0;
129         /* always keep at least 1 reference to the root node */
130         exfat_get_node(ef->root);
131
132         return 0;
133 }
134
135 void exfat_unmount(struct exfat* ef)
136 {
137         exfat_put_node(ef, ef->root);
138         exfat_reset_cache(ef);
139         free(ef->root);
140         ef->root = NULL;
141         free(ef->zero_block);
142         ef->zero_block = NULL;
143         free(ef->cmap.chunk);
144         ef->cmap.chunk = NULL;
145         close(ef->fd);
146         ef->fd = 0;
147         free(ef->sb);
148         ef->sb = NULL;
149         free(ef->upcase);
150         ef->upcase = NULL;
151         ef->upcase_chars = 0;
152 }