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