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