xref: /haiku/src/build/libroot/fs_freebsd.cpp (revision 25a7b01d15612846f332751841da3579db313082)
1*19a18af3SJohn Scipione /*
2*19a18af3SJohn Scipione  * Copyright 2008, Samuel Rodriguez Perez, samuelgaliza@gmail.com.
3*19a18af3SJohn Scipione  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
4*19a18af3SJohn Scipione  * Distributed under the terms of the MIT License.
5*19a18af3SJohn Scipione  */
6*19a18af3SJohn Scipione 
7*19a18af3SJohn Scipione 
8*19a18af3SJohn Scipione #include "fs_freebsd.h"
9*19a18af3SJohn Scipione 
10*19a18af3SJohn Scipione #include <errno.h>
11*19a18af3SJohn Scipione #include <fcntl.h>
12*19a18af3SJohn Scipione #include <stdio.h>
13*19a18af3SJohn Scipione #include <stdlib.h>
14*19a18af3SJohn Scipione #include <string.h>
15*19a18af3SJohn Scipione #include <sys/disk.h>
16*19a18af3SJohn Scipione #include <sys/ioctl.h>
17*19a18af3SJohn Scipione #include <sys/stat.h>
18*19a18af3SJohn Scipione #include <sys/time.h>
19*19a18af3SJohn Scipione #include <unistd.h>
20*19a18af3SJohn Scipione 
21*19a18af3SJohn Scipione 
22*19a18af3SJohn Scipione // Read and write operations in FreeBSD only work on devices block by block.
23*19a18af3SJohn Scipione 
24*19a18af3SJohn Scipione ssize_t
haiku_freebsd_read(int fd,void * buf,size_t nbytes)25*19a18af3SJohn Scipione haiku_freebsd_read(int fd, void *buf, size_t nbytes)
26*19a18af3SJohn Scipione {
27*19a18af3SJohn Scipione 	struct stat st;
28*19a18af3SJohn Scipione 	if (fstat(fd, &st) != 0)
29*19a18af3SJohn Scipione 		return -1;
30*19a18af3SJohn Scipione 
31*19a18af3SJohn Scipione 	if (S_ISREG(st.st_mode))
32*19a18af3SJohn Scipione 		return read(fd, buf, nbytes); // Is a file! Good :)
33*19a18af3SJohn Scipione 
34*19a18af3SJohn Scipione 	uint sectorSize;
35*19a18af3SJohn Scipione 	if (ioctl(fd, DIOCGSECTORSIZE, &sectorSize) == -1)
36*19a18af3SJohn Scipione 		sectorSize = 512; // If fail, hardcode to 512 for now
37*19a18af3SJohn Scipione 
38*19a18af3SJohn Scipione 	off_t cur = lseek(fd, 0, SEEK_CUR);
39*19a18af3SJohn Scipione 	if (cur == -1)
40*19a18af3SJohn Scipione 		perror("lseek 1");
41*19a18af3SJohn Scipione 
42*19a18af3SJohn Scipione 	off_t seekDiff = (sectorSize - (cur % sectorSize)) % sectorSize;
43*19a18af3SJohn Scipione 	off_t nbytesDiff = (nbytes - seekDiff) % sectorSize;
44*19a18af3SJohn Scipione 
45*19a18af3SJohn Scipione 	if (seekDiff == 0 && nbytesDiff == 0) {
46*19a18af3SJohn Scipione 		// Not needed but this saves malloc and free operations
47*19a18af3SJohn Scipione 		return read(fd, buf, nbytes);
48*19a18af3SJohn Scipione 	} else if (cur % sectorSize + nbytes <= sectorSize) {
49*19a18af3SJohn Scipione 		// Read complete in only a block
50*19a18af3SJohn Scipione 		char* tmpBlock = (char*)malloc(sectorSize);
51*19a18af3SJohn Scipione 
52*19a18af3SJohn Scipione 		// Put at start of the block
53*19a18af3SJohn Scipione 		off_t sdCur = lseek(fd, -(cur % sectorSize), SEEK_CUR);
54*19a18af3SJohn Scipione 		if (sdCur == -1)
55*19a18af3SJohn Scipione 			perror("lseek oneblock");
56*19a18af3SJohn Scipione 
57*19a18af3SJohn Scipione 		if (read(fd, tmpBlock, sectorSize) == -1)
58*19a18af3SJohn Scipione 			perror("read oneblock");
59*19a18af3SJohn Scipione 
60*19a18af3SJohn Scipione 		memcpy((char*)buf, tmpBlock + cur % sectorSize, nbytes);
61*19a18af3SJohn Scipione 
62*19a18af3SJohn Scipione 		// repos at byte offset of latest wrote block
63*19a18af3SJohn Scipione 		if (lseek(fd, -sectorSize + (cur % sectorSize) + nbytes, SEEK_CUR)
64*19a18af3SJohn Scipione 				== -1) {
65*19a18af3SJohn Scipione 			perror("lseek2 oneblock");
66*19a18af3SJohn Scipione 		}
67*19a18af3SJohn Scipione 
68*19a18af3SJohn Scipione 		free(tmpBlock);
69*19a18af3SJohn Scipione 
70*19a18af3SJohn Scipione 		return nbytes;
71*19a18af3SJohn Scipione 	} else {
72*19a18af3SJohn Scipione 		// Needs to write more than a block
73*19a18af3SJohn Scipione 
74*19a18af3SJohn Scipione 		char* tmpBlock = (char*)malloc(sectorSize);
75*19a18af3SJohn Scipione 
76*19a18af3SJohn Scipione 		// First block if seek isn't
77*19a18af3SJohn Scipione 		if (seekDiff > 0) {
78*19a18af3SJohn Scipione 			// read entire block at 0 pos
79*19a18af3SJohn Scipione 			if (lseek(fd, -(sectorSize - seekDiff), SEEK_CUR) == -1)
80*19a18af3SJohn Scipione 				perror("lseek seekDiff");
81*19a18af3SJohn Scipione 
82*19a18af3SJohn Scipione 			off_t sdCur = lseek(fd,0,SEEK_CUR);
83*19a18af3SJohn Scipione 			if (sdCur == -1)
84*19a18af3SJohn Scipione 				perror("lseek2 seekDiff");
85*19a18af3SJohn Scipione 
86*19a18af3SJohn Scipione 			if (read(fd, tmpBlock, sectorSize) == -1 )
87*19a18af3SJohn Scipione 				perror("read seekDiff");
88*19a18af3SJohn Scipione 
89*19a18af3SJohn Scipione 			// alter content
90*19a18af3SJohn Scipione 			memcpy(buf, tmpBlock + (sectorSize - seekDiff), seekDiff);
91*19a18af3SJohn Scipione 		}
92*19a18af3SJohn Scipione 
93*19a18af3SJohn Scipione 		// Blocks between
94*19a18af3SJohn Scipione 		if ((nbytes - seekDiff) >= sectorSize) {
95*19a18af3SJohn Scipione 			if (read(fd, ((char*)buf) + seekDiff, nbytes - seekDiff
96*19a18af3SJohn Scipione 					- nbytesDiff) == -1) {
97*19a18af3SJohn Scipione 				perror("read between");
98*19a18af3SJohn Scipione 			}
99*19a18af3SJohn Scipione 		}
100*19a18af3SJohn Scipione 
101*19a18af3SJohn Scipione 		// Last block if overflow
102*19a18af3SJohn Scipione 		if (nbytesDiff > 0 ) {
103*19a18af3SJohn Scipione 			off_t sdCur = lseek(fd, 0, SEEK_CUR);
104*19a18af3SJohn Scipione 			if (sdCur == -1)
105*19a18af3SJohn Scipione 				perror("lseek last");
106*19a18af3SJohn Scipione 
107*19a18af3SJohn Scipione 			if (read(fd, tmpBlock, sectorSize) == -1)
108*19a18af3SJohn Scipione 				perror("read last");
109*19a18af3SJohn Scipione 
110*19a18af3SJohn Scipione 			memcpy(((char*)buf) + nbytes - nbytesDiff, tmpBlock, nbytesDiff);
111*19a18af3SJohn Scipione 
112*19a18af3SJohn Scipione 			// repos at byte offset of latest wrote block
113*19a18af3SJohn Scipione 			if (lseek(fd, -(sectorSize - nbytesDiff), SEEK_CUR) == -1)
114*19a18af3SJohn Scipione 				perror("lseek2 last");
115*19a18af3SJohn Scipione 		}
116*19a18af3SJohn Scipione 
117*19a18af3SJohn Scipione 		free(tmpBlock);
118*19a18af3SJohn Scipione 
119*19a18af3SJohn Scipione 		return nbytes;
120*19a18af3SJohn Scipione 	}
121*19a18af3SJohn Scipione }
122*19a18af3SJohn Scipione 
123*19a18af3SJohn Scipione 
124*19a18af3SJohn Scipione ssize_t
haiku_freebsd_write(int fd,const void * buf,size_t nbytes)125*19a18af3SJohn Scipione haiku_freebsd_write(int fd, const void *buf, size_t nbytes)
126*19a18af3SJohn Scipione {
127*19a18af3SJohn Scipione 	struct stat st;
128*19a18af3SJohn Scipione 	if (fstat(fd, &st) != 0)
129*19a18af3SJohn Scipione 		return -1;
130*19a18af3SJohn Scipione 
131*19a18af3SJohn Scipione 	if (S_ISREG(st.st_mode))
132*19a18af3SJohn Scipione 		return write(fd, buf, nbytes); // Is a file! Good :)
133*19a18af3SJohn Scipione 
134*19a18af3SJohn Scipione 	uint sectorSize;
135*19a18af3SJohn Scipione 	if (ioctl(fd, DIOCGSECTORSIZE, &sectorSize) == -1)
136*19a18af3SJohn Scipione 		sectorSize = 512; // If fail, hardcode do 512 for now
137*19a18af3SJohn Scipione 
138*19a18af3SJohn Scipione 	off_t cur = lseek(fd, 0, SEEK_CUR);
139*19a18af3SJohn Scipione 	if (cur == -1)
140*19a18af3SJohn Scipione 		perror("lseek 1");
141*19a18af3SJohn Scipione 
142*19a18af3SJohn Scipione 	off_t seekDiff = (sectorSize - (cur % sectorSize)) % sectorSize;
143*19a18af3SJohn Scipione 	off_t nbytesDiff = (nbytes - seekDiff) % sectorSize;
144*19a18af3SJohn Scipione 
145*19a18af3SJohn Scipione 	if (seekDiff == 0 && nbytesDiff == 0) {
146*19a18af3SJohn Scipione 		// Not needed but this saves malloc and free operations
147*19a18af3SJohn Scipione 		return write(fd, buf, nbytes);
148*19a18af3SJohn Scipione 	} else if (cur % sectorSize + nbytes <= sectorSize) {
149*19a18af3SJohn Scipione 		// Write complete in only a block
150*19a18af3SJohn Scipione 		char* tmpBlock = (char*)malloc(sectorSize);
151*19a18af3SJohn Scipione 
152*19a18af3SJohn Scipione 		// Put at start of the block
153*19a18af3SJohn Scipione 		off_t sdCur = lseek(fd, -(cur % sectorSize), SEEK_CUR);
154*19a18af3SJohn Scipione 		if (sdCur == -1)
155*19a18af3SJohn Scipione 			perror("lseek oneblock");
156*19a18af3SJohn Scipione 
157*19a18af3SJohn Scipione 		if (pread(fd, tmpBlock, sectorSize, sdCur) == -1)
158*19a18af3SJohn Scipione 			perror("pread oneblock");
159*19a18af3SJohn Scipione 
160*19a18af3SJohn Scipione 		memcpy(tmpBlock + cur % sectorSize, (char*)buf, nbytes);
161*19a18af3SJohn Scipione 		if (write(fd, tmpBlock, sectorSize) == -1)
162*19a18af3SJohn Scipione 			perror("write oneblock");
163*19a18af3SJohn Scipione 
164*19a18af3SJohn Scipione 		// repos at byte offset of latest written block
165*19a18af3SJohn Scipione 		if (lseek(fd, -sectorSize + (cur % sectorSize) + nbytes, SEEK_CUR)
166*19a18af3SJohn Scipione 				== -1) {
167*19a18af3SJohn Scipione 			perror("lseek2 oneblock");
168*19a18af3SJohn Scipione 		}
169*19a18af3SJohn Scipione 
170*19a18af3SJohn Scipione 		free(tmpBlock);
171*19a18af3SJohn Scipione 
172*19a18af3SJohn Scipione 		return nbytes;
173*19a18af3SJohn Scipione 	} else {
174*19a18af3SJohn Scipione 		// Needs to write more than a block
175*19a18af3SJohn Scipione 
176*19a18af3SJohn Scipione 		char* tmpBlock = (char*)malloc(sectorSize);
177*19a18af3SJohn Scipione 
178*19a18af3SJohn Scipione 		// First block if seek isn't
179*19a18af3SJohn Scipione 		if (seekDiff > 0) {
180*19a18af3SJohn Scipione 			// read entire block at 0 pos
181*19a18af3SJohn Scipione 			if (lseek(fd, -(sectorSize - seekDiff), SEEK_CUR) == -1)
182*19a18af3SJohn Scipione 				perror("lseek seekDiff");
183*19a18af3SJohn Scipione 
184*19a18af3SJohn Scipione 			off_t sdCur = lseek(fd, 0, SEEK_CUR);
185*19a18af3SJohn Scipione 			if (sdCur == -1)
186*19a18af3SJohn Scipione 				perror("lseek2 seekDiff");
187*19a18af3SJohn Scipione 
188*19a18af3SJohn Scipione 			if (pread(fd, tmpBlock, sectorSize, sdCur) == -1)
189*19a18af3SJohn Scipione 				perror("pread seekDiff");
190*19a18af3SJohn Scipione 
191*19a18af3SJohn Scipione 			// alter content
192*19a18af3SJohn Scipione 			memcpy(tmpBlock + (sectorSize - seekDiff), buf, seekDiff);
193*19a18af3SJohn Scipione 			if (write(fd, tmpBlock, sectorSize) == -1)
194*19a18af3SJohn Scipione 				perror("write seekDiff");
195*19a18af3SJohn Scipione 		}
196*19a18af3SJohn Scipione 
197*19a18af3SJohn Scipione 		// Blocks between
198*19a18af3SJohn Scipione 		if ((nbytes - seekDiff) >= sectorSize) {
199*19a18af3SJohn Scipione 			if (write(fd, ((char*)buf) + seekDiff, nbytes - seekDiff
200*19a18af3SJohn Scipione 					- nbytesDiff) == -1) {
201*19a18af3SJohn Scipione 				perror("write between");
202*19a18af3SJohn Scipione 			}
203*19a18af3SJohn Scipione 		}
204*19a18af3SJohn Scipione 
205*19a18af3SJohn Scipione 		// Last block if overflow
206*19a18af3SJohn Scipione 		if (nbytesDiff > 0) {
207*19a18af3SJohn Scipione 			off_t sdCur = lseek(fd, 0, SEEK_CUR);
208*19a18af3SJohn Scipione 			if (sdCur == -1)
209*19a18af3SJohn Scipione 				perror("lseek last");
210*19a18af3SJohn Scipione 
211*19a18af3SJohn Scipione 			if (pread(fd, tmpBlock, sectorSize, sdCur) == -1)
212*19a18af3SJohn Scipione 				perror("pread last");
213*19a18af3SJohn Scipione 
214*19a18af3SJohn Scipione 			memcpy(tmpBlock, ((char*)buf) + nbytes - nbytesDiff, nbytesDiff);
215*19a18af3SJohn Scipione 			if (write(fd, tmpBlock, sectorSize) == -1)
216*19a18af3SJohn Scipione 				perror("write last");
217*19a18af3SJohn Scipione 
218*19a18af3SJohn Scipione 			// repos at byte offset of latest wrote block
219*19a18af3SJohn Scipione 			if (lseek(fd, -(sectorSize - nbytesDiff), SEEK_CUR) == -1)
220*19a18af3SJohn Scipione 				perror("lseek2 last");
221*19a18af3SJohn Scipione 		}
222*19a18af3SJohn Scipione 
223*19a18af3SJohn Scipione 		free(tmpBlock);
224*19a18af3SJohn Scipione 
225*19a18af3SJohn Scipione 		return nbytes;
226*19a18af3SJohn Scipione 	}
227*19a18af3SJohn Scipione }
228*19a18af3SJohn Scipione 
229*19a18af3SJohn Scipione 
230*19a18af3SJohn Scipione ssize_t
haiku_freebsd_readv(int fd,const struct iovec * vecs,size_t count)231*19a18af3SJohn Scipione haiku_freebsd_readv(int fd, const struct iovec *vecs, size_t count)
232*19a18af3SJohn Scipione {
233*19a18af3SJohn Scipione 	ssize_t bytesRead = 0;
234*19a18af3SJohn Scipione 
235*19a18af3SJohn Scipione 	for (size_t i = 0; i < count; i++) {
236*19a18af3SJohn Scipione 		ssize_t currentRead = haiku_freebsd_read(fd, vecs[i].iov_base,
237*19a18af3SJohn Scipione 			vecs[i].iov_len);
238*19a18af3SJohn Scipione 
239*19a18af3SJohn Scipione 		if (currentRead < 0)
240*19a18af3SJohn Scipione 			return bytesRead > 0 ? bytesRead : -1;
241*19a18af3SJohn Scipione 
242*19a18af3SJohn Scipione 		bytesRead += currentRead;
243*19a18af3SJohn Scipione 
244*19a18af3SJohn Scipione 		if ((size_t)currentRead != vecs[i].iov_len)
245*19a18af3SJohn Scipione 			break;
246*19a18af3SJohn Scipione 	}
247*19a18af3SJohn Scipione 
248*19a18af3SJohn Scipione 	return bytesRead;
249*19a18af3SJohn Scipione }
250*19a18af3SJohn Scipione 
251*19a18af3SJohn Scipione 
252*19a18af3SJohn Scipione ssize_t
haiku_freebsd_writev(int fd,const struct iovec * vecs,size_t count)253*19a18af3SJohn Scipione haiku_freebsd_writev(int fd, const struct iovec *vecs, size_t count)
254*19a18af3SJohn Scipione {
255*19a18af3SJohn Scipione 	ssize_t bytesWritten = 0;
256*19a18af3SJohn Scipione 
257*19a18af3SJohn Scipione 	for (size_t i = 0; i < count; i++) {
258*19a18af3SJohn Scipione 		ssize_t written = haiku_freebsd_write(fd, vecs[i].iov_base,
259*19a18af3SJohn Scipione 			vecs[i].iov_len);
260*19a18af3SJohn Scipione 
261*19a18af3SJohn Scipione 		if (written < 0)
262*19a18af3SJohn Scipione 			return bytesWritten > 0 ? bytesWritten : -1;
263*19a18af3SJohn Scipione 
264*19a18af3SJohn Scipione 		bytesWritten += written;
265*19a18af3SJohn Scipione 
266*19a18af3SJohn Scipione 		if ((size_t)written != vecs[i].iov_len)
267*19a18af3SJohn Scipione 			break;
268*19a18af3SJohn Scipione 	}
269*19a18af3SJohn Scipione 
270*19a18af3SJohn Scipione 	return bytesWritten;
271*19a18af3SJohn Scipione }
272