2 * Copyright 2008, Samuel Rodriguez Perez, samuelgaliza@gmail.com.
3 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
8 #include "fs_freebsd.h"
16 #include <sys/ioctl.h>
22 // Read and write operations in FreeBSD only work on devices block by block.
25 haiku_freebsd_read(int fd
, void *buf
, size_t nbytes
)
28 if (fstat(fd
, &st
) != 0)
31 if (S_ISREG(st
.st_mode
))
32 return read(fd
, buf
, nbytes
); // Is a file! Good :)
35 if (ioctl(fd
, DIOCGSECTORSIZE
, §orSize
) == -1)
36 sectorSize
= 512; // If fail, hardcode to 512 for now
38 off_t cur
= lseek(fd
, 0, SEEK_CUR
);
42 off_t seekDiff
= (sectorSize
- (cur
% sectorSize
)) % sectorSize
;
43 off_t nbytesDiff
= (nbytes
- seekDiff
) % sectorSize
;
45 if (seekDiff
== 0 && nbytesDiff
== 0) {
46 // Not needed but this saves malloc and free operations
47 return read(fd
, buf
, nbytes
);
48 } else if (cur
% sectorSize
+ nbytes
<= sectorSize
) {
49 // Read complete in only a block
50 char* tmpBlock
= (char*)malloc(sectorSize
);
52 // Put at start of the block
53 off_t sdCur
= lseek(fd
, -(cur
% sectorSize
), SEEK_CUR
);
55 perror("lseek oneblock");
57 if (read(fd
, tmpBlock
, sectorSize
) == -1)
58 perror("read oneblock");
60 memcpy((char*)buf
, tmpBlock
+ cur
% sectorSize
, nbytes
);
62 // repos at byte offset of latest wrote block
63 if (lseek(fd
, -sectorSize
+ (cur
% sectorSize
) + nbytes
, SEEK_CUR
)
65 perror("lseek2 oneblock");
72 // Needs to write more than a block
74 char* tmpBlock
= (char*)malloc(sectorSize
);
76 // First block if seek isn't
78 // read entire block at 0 pos
79 if (lseek(fd
, -(sectorSize
- seekDiff
), SEEK_CUR
) == -1)
80 perror("lseek seekDiff");
82 off_t sdCur
= lseek(fd
,0,SEEK_CUR
);
84 perror("lseek2 seekDiff");
86 if (read(fd
, tmpBlock
, sectorSize
) == -1 )
87 perror("read seekDiff");
90 memcpy(buf
, tmpBlock
+ (sectorSize
- seekDiff
), seekDiff
);
94 if ((nbytes
- seekDiff
) >= sectorSize
) {
95 if (read(fd
, ((char*)buf
) + seekDiff
, nbytes
- seekDiff
96 - nbytesDiff
) == -1) {
97 perror("read between");
101 // Last block if overflow
102 if (nbytesDiff
> 0 ) {
103 off_t sdCur
= lseek(fd
, 0, SEEK_CUR
);
105 perror("lseek last");
107 if (read(fd
, tmpBlock
, sectorSize
) == -1)
110 memcpy(((char*)buf
) + nbytes
- nbytesDiff
, tmpBlock
, nbytesDiff
);
112 // repos at byte offset of latest wrote block
113 if (lseek(fd
, -(sectorSize
- nbytesDiff
), SEEK_CUR
) == -1)
114 perror("lseek2 last");
125 haiku_freebsd_write(int fd
, const void *buf
, size_t nbytes
)
128 if (fstat(fd
, &st
) != 0)
131 if (S_ISREG(st
.st_mode
))
132 return write(fd
, buf
, nbytes
); // Is a file! Good :)
135 if (ioctl(fd
, DIOCGSECTORSIZE
, §orSize
) == -1)
136 sectorSize
= 512; // If fail, hardcode do 512 for now
138 off_t cur
= lseek(fd
, 0, SEEK_CUR
);
142 off_t seekDiff
= (sectorSize
- (cur
% sectorSize
)) % sectorSize
;
143 off_t nbytesDiff
= (nbytes
- seekDiff
) % sectorSize
;
145 if (seekDiff
== 0 && nbytesDiff
== 0) {
146 // Not needed but this saves malloc and free operations
147 return write(fd
, buf
, nbytes
);
148 } else if (cur
% sectorSize
+ nbytes
<= sectorSize
) {
149 // Write complete in only a block
150 char* tmpBlock
= (char*)malloc(sectorSize
);
152 // Put at start of the block
153 off_t sdCur
= lseek(fd
, -(cur
% sectorSize
), SEEK_CUR
);
155 perror("lseek oneblock");
157 if (pread(fd
, tmpBlock
, sectorSize
, sdCur
) == -1)
158 perror("pread oneblock");
160 memcpy(tmpBlock
+ cur
% sectorSize
, (char*)buf
, nbytes
);
161 if (write(fd
, tmpBlock
, sectorSize
) == -1)
162 perror("write oneblock");
164 // repos at byte offset of latest written block
165 if (lseek(fd
, -sectorSize
+ (cur
% sectorSize
) + nbytes
, SEEK_CUR
)
167 perror("lseek2 oneblock");
174 // Needs to write more than a block
176 char* tmpBlock
= (char*)malloc(sectorSize
);
178 // First block if seek isn't
180 // read entire block at 0 pos
181 if (lseek(fd
, -(sectorSize
- seekDiff
), SEEK_CUR
) == -1)
182 perror("lseek seekDiff");
184 off_t sdCur
= lseek(fd
, 0, SEEK_CUR
);
186 perror("lseek2 seekDiff");
188 if (pread(fd
, tmpBlock
, sectorSize
, sdCur
) == -1)
189 perror("pread seekDiff");
192 memcpy(tmpBlock
+ (sectorSize
- seekDiff
), buf
, seekDiff
);
193 if (write(fd
, tmpBlock
, sectorSize
) == -1)
194 perror("write seekDiff");
198 if ((nbytes
- seekDiff
) >= sectorSize
) {
199 if (write(fd
, ((char*)buf
) + seekDiff
, nbytes
- seekDiff
200 - nbytesDiff
) == -1) {
201 perror("write between");
205 // Last block if overflow
206 if (nbytesDiff
> 0) {
207 off_t sdCur
= lseek(fd
, 0, SEEK_CUR
);
209 perror("lseek last");
211 if (pread(fd
, tmpBlock
, sectorSize
, sdCur
) == -1)
212 perror("pread last");
214 memcpy(tmpBlock
, ((char*)buf
) + nbytes
- nbytesDiff
, nbytesDiff
);
215 if (write(fd
, tmpBlock
, sectorSize
) == -1)
216 perror("write last");
218 // repos at byte offset of latest wrote block
219 if (lseek(fd
, -(sectorSize
- nbytesDiff
), SEEK_CUR
) == -1)
220 perror("lseek2 last");
231 haiku_freebsd_readv(int fd
, const struct iovec
*vecs
, size_t count
)
233 ssize_t bytesRead
= 0;
235 for (size_t i
= 0; i
< count
; i
++) {
236 ssize_t currentRead
= haiku_freebsd_read(fd
, vecs
[i
].iov_base
,
240 return bytesRead
> 0 ? bytesRead
: -1;
242 bytesRead
+= currentRead
;
244 if ((size_t)currentRead
!= vecs
[i
].iov_len
)
253 haiku_freebsd_writev(int fd
, const struct iovec
*vecs
, size_t count
)
255 ssize_t bytesWritten
= 0;
257 for (size_t i
= 0; i
< count
; i
++) {
258 ssize_t written
= haiku_freebsd_write(fd
, vecs
[i
].iov_base
,
262 return bytesWritten
> 0 ? bytesWritten
: -1;
264 bytesWritten
+= written
;
266 if ((size_t)written
!= vecs
[i
].iov_len
)