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