1 /* 2 * Copyright 2007, Ingo Weinhold, bonefish@cs.tu-berlin.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 19 #ifdef __BEOS__ 20 # include <Drivers.h> 21 #else 22 # if defined(HAIKU_HOST_PLATFORM_FREEBSD) \ 23 || defined(HAIKU_HOST_PLATFORM_DARWIN) 24 # include <sys/ioctl.h> 25 # else 26 // the (POSIX) correct place of definition for ioctl() 27 # include <stropts.h> 28 # endif 29 30 # if defined(HAIKU_HOST_PLATFORM_LINUX) 31 # include <linux/hdreg.h> 32 # include <linux/fs.h> 33 # endif 34 #endif 35 36 37 #ifndef __BEOS__ 38 // Defined in libroot_build.so. 39 extern "C" int _kern_dup(int fd); 40 extern "C" status_t _kern_close(int fd); 41 #endif 42 43 44 #ifdef HAIKU_HOST_PLATFORM_LINUX 45 46 static bool 47 test_size(int fd, off_t size) 48 { 49 char buffer[1]; 50 51 if (size == 0) 52 return true; 53 54 if (lseek(fd, size - 1, SEEK_SET) < 0) 55 return false; 56 57 return (read(fd, &buffer, 1) == 1); 58 } 59 60 61 static off_t 62 get_partition_size(int fd, off_t maxSize) 63 { 64 // binary search 65 off_t lower = 0; 66 off_t upper = maxSize; 67 while (lower < upper) { 68 off_t mid = (lower + upper + 1) / 2; 69 if (test_size(fd, mid)) 70 lower = mid; 71 else 72 upper = mid - 1; 73 } 74 75 return lower; 76 } 77 78 #endif // HAIKU_HOST_PLATFORM_LINUX 79 80 81 int 82 fssh_dup(int fd) 83 { 84 // Use the _kern_dup() defined in libroot on BeOS incompatible systems. 85 // Required for proper attribute emulation support. 86 #if __BEOS__ 87 return dup(fd); 88 #else 89 int result = _kern_dup(fd); 90 if (result < 0) { 91 fssh_set_errno(result); 92 return -1; 93 } 94 return result; 95 #endif 96 } 97 98 99 int 100 fssh_close(int fd) 101 { 102 // Use the _kern_close() defined in libroot on BeOS incompatible systems. 103 // Required for proper attribute emulation support. 104 #if __BEOS__ 105 return close(fd); 106 #else 107 return _kern_close(fd); 108 #endif 109 } 110 111 112 int 113 fssh_unlink(const char *name) 114 { 115 return unlink(name); 116 } 117 118 119 int 120 fssh_ioctl(int fd, unsigned long op, ...) 121 { 122 status_t error = B_BAD_VALUE; 123 va_list list; 124 125 // count arguments 126 127 va_start(list, op); 128 129 switch (op) { 130 case FSSH_B_GET_GEOMETRY: 131 { 132 fssh_device_geometry *geometry 133 = va_arg(list, fssh_device_geometry*); 134 135 #ifdef __BEOS__ 136 device_geometry systemGeometry; 137 if (ioctl(fd, B_GET_GEOMETRY, &systemGeometry) == 0) { 138 geometry->bytes_per_sector 139 = systemGeometry.bytes_per_sector; 140 geometry->sectors_per_track 141 = systemGeometry.sectors_per_track; 142 geometry->cylinder_count = systemGeometry.cylinder_count; 143 geometry->head_count = systemGeometry.head_count; 144 geometry->device_type = systemGeometry.device_type; 145 geometry->removable = systemGeometry.removable; 146 geometry->read_only = systemGeometry.read_only; 147 geometry->write_once = systemGeometry.write_once; 148 error = B_OK; 149 } else 150 error = errno; 151 152 #elif defined(HAIKU_HOST_PLATFORM_LINUX) 153 struct hd_geometry hdGeometry; 154 // BLKGETSIZE and BLKGETSIZE64 don't seem to work for 155 // partitions. So we get the device geometry (there only seems 156 // to be HDIO_GETGEO, which is kind of obsolete, BTW), and 157 // get the partition size via binary search. 158 if (ioctl(fd, HDIO_GETGEO, &hdGeometry) == 0) { 159 int blockSize = 512; 160 if (hdGeometry.heads == 0) { 161 off_t size; 162 if (ioctl(fd, BLKGETSIZE64, &size) == 0) { 163 off_t blocks = size / blockSize; 164 uint32_t heads = (blocks + ULONG_MAX - 1) 165 / ULONG_MAX; 166 if (heads == 0) 167 heads = 1; 168 169 geometry->head_count = heads; 170 geometry->cylinder_count = blocks / heads; 171 geometry->sectors_per_track = 1; 172 error = B_OK; 173 } else 174 error = errno; 175 } else { 176 off_t bytesPerCylinder = (off_t)hdGeometry.heads 177 * hdGeometry.sectors * 512; 178 off_t deviceSize = bytesPerCylinder * hdGeometry.cylinders; 179 off_t partitionSize = get_partition_size(fd, deviceSize); 180 181 geometry->head_count = hdGeometry.heads; 182 geometry->cylinder_count = partitionSize / bytesPerCylinder; 183 geometry->sectors_per_track = hdGeometry.sectors; 184 error = B_OK; 185 } 186 187 if (error == B_OK) { 188 // TODO: Get the real values... 189 geometry->bytes_per_sector = blockSize; 190 geometry->device_type = FSSH_B_DISK; 191 geometry->removable = false; 192 geometry->read_only = false; 193 geometry->write_once = false; 194 } 195 } else 196 error = errno; 197 198 #else 199 // Not implemented for this platform, i.e. we won't be able to 200 // deal with block devices. 201 #endif 202 203 break; 204 } 205 206 case FSSH_B_FLUSH_DRIVE_CACHE: 207 { 208 #ifdef __BEOS__ 209 if (ioctl(fd, B_FLUSH_DRIVE_CACHE) == 0) 210 error = B_OK; 211 else 212 error = errno; 213 #else 214 error = B_OK; 215 #endif 216 217 break; 218 } 219 220 case 10000: // IOCTL_FILE_UNCACHED_IO 221 { 222 #ifdef __BEOS__ 223 if (ioctl(fd, 10000) == 0) 224 error = B_OK; 225 else 226 error = errno; 227 #else 228 error = B_OK; 229 #endif 230 231 break; 232 } 233 } 234 235 va_end(list); 236 237 if (error != B_OK) { 238 fssh_set_errno(error); 239 return -1; 240 } 241 return 0; 242 } 243 244 245 fssh_ssize_t 246 fssh_read(int fd, void *buffer, fssh_size_t count) 247 { 248 return read(fd, buffer, count); 249 } 250 251 252 fssh_ssize_t 253 fssh_read_pos(int fd, fssh_off_t pos, void *buffer, fssh_size_t count) 254 { 255 return read_pos(fd, pos, buffer, count); 256 } 257 258 259 fssh_ssize_t 260 fssh_write(int fd, const void *buffer, fssh_size_t count) 261 { 262 return write(fd, buffer, count); 263 } 264 265 266 fssh_ssize_t 267 fssh_write_pos(int fd, fssh_off_t pos, const void *buffer, fssh_size_t count) 268 { 269 return write_pos(fd, pos, buffer, count); 270 } 271 272 273 fssh_gid_t 274 fssh_getegid(void) 275 { 276 return 0; 277 } 278 279 280 fssh_uid_t 281 fssh_geteuid(void) 282 { 283 return 0; 284 } 285 286 287 fssh_gid_t 288 fssh_getgid(void) 289 { 290 return 0; 291 } 292 293 294 #if 0 295 int 296 fssh_getgroups(int groupSize, fssh_gid_t groupList[]) 297 { 298 } 299 #endif // 0 300 301 302 fssh_uid_t 303 fssh_getuid(void) 304 { 305 return 0; 306 } 307