OSDN Git Service

Fixed memory leak: free root node structure on unmount.
[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 <errno.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #define _XOPEN_SOURCE /* for tzset() in Linux */
16 #include <time.h>
17
18 static uint64_t rootdir_size(const struct exfat* ef)
19 {
20         uint64_t clusters = 0;
21         cluster_t rootdir_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
22
23         while (!CLUSTER_INVALID(rootdir_cluster))
24         {
25                 clusters++;
26                 /* root directory cannot be contiguous because there is no flag
27                    to indicate this */
28                 rootdir_cluster = exfat_next_cluster(ef, ef->root, rootdir_cluster);
29         }
30         return clusters * CLUSTER_SIZE(*ef->sb);
31 }
32
33 int exfat_mount(struct exfat* ef, const char* spec)
34 {
35         tzset();
36         memset(ef, 0, sizeof(struct exfat));
37
38         ef->sb = malloc(sizeof(struct exfat_super_block));
39         if (ef->sb == NULL)
40         {
41                 exfat_error("memory allocation failed");
42                 return -ENOMEM;
43         }
44         memset(ef->sb, 0, sizeof(struct exfat_super_block));
45
46         ef->fd = open(spec, O_RDWR);
47         if (ef->fd < 0)
48         {
49                 free(ef->sb);
50                 exfat_error("failed to open `%s'", spec);
51                 return -EIO;
52         }
53
54         exfat_read_raw(ef->sb, sizeof(struct exfat_super_block), 0, ef->fd);
55         if (memcmp(ef->sb->oem_name, "EXFAT   ", 8) != 0)
56         {
57                 close(ef->fd);
58                 free(ef->sb);
59                 exfat_error("exFAT file system is not found");
60                 return -EIO;
61         }
62
63         ef->zero_block = malloc(BLOCK_SIZE(*ef->sb));
64         if (ef->zero_block == NULL)
65         {
66                 close(ef->fd);
67                 free(ef->sb);
68                 exfat_error("failed to allocate zero block");
69                 return -ENOMEM;
70         }
71         memset(ef->zero_block, 0, BLOCK_SIZE(*ef->sb));
72
73         ef->root = malloc(sizeof(struct exfat_node));
74         if (ef->root == NULL)
75         {
76                 free(ef->zero_block);
77                 close(ef->fd);
78                 free(ef->sb);
79                 exfat_error("failed to allocate root node");
80                 return -ENOMEM;
81         }
82         memset(ef->root, 0, sizeof(struct exfat_node));
83         ef->root->flags = EXFAT_ATTRIB_DIR;
84         ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
85         ef->root->fptr_cluster = ef->root->start_cluster;
86         ef->root->name[0] = cpu_to_le16('\0');
87         ef->root->size = rootdir_size(ef);
88         /* exFAT does not have time attributes for the root directory */
89         ef->root->mtime = 0;
90         ef->root->atime = 0;
91         /* always keep at least 1 reference to the root node */
92         exfat_get_node(ef->root);
93
94         return 0;
95 }
96
97 void exfat_unmount(struct exfat* ef)
98 {
99         exfat_put_node(ef, ef->root);
100         exfat_reset_cache(ef);
101         free(ef->root);
102         ef->root = NULL;
103         free(ef->zero_block);
104         ef->zero_block = NULL;
105         free(ef->cmap.chunk);
106         ef->cmap.chunk = NULL;
107         close(ef->fd);
108         ef->fd = 0;
109         free(ef->sb);
110         ef->sb = NULL;
111         free(ef->upcase);
112         ef->upcase = NULL;
113         ef->upcase_chars = 0;
114 }