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