OSDN Git Service

Changed source files headings to meet the FSF recommendations.
[android-x86/external-exfat.git] / libexfat / io.c
1 /*
2         io.c (02.09.09)
3         exFAT file system implementation library.
4
5         Copyright (C) 2009, 2010  Andrew Nayenko
6
7         This program is free software: you can redistribute it and/or modify
8         it under the terms of the GNU General Public License as published by
9         the Free Software Foundation, either version 3 of the License, or
10         (at your option) any later version.
11
12         This program is distributed in the hope that it will be useful,
13         but WITHOUT ANY WARRANTY; without even the implied warranty of
14         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15         GNU General Public License for more details.
16
17         You should have received a copy of the GNU General Public License
18         along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "exfat.h"
22 #include <inttypes.h>
23 #include <sys/types.h>
24 #include <sys/uio.h>
25 #define __USE_UNIX98 /* for pread() in Linux */
26 #include <unistd.h>
27
28 #if _FILE_OFFSET_BITS != 64
29         #error You should define _FILE_OFFSET_BITS=64
30 #endif
31
32 void exfat_read_raw(void* buffer, size_t size, off_t offset, int fd)
33 {
34         if (pread(fd, buffer, size, offset) != size)
35                 exfat_bug("failed to read %zu bytes from file at %"PRIu64, size,
36                                 (uint64_t) offset);
37 }
38
39 void exfat_write_raw(const void* buffer, size_t size, off_t offset, int fd)
40 {
41         if (pwrite(fd, buffer, size, offset) != size)
42                 exfat_bug("failed to write %zu bytes to file at %"PRIu64, size,
43                                 (uint64_t) offset);
44 }
45
46 ssize_t exfat_read(const struct exfat* ef, struct exfat_node* node,
47                 void* buffer, size_t size, off_t offset)
48 {
49         cluster_t cluster;
50         char* bufp = buffer;
51         off_t lsize, loffset, remainder;
52
53         if (offset >= node->size)
54                 return 0;
55         if (size == 0)
56                 return 0;
57
58         cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb));
59         if (CLUSTER_INVALID(cluster))
60         {
61                 exfat_error("got invalid cluster");
62                 return -1;
63         }
64
65         loffset = offset % CLUSTER_SIZE(*ef->sb);
66         remainder = MIN(size, node->size - offset);
67         while (remainder > 0)
68         {
69                 if (CLUSTER_INVALID(cluster))
70                 {
71                         exfat_error("got invalid cluster");
72                         return -1;
73                 }
74                 lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
75                 exfat_read_raw(bufp, lsize, exfat_c2o(ef, cluster) + loffset, ef->fd);
76                 bufp += lsize;
77                 loffset = 0;
78                 remainder -= lsize;
79                 cluster = exfat_next_cluster(ef, node, cluster);
80         }
81         if (!ef->ro && !ef->noatime)
82                 exfat_update_atime(node);
83         return size - remainder;
84 }
85
86 ssize_t exfat_write(struct exfat* ef, struct exfat_node* node,
87                 const void* buffer, size_t size, off_t offset)
88 {
89         cluster_t cluster;
90         const char* bufp = buffer;
91         off_t lsize, loffset, remainder;
92
93         if (offset + size > node->size)
94         {
95                 int rc = exfat_truncate(ef, node, offset + size);
96                 if (rc != 0)
97                         return rc;
98         }
99         if (size == 0)
100                 return 0;
101
102         cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb));
103         if (CLUSTER_INVALID(cluster))
104         {
105                 exfat_error("got invalid cluster");
106                 return -1;
107         }
108
109         loffset = offset % CLUSTER_SIZE(*ef->sb);
110         remainder = size;
111         while (remainder > 0)
112         {
113                 if (CLUSTER_INVALID(cluster))
114                 {
115                         exfat_error("got invalid cluster");
116                         return -1;
117                 }
118                 lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
119                 exfat_write_raw(bufp, lsize, exfat_c2o(ef, cluster) + loffset, ef->fd);
120                 bufp += lsize;
121                 loffset = 0;
122                 remainder -= lsize;
123                 cluster = exfat_next_cluster(ef, node, cluster);
124         }
125         exfat_update_mtime(node);
126         return size - remainder;
127 }