OSDN Git Service

Implemented uid and gid mount options.
[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         ef->uid = get_int_option(options, "uid", 10, geteuid());
68         ef->gid = get_int_option(options, "gid", 10, getegid());
69 }
70
71 int exfat_mount(struct exfat* ef, const char* spec, const char* options)
72 {
73         tzset();
74         memset(ef, 0, sizeof(struct exfat));
75
76         ef->sb = malloc(sizeof(struct exfat_super_block));
77         if (ef->sb == NULL)
78         {
79                 exfat_error("memory allocation failed");
80                 return -ENOMEM;
81         }
82         memset(ef->sb, 0, sizeof(struct exfat_super_block));
83
84         parse_options(ef, options);
85
86         ef->fd = open(spec, O_RDWR);
87         if (ef->fd < 0)
88         {
89                 free(ef->sb);
90                 exfat_error("failed to open `%s'", spec);
91                 return -EIO;
92         }
93
94         exfat_read_raw(ef->sb, sizeof(struct exfat_super_block), 0, ef->fd);
95         if (memcmp(ef->sb->oem_name, "EXFAT   ", 8) != 0)
96         {
97                 close(ef->fd);
98                 free(ef->sb);
99                 exfat_error("exFAT file system is not found");
100                 return -EIO;
101         }
102
103         ef->zero_block = malloc(BLOCK_SIZE(*ef->sb));
104         if (ef->zero_block == NULL)
105         {
106                 close(ef->fd);
107                 free(ef->sb);
108                 exfat_error("failed to allocate zero block");
109                 return -ENOMEM;
110         }
111         memset(ef->zero_block, 0, BLOCK_SIZE(*ef->sb));
112
113         ef->root = malloc(sizeof(struct exfat_node));
114         if (ef->root == NULL)
115         {
116                 free(ef->zero_block);
117                 close(ef->fd);
118                 free(ef->sb);
119                 exfat_error("failed to allocate root node");
120                 return -ENOMEM;
121         }
122         memset(ef->root, 0, sizeof(struct exfat_node));
123         ef->root->flags = EXFAT_ATTRIB_DIR;
124         ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
125         ef->root->fptr_cluster = ef->root->start_cluster;
126         ef->root->name[0] = cpu_to_le16('\0');
127         ef->root->size = rootdir_size(ef);
128         /* exFAT does not have time attributes for the root directory */
129         ef->root->mtime = 0;
130         ef->root->atime = 0;
131         /* always keep at least 1 reference to the root node */
132         exfat_get_node(ef->root);
133
134         return 0;
135 }
136
137 void exfat_unmount(struct exfat* ef)
138 {
139         exfat_put_node(ef, ef->root);
140         exfat_reset_cache(ef);
141         free(ef->root);
142         ef->root = NULL;
143         free(ef->zero_block);
144         ef->zero_block = NULL;
145         free(ef->cmap.chunk);
146         ef->cmap.chunk = NULL;
147         close(ef->fd);
148         ef->fd = 0;
149         free(ef->sb);
150         ef->sb = NULL;
151         free(ef->upcase);
152         ef->upcase = NULL;
153         ef->upcase_chars = 0;
154 }