OSDN Git Service

Update atime on read.
[android-x86/external-exfat.git] / libexfat / io.c
1 /*
2  *  io.c
3  *  exFAT file system implementation library.
4  *
5  *  Created by Andrew Nayenko on 02.09.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 <inttypes.h>
12 #include <sys/types.h>
13 #include <sys/uio.h>
14 #define __USE_UNIX98 /* for pread() in Linux */
15 #include <unistd.h>
16
17 #if _FILE_OFFSET_BITS != 64
18         #error You should define _FILE_OFFSET_BITS=64
19 #endif
20
21 void exfat_read_raw(void* buffer, size_t size, off_t offset, int fd)
22 {
23         if (pread(fd, buffer, size, offset) != size)
24                 exfat_bug("failed to read %zu bytes from file at %"PRIu64, size,
25                                 (uint64_t) offset);
26 }
27
28 void exfat_write_raw(const void* buffer, size_t size, off_t offset, int fd)
29 {
30         if (pwrite(fd, buffer, size, offset) != size)
31                 exfat_bug("failed to write %zu bytes to file at %"PRIu64, size,
32                                 (uint64_t) offset);
33 }
34
35 ssize_t exfat_read(const struct exfat* ef, struct exfat_node* node,
36                 void* buffer, size_t size, off_t offset)
37 {
38         cluster_t cluster;
39         char* bufp = buffer;
40         off_t lsize, loffset, remainder;
41
42         if (offset >= node->size)
43                 return 0;
44         if (size == 0)
45                 return 0;
46
47         cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb));
48         if (CLUSTER_INVALID(cluster))
49         {
50                 exfat_error("got invalid cluster");
51                 return -1;
52         }
53
54         loffset = offset % CLUSTER_SIZE(*ef->sb);
55         remainder = MIN(size, node->size - offset);
56         while (remainder > 0)
57         {
58                 if (CLUSTER_INVALID(cluster))
59                 {
60                         exfat_error("got invalid cluster");
61                         return -1;
62                 }
63                 lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
64                 exfat_read_raw(bufp, lsize, exfat_c2o(ef, cluster) + loffset, ef->fd);
65                 bufp += lsize;
66                 loffset = 0;
67                 remainder -= lsize;
68                 cluster = exfat_next_cluster(ef, node, cluster);
69         }
70         if (!ef->ro)
71                 exfat_update_atime(node);
72         return size - remainder;
73 }
74
75 ssize_t exfat_write(struct exfat* ef, struct exfat_node* node,
76                 const void* buffer, size_t size, off_t offset)
77 {
78         cluster_t cluster;
79         const char* bufp = buffer;
80         off_t lsize, loffset, remainder;
81
82         if (offset + size > node->size)
83         {
84                 int rc = exfat_truncate(ef, node, offset + size);
85                 if (rc != 0)
86                         return rc;
87         }
88         if (size == 0)
89                 return 0;
90
91         cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb));
92         if (CLUSTER_INVALID(cluster))
93         {
94                 exfat_error("got invalid cluster");
95                 return -1;
96         }
97
98         loffset = offset % CLUSTER_SIZE(*ef->sb);
99         remainder = size;
100         while (remainder > 0)
101         {
102                 if (CLUSTER_INVALID(cluster))
103                 {
104                         exfat_error("got invalid cluster");
105                         return -1;
106                 }
107                 lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
108                 exfat_write_raw(bufp, lsize, exfat_c2o(ef, cluster) + loffset, ef->fd);
109                 bufp += lsize;
110                 loffset = 0;
111                 remainder -= lsize;
112                 cluster = exfat_next_cluster(ef, node, cluster);
113         }
114         node->mtime = time(NULL);
115         node->flags |= EXFAT_ATTRIB_DIRTY;
116         return size - remainder;
117 }