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