OSDN Git Service

Implemented existing files writing in libexfat.
[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 <sys/types.h>
12 #include <sys/uio.h>
13 #define __USE_UNIX98 /* for pread() in Linux */
14 #include <unistd.h>
15
16 #if _FILE_OFFSET_BITS != 64
17         #error You should define _FILE_OFFSET_BITS=64
18 #endif
19
20 void exfat_read_raw(void* buffer, size_t size, off_t offset, int fd)
21 {
22         if (pread(fd, buffer, size, offset) != size)
23                 exfat_bug("failed to read %zu bytes from file at %llu", size, offset);
24 }
25
26 void exfat_write_raw(const void* buffer, size_t size, off_t offset, int fd)
27 {
28         if (pwrite(fd, buffer, size, offset) != size)
29                 exfat_bug("failed to write %zu bytes to file at %llu", size, offset);
30 }
31
32 ssize_t exfat_read(const struct exfat* ef, const struct exfat_node* node,
33                 void* buffer, size_t size, off_t offset)
34 {
35         cluster_t cluster;
36         char* bufp = buffer;
37         off_t lsize, loffset, remainder;
38
39         if (offset >= node->size)
40                 return 0;
41         if (size == 0)
42                 return 0;
43
44         cluster = exfat_advance_cluster(ef, node, node->start_cluster,
45                         offset / CLUSTER_SIZE(*ef->sb));
46         if (CLUSTER_INVALID(cluster))
47         {
48                 exfat_error("got invalid cluster");
49                 return -1;
50         }
51
52         loffset = offset % CLUSTER_SIZE(*ef->sb);
53         remainder = MIN(size, node->size - offset);
54         while (remainder > 0)
55         {
56                 if (CLUSTER_INVALID(cluster))
57                 {
58                         exfat_error("got invalid cluster");
59                         return -1;
60                 }
61                 lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
62                 exfat_read_raw(bufp, lsize, exfat_c2o(ef, cluster) + loffset, ef->fd);
63                 bufp += lsize;
64                 loffset = 0;
65                 remainder -= lsize;
66                 cluster = exfat_next_cluster(ef, node, cluster);
67         }
68         return size - remainder;
69 }
70
71 ssize_t exfat_write(struct exfat* ef, struct exfat_node* node,
72                 const void* buffer, size_t size, off_t offset)
73 {
74         cluster_t cluster;
75         const char* bufp = buffer;
76         off_t lsize, loffset, remainder;
77
78         if (offset + size > node->size)
79                 exfat_truncate(ef, node, offset + size);
80         if (size == 0)
81                 return 0;
82
83         cluster = exfat_advance_cluster(ef, node, node->start_cluster,
84                         offset / CLUSTER_SIZE(*ef->sb));
85         if (CLUSTER_INVALID(cluster))
86         {
87                 exfat_error("got invalid cluster");
88                 return -1;
89         }
90
91         loffset = offset % CLUSTER_SIZE(*ef->sb);
92         remainder = size;
93         while (remainder > 0)
94         {
95                 if (CLUSTER_INVALID(cluster))
96                 {
97                         exfat_error("got invalid cluster");
98                         return -1;
99                 }
100                 lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
101                 exfat_write_raw(bufp, lsize, exfat_c2o(ef, cluster) + loffset, ef->fd);
102                 bufp += lsize;
103                 loffset = 0;
104                 remainder -= lsize;
105                 cluster = exfat_next_cluster(ef, node, cluster);
106         }
107         /* FIXME update modification time */
108         /* FIXME no need to flush immediately */
109         exfat_flush_node(ef, node);
110         return size - remainder;
111 }