1 /* 2 * Copyright 2007-2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "compatibility.h" 7 8 #include "fssh_unistd.h" 9 10 #include <errno.h> 11 #include <stdarg.h> 12 #include <unistd.h> 13 14 #include <SupportDefs.h> 15 16 #include "fssh_drivers.h" 17 #include "fssh_errno.h" 18 #include "partition_support.h" 19 20 #ifdef __BEOS__ 21 # include <Drivers.h> 22 #else 23 # if defined(HAIKU_HOST_PLATFORM_FREEBSD) \ 24 || defined(HAIKU_HOST_PLATFORM_DARWIN) 25 # include <sys/ioctl.h> 26 # include <sys/stat.h> 27 # include <sys/disk.h> 28 # ifndef HAIKU_HOST_PLATFORM_DARWIN 29 # include <sys/disklabel.h> 30 # endif 31 # else 32 // the (POSIX) correct place of definition for ioctl() 33 # include <stropts.h> 34 # endif 35 36 # if defined(HAIKU_HOST_PLATFORM_LINUX) 37 # include <linux/hdreg.h> 38 # include <linux/fs.h> 39 # endif 40 #endif 41 42 43 #ifndef __BEOS__ 44 // Defined in libroot_build.so. 45 extern "C" int _kern_dup(int fd); 46 extern "C" status_t _kern_close(int fd); 47 #endif 48 49 50 #ifdef HAIKU_HOST_PLATFORM_LINUX 51 52 static bool 53 test_size(int fd, off_t size) 54 { 55 char buffer[1]; 56 57 if (size == 0) 58 return true; 59 60 if (lseek(fd, size - 1, SEEK_SET) < 0) 61 return false; 62 63 return (read(fd, &buffer, 1) == 1); 64 } 65 66 67 static off_t 68 get_partition_size(int fd, off_t maxSize) 69 { 70 // binary search 71 off_t lower = 0; 72 off_t upper = maxSize; 73 while (lower < upper) { 74 off_t mid = (lower + upper + 1) / 2; 75 if (test_size(fd, mid)) 76 lower = mid; 77 else 78 upper = mid - 1; 79 } 80 81 return lower; 82 } 83 84 #endif // HAIKU_HOST_PLATFORM_LINUX 85 86 87 int 88 fssh_dup(int fd) 89 { 90 // Use the _kern_dup() defined in libroot on BeOS incompatible systems. 91 // Required for proper attribute emulation support. 92 int newFD; 93 #if __BEOS__ 94 newFD = dup(fd); 95 #else 96 newFD = _kern_dup(fd); 97 if (newFD < 0) { 98 fssh_set_errno(newFD); 99 newFD = -1; 100 } 101 #endif 102 103 FSShell::restricted_file_duped(fd, newFD); 104 105 return newFD; 106 } 107 108 109 int 110 fssh_close(int fd) 111 { 112 FSShell::restricted_file_closed(fd); 113 114 // Use the _kern_close() defined in libroot on BeOS incompatible systems. 115 // Required for proper attribute emulation support. 116 #if __BEOS__ 117 return close(fd); 118 #else 119 return _kern_close(fd); 120 #endif 121 } 122 123 124 int 125 fssh_unlink(const char *name) 126 { 127 return unlink(name); 128 } 129 130 131 int 132 fssh_ioctl(int fd, unsigned long op, ...) 133 { 134 status_t error = B_BAD_VALUE; 135 va_list list; 136 137 // count arguments 138 139 va_start(list, op); 140 141 switch (op) { 142 case FSSH_B_GET_GEOMETRY: 143 { 144 fssh_device_geometry *geometry 145 = va_arg(list, fssh_device_geometry*); 146 147 #ifdef __BEOS__ 148 device_geometry systemGeometry; 149 if (ioctl(fd, B_GET_GEOMETRY, &systemGeometry) == 0) { 150 geometry->bytes_per_sector 151 = systemGeometry.bytes_per_sector; 152 geometry->sectors_per_track 153 = systemGeometry.sectors_per_track; 154 geometry->cylinder_count = systemGeometry.cylinder_count; 155 geometry->head_count = systemGeometry.head_count; 156 geometry->device_type = systemGeometry.device_type; 157 geometry->removable = systemGeometry.removable; 158 geometry->read_only = systemGeometry.read_only; 159 geometry->write_once = systemGeometry.write_once; 160 error = B_OK; 161 } else 162 error = errno; 163 164 #elif defined(HAIKU_HOST_PLATFORM_LINUX) 165 struct hd_geometry hdGeometry; 166 // BLKGETSIZE and BLKGETSIZE64 don't seem to work for 167 // partitions. So we get the device geometry (there only seems 168 // to be HDIO_GETGEO, which is kind of obsolete, BTW), and 169 // get the partition size via binary search. 170 if (ioctl(fd, HDIO_GETGEO, &hdGeometry) == 0) { 171 int blockSize = 512; 172 if (hdGeometry.heads == 0) { 173 off_t size; 174 if (ioctl(fd, BLKGETSIZE64, &size) == 0) { 175 off_t blocks = size / blockSize; 176 uint32_t heads = (blocks + ULONG_MAX - 1) 177 / ULONG_MAX; 178 if (heads == 0) 179 heads = 1; 180 181 geometry->head_count = heads; 182 geometry->cylinder_count = blocks / heads; 183 geometry->sectors_per_track = 1; 184 error = B_OK; 185 } else 186 error = errno; 187 } else { 188 off_t bytesPerCylinder = (off_t)hdGeometry.heads 189 * hdGeometry.sectors * 512; 190 off_t deviceSize = bytesPerCylinder * hdGeometry.cylinders; 191 off_t partitionSize = get_partition_size(fd, deviceSize); 192 193 geometry->head_count = hdGeometry.heads; 194 geometry->cylinder_count = partitionSize / bytesPerCylinder; 195 geometry->sectors_per_track = hdGeometry.sectors; 196 error = B_OK; 197 } 198 199 if (error == B_OK) { 200 // TODO: Get the real values... 201 geometry->bytes_per_sector = blockSize; 202 geometry->device_type = FSSH_B_DISK; 203 geometry->removable = false; 204 geometry->read_only = false; 205 geometry->write_once = false; 206 } 207 } else 208 error = errno; 209 210 #elif HAIKU_HOST_PLATFORM_FREEBSD 211 { 212 // FreeBSD has not block devices 213 214 struct stat status; 215 216 if (fstat(fd, &status) == 0) { 217 // Do nothing for a regular file 218 if (S_ISREG(status.st_mode)) 219 break; 220 221 struct disklabel disklabel; 222 off_t mediaSize; 223 224 memset(&disklabel,0,sizeof disklabel); 225 226 // Ignore errors, this way we can use memory devices (md%d) 227 ioctl(fd, DIOCGSECTORSIZE, &disklabel.d_secsize); 228 ioctl(fd, DIOCGFWSECTORS, &disklabel.d_nsectors); 229 ioctl(fd, DIOCGFWHEADS, &disklabel.d_ntracks); 230 ioctl(fd, DIOCGMEDIASIZE, &mediaSize); 231 232 if (disklabel.d_nsectors == 0) { 233 // Seems to be a md device, then ioctls returns lots of 234 // zeroes and hardcode some defaults 235 disklabel.d_nsectors = 64; 236 disklabel.d_ntracks = 16; 237 } 238 239 disklabel.d_secperunit = mediaSize / disklabel.d_secsize; 240 disklabel.d_ncylinders = mediaSize / disklabel.d_secsize 241 / disklabel.d_nsectors 242 / disklabel.d_ntracks; 243 244 geometry->head_count = disklabel.d_ntracks; 245 geometry->cylinder_count = disklabel.d_ncylinders; 246 geometry->sectors_per_track = disklabel.d_nsectors; 247 248 geometry->bytes_per_sector = disklabel.d_secsize; 249 // FreeBSD supports device_type flag as disklabel.d_type, 250 // for now we harcod it to B_DISK. 251 geometry->device_type = FSSH_B_DISK; 252 geometry->removable = disklabel.d_flags & D_REMOVABLE > 0; 253 // read_only? 254 geometry->read_only = false; 255 // FreeBSD does not support write_once flag. 256 geometry->write_once = false; 257 error = B_OK; 258 } else 259 error = errno; 260 } 261 #else 262 // Not implemented for this platform, i.e. we won't be able to 263 // deal with disk devices. 264 #endif 265 266 break; 267 } 268 269 case FSSH_B_FLUSH_DRIVE_CACHE: 270 { 271 #ifdef __BEOS__ 272 if (ioctl(fd, B_FLUSH_DRIVE_CACHE) == 0) 273 error = B_OK; 274 else 275 error = errno; 276 #else 277 error = B_OK; 278 #endif 279 280 break; 281 } 282 283 case 10000: // IOCTL_FILE_UNCACHED_IO 284 { 285 #ifdef __BEOS__ 286 if (ioctl(fd, 10000) == 0) 287 error = B_OK; 288 else 289 error = errno; 290 #else 291 error = B_OK; 292 #endif 293 294 break; 295 } 296 } 297 298 va_end(list); 299 300 if (error != B_OK) { 301 fssh_set_errno(error); 302 return -1; 303 } 304 return 0; 305 } 306 307 308 fssh_ssize_t 309 fssh_read(int fd, void *buffer, fssh_size_t count) 310 { 311 #if !defined(HAIKU_HOST_PLATFORM_FREEBSD) 312 fssh_off_t pos = -1; 313 if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0) 314 return -1; 315 return read(fd, buffer, count); 316 #else 317 fssh_ssize_t bytesRead = read_pos(fd, fssh_lseek(fd, 0, FSSH_SEEK_CUR), 318 buffer, count); 319 if (bytesRead > 0) 320 fssh_lseek(fd, bytesRead, FSSH_SEEK_CUR); 321 return bytesRead; 322 #endif 323 } 324 325 326 fssh_ssize_t 327 fssh_read_pos(int fd, fssh_off_t pos, void *buffer, fssh_size_t count) 328 { 329 if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0) 330 return -1; 331 return read_pos(fd, pos, buffer, count); 332 } 333 334 335 fssh_ssize_t 336 fssh_write(int fd, const void *buffer, fssh_size_t count) 337 { 338 #if !defined(HAIKU_HOST_PLATFORM_FREEBSD) 339 fssh_off_t pos = -1; 340 if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0) 341 return -1; 342 return write(fd, buffer, count); 343 #else 344 fssh_ssize_t written = write_pos(fd, fssh_lseek(fd, 0, FSSH_SEEK_CUR), 345 buffer, count); 346 if (written > 0) 347 fssh_lseek(fd, written, FSSH_SEEK_CUR); 348 return written; 349 #endif 350 } 351 352 353 fssh_ssize_t 354 fssh_write_pos(int fd, fssh_off_t pos, const void *buffer, fssh_size_t count) 355 { 356 if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0) 357 return -1; 358 return write_pos(fd, pos, buffer, count); 359 } 360 361 362 // fssh_lseek() -- implemented in partition_support.cpp 363 364 365 fssh_gid_t 366 fssh_getegid(void) 367 { 368 return 0; 369 } 370 371 372 fssh_uid_t 373 fssh_geteuid(void) 374 { 375 return 0; 376 } 377 378 379 fssh_gid_t 380 fssh_getgid(void) 381 { 382 return 0; 383 } 384 385 386 #if 0 387 int 388 fssh_getgroups(int groupSize, fssh_gid_t groupList[]) 389 { 390 } 391 #endif // 0 392 393 394 fssh_uid_t 395 fssh_getuid(void) 396 { 397 return 0; 398 } 399