1 /* 2 * unix_io.c --- This is the Unix (well, really POSIX) implementation 3 * of the I/O manager. 4 * 5 * Implements a one-block write-through cache. 6 * 7 * Includes support for Windows NT support under Cygwin. 8 * 9 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 10 * 2002 by Theodore Ts'o. 11 * 12 * %Begin-Header% 13 * This file may be redistributed under the terms of the GNU Public 14 * License. 15 * %End-Header% 16 */ 17 18 #define _LARGEFILE_SOURCE 19 #define _LARGEFILE64_SOURCE 20 21 #include <stdio.h> 22 #include <string.h> 23 #if HAVE_UNISTD_H 24 #include <unistd.h> 25 #endif 26 #if HAVE_ERRNO_H 27 #include <errno.h> 28 #endif 29 #include <fcntl.h> 30 #include <time.h> 31 #ifdef __linux__ 32 #include <sys/utsname.h> 33 #endif 34 #ifdef HAVE_SYS_IOCTL_H 35 #include <sys/ioctl.h> 36 #endif 37 #ifdef HAVE_SYS_MOUNT_H 38 #include <sys/mount.h> 39 #endif 40 #if HAVE_SYS_STAT_H 41 #include <sys/stat.h> 42 #endif 43 #if HAVE_SYS_TYPES_H 44 #include <sys/types.h> 45 #endif 46 #if HAVE_SYS_RESOURCE_H 47 #include <sys/resource.h> 48 #endif 49 50 #if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) 51 #define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */ 52 #endif 53 54 #include "ext2_fs.h" 55 #include "ext2fs.h" 56 57 /* 58 * For checking structure magic numbers... 59 */ 60 61 #define EXT2_CHECK_MAGIC(struct, code) \ 62 if ((struct)->magic != (code)) return (code) 63 64 struct unix_cache { 65 char *buf; 66 unsigned long block; 67 int access_time; 68 unsigned dirty:1; 69 unsigned in_use:1; 70 }; 71 72 #define CACHE_SIZE 8 73 #define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */ 74 #define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */ 75 76 struct unix_private_data { 77 int magic; 78 int dev; 79 int flags; 80 int access_time; 81 ext2_loff_t offset; 82 struct unix_cache cache[CACHE_SIZE]; 83 struct struct_io_stats io_stats; 84 }; 85 86 static errcode_t unix_open(const char *name, int flags, io_channel *channel); 87 static errcode_t unix_close(io_channel channel); 88 static errcode_t unix_set_blksize(io_channel channel, int blksize); 89 static errcode_t unix_read_blk(io_channel channel, unsigned long block, 90 int count, void *data); 91 static errcode_t unix_write_blk(io_channel channel, unsigned long block, 92 int count, const void *data); 93 static errcode_t unix_flush(io_channel channel); 94 static errcode_t unix_write_byte(io_channel channel, unsigned long offset, 95 int size, const void *data); 96 static errcode_t unix_set_option(io_channel channel, const char *option, 97 const char *arg); 98 static errcode_t unix_get_stats(io_channel channel, io_stats *stats) 99 ; 100 static void reuse_cache(io_channel channel, struct unix_private_data *data, 101 struct unix_cache *cache, unsigned long long block); 102 static errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 103 int count, void *data); 104 static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 105 int count, const void *data); 106 107 /* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel 108 * does not know buffered block devices - everything is raw. */ 109 #if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 110 #define NEED_BOUNCE_BUFFER 111 #else 112 #undef NEED_BOUNCE_BUFFER 113 #endif 114 115 static struct struct_io_manager struct_unix_manager = { 116 EXT2_ET_MAGIC_IO_MANAGER, 117 "Unix I/O Manager", 118 unix_open, 119 unix_close, 120 unix_set_blksize, 121 unix_read_blk, 122 unix_write_blk, 123 unix_flush, 124 #ifdef NEED_BOUNCE_BUFFER 125 0, 126 #else 127 unix_write_byte, 128 #endif 129 unix_set_option, 130 unix_get_stats, 131 unix_read_blk64, 132 unix_write_blk64, 133 }; 134 135 io_manager unix_io_manager = &struct_unix_manager; 136 137 static errcode_t unix_get_stats(io_channel channel, io_stats *stats) 138 { 139 errcode_t retval = 0; 140 141 struct unix_private_data *data; 142 143 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 144 data = (struct unix_private_data *) channel->private_data; 145 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 146 147 if (stats) 148 *stats = &data->io_stats; 149 150 return retval; 151 } 152 153 /* 154 * Here are the raw I/O functions 155 */ 156 #ifndef NEED_BOUNCE_BUFFER 157 static errcode_t raw_read_blk(io_channel channel, 158 struct unix_private_data *data, 159 unsigned long long block, 160 int count, void *buf) 161 { 162 errcode_t retval; 163 ssize_t size; 164 ext2_loff_t location; 165 int actual = 0; 166 167 size = (count < 0) ? -count : count * channel->block_size; 168 data->io_stats.bytes_read += size; 169 location = ((ext2_loff_t) block * channel->block_size) + data->offset; 170 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 171 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 172 goto error_out; 173 } 174 actual = read(data->dev, buf, size); 175 if (actual != size) { 176 if (actual < 0) 177 actual = 0; 178 retval = EXT2_ET_SHORT_READ; 179 goto error_out; 180 } 181 return 0; 182 183 error_out: 184 memset((char *) buf+actual, 0, size-actual); 185 if (channel->read_error) 186 retval = (channel->read_error)(channel, block, count, buf, 187 size, actual, retval); 188 return retval; 189 } 190 #else /* NEED_BOUNCE_BUFFER */ 191 /* 192 * Windows and FreeBSD block devices only allow sector alignment IO in offset and size 193 */ 194 static errcode_t raw_read_blk(io_channel channel, 195 struct unix_private_data *data, 196 unsigned long block, 197 int count, void *buf) 198 { 199 errcode_t retval; 200 size_t size, alignsize, fragment; 201 ext2_loff_t location; 202 int total = 0, actual; 203 #define BLOCKALIGN 512 204 char sector[BLOCKALIGN]; 205 206 size = (count < 0) ? -count : count * channel->block_size; 207 data->io_stats.bytes_read += size; 208 location = ((ext2_loff_t) block * channel->block_size) + data->offset; 209 #ifdef DEBUG 210 printf("count=%d, size=%d, block=%lu, blk_size=%d, location=%llx\n", 211 count, size, block, channel->block_size, (long long)location); 212 #endif 213 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 214 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 215 goto error_out; 216 } 217 fragment = size % BLOCKALIGN; 218 alignsize = size - fragment; 219 if (alignsize) { 220 actual = read(data->dev, buf, alignsize); 221 if (actual != alignsize) 222 goto short_read; 223 } 224 if (fragment) { 225 actual = read(data->dev, sector, BLOCKALIGN); 226 if (actual != BLOCKALIGN) 227 goto short_read; 228 memcpy(buf+alignsize, sector, fragment); 229 } 230 return 0; 231 232 short_read: 233 if (actual>0) 234 total += actual; 235 retval = EXT2_ET_SHORT_READ; 236 237 error_out: 238 memset((char *) buf+total, 0, size-actual); 239 if (channel->read_error) 240 retval = (channel->read_error)(channel, block, count, buf, 241 size, actual, retval); 242 return retval; 243 } 244 #endif 245 246 static errcode_t raw_write_blk(io_channel channel, 247 struct unix_private_data *data, 248 unsigned long long block, 249 int count, const void *buf) 250 { 251 ssize_t size; 252 ext2_loff_t location; 253 int actual = 0; 254 errcode_t retval; 255 256 if (count == 1) 257 size = channel->block_size; 258 else { 259 if (count < 0) 260 size = -count; 261 else 262 size = count * channel->block_size; 263 } 264 data->io_stats.bytes_written += size; 265 266 location = ((ext2_loff_t) block * channel->block_size) + data->offset; 267 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 268 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 269 goto error_out; 270 } 271 272 actual = write(data->dev, buf, size); 273 if (actual != size) { 274 retval = EXT2_ET_SHORT_WRITE; 275 goto error_out; 276 } 277 return 0; 278 279 error_out: 280 if (channel->write_error) 281 retval = (channel->write_error)(channel, block, count, buf, 282 size, actual, retval); 283 return retval; 284 } 285 286 287 /* 288 * Here we implement the cache functions 289 */ 290 291 /* Allocate the cache buffers */ 292 static errcode_t alloc_cache(io_channel channel, 293 struct unix_private_data *data) 294 { 295 errcode_t retval; 296 struct unix_cache *cache; 297 int i; 298 299 data->access_time = 0; 300 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 301 cache->block = 0; 302 cache->access_time = 0; 303 cache->dirty = 0; 304 cache->in_use = 0; 305 if ((retval = ext2fs_get_mem(channel->block_size, 306 &cache->buf))) 307 return retval; 308 } 309 return 0; 310 } 311 312 /* Free the cache buffers */ 313 static void free_cache(struct unix_private_data *data) 314 { 315 struct unix_cache *cache; 316 int i; 317 318 data->access_time = 0; 319 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 320 cache->block = 0; 321 cache->access_time = 0; 322 cache->dirty = 0; 323 cache->in_use = 0; 324 if (cache->buf) 325 ext2fs_free_mem(&cache->buf); 326 cache->buf = 0; 327 } 328 } 329 330 #ifndef NO_IO_CACHE 331 /* 332 * Try to find a block in the cache. If the block is not found, and 333 * eldest is a non-zero pointer, then fill in eldest with the cache 334 * entry to that should be reused. 335 */ 336 static struct unix_cache *find_cached_block(struct unix_private_data *data, 337 unsigned long long block, 338 struct unix_cache **eldest) 339 { 340 struct unix_cache *cache, *unused_cache, *oldest_cache; 341 int i; 342 343 unused_cache = oldest_cache = 0; 344 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 345 if (!cache->in_use) { 346 if (!unused_cache) 347 unused_cache = cache; 348 continue; 349 } 350 if (cache->block == block) { 351 cache->access_time = ++data->access_time; 352 return cache; 353 } 354 if (!oldest_cache || 355 (cache->access_time < oldest_cache->access_time)) 356 oldest_cache = cache; 357 } 358 if (eldest) 359 *eldest = (unused_cache) ? unused_cache : oldest_cache; 360 return 0; 361 } 362 363 /* 364 * Reuse a particular cache entry for another block. 365 */ 366 static void reuse_cache(io_channel channel, struct unix_private_data *data, 367 struct unix_cache *cache, unsigned long long block) 368 { 369 if (cache->dirty && cache->in_use) 370 raw_write_blk(channel, data, cache->block, 1, cache->buf); 371 372 cache->in_use = 1; 373 cache->dirty = 0; 374 cache->block = block; 375 cache->access_time = ++data->access_time; 376 } 377 378 /* 379 * Flush all of the blocks in the cache 380 */ 381 static errcode_t flush_cached_blocks(io_channel channel, 382 struct unix_private_data *data, 383 int invalidate) 384 385 { 386 struct unix_cache *cache; 387 errcode_t retval, retval2; 388 int i; 389 390 retval2 = 0; 391 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 392 if (!cache->in_use) 393 continue; 394 395 if (invalidate) 396 cache->in_use = 0; 397 398 if (!cache->dirty) 399 continue; 400 401 retval = raw_write_blk(channel, data, 402 cache->block, 1, cache->buf); 403 if (retval) 404 retval2 = retval; 405 else 406 cache->dirty = 0; 407 } 408 return retval2; 409 } 410 #endif /* NO_IO_CACHE */ 411 412 static errcode_t unix_open(const char *name, int flags, io_channel *channel) 413 { 414 io_channel io = NULL; 415 struct unix_private_data *data = NULL; 416 errcode_t retval; 417 int open_flags; 418 struct stat st; 419 #ifdef __linux__ 420 struct utsname ut; 421 #endif 422 423 if (name == 0) 424 return EXT2_ET_BAD_DEVICE_NAME; 425 retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); 426 if (retval) 427 return retval; 428 memset(io, 0, sizeof(struct struct_io_channel)); 429 io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 430 retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data); 431 if (retval) 432 goto cleanup; 433 434 io->manager = unix_io_manager; 435 retval = ext2fs_get_mem(strlen(name)+1, &io->name); 436 if (retval) 437 goto cleanup; 438 439 strcpy(io->name, name); 440 io->private_data = data; 441 io->block_size = 1024; 442 io->read_error = 0; 443 io->write_error = 0; 444 io->refcount = 1; 445 446 memset(data, 0, sizeof(struct unix_private_data)); 447 data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; 448 data->io_stats.num_fields = 2; 449 450 if ((retval = alloc_cache(io, data))) 451 goto cleanup; 452 453 open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; 454 if (flags & IO_FLAG_EXCLUSIVE) 455 open_flags |= O_EXCL; 456 #ifdef HAVE_OPEN64 457 data->dev = open64(io->name, open_flags); 458 #else 459 data->dev = open(io->name, open_flags); 460 #endif 461 if (data->dev < 0) { 462 retval = errno; 463 goto cleanup; 464 } 465 466 #ifdef BLKROGET 467 if (flags & IO_FLAG_RW) { 468 int error; 469 int readonly = 0; 470 471 /* Is the block device actually writable? */ 472 error = ioctl(data->dev, BLKROGET, &readonly); 473 if (!error && readonly) { 474 close(data->dev); 475 retval = EPERM; 476 goto cleanup; 477 } 478 } 479 #endif 480 481 #ifdef __linux__ 482 #undef RLIM_INFINITY 483 #if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) 484 #define RLIM_INFINITY ((unsigned long)(~0UL>>1)) 485 #else 486 #define RLIM_INFINITY (~0UL) 487 #endif 488 /* 489 * Work around a bug in 2.4.10-2.4.18 kernels where writes to 490 * block devices are wrongly getting hit by the filesize 491 * limit. This workaround isn't perfect, since it won't work 492 * if glibc wasn't built against 2.2 header files. (Sigh.) 493 * 494 */ 495 if ((flags & IO_FLAG_RW) && 496 (uname(&ut) == 0) && 497 ((ut.release[0] == '2') && (ut.release[1] == '.') && 498 (ut.release[2] == '4') && (ut.release[3] == '.') && 499 (ut.release[4] == '1') && (ut.release[5] >= '0') && 500 (ut.release[5] < '8')) && 501 (fstat(data->dev, &st) == 0) && 502 (S_ISBLK(st.st_mode))) { 503 struct rlimit rlim; 504 505 rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; 506 setrlimit(RLIMIT_FSIZE, &rlim); 507 getrlimit(RLIMIT_FSIZE, &rlim); 508 if (((unsigned long) rlim.rlim_cur) < 509 ((unsigned long) rlim.rlim_max)) { 510 rlim.rlim_cur = rlim.rlim_max; 511 setrlimit(RLIMIT_FSIZE, &rlim); 512 } 513 } 514 #endif 515 *channel = io; 516 return 0; 517 518 cleanup: 519 if (data) { 520 free_cache(data); 521 ext2fs_free_mem(&data); 522 } 523 if (io) 524 ext2fs_free_mem(&io); 525 return retval; 526 } 527 528 static errcode_t unix_close(io_channel channel) 529 { 530 struct unix_private_data *data; 531 errcode_t retval = 0; 532 533 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 534 data = (struct unix_private_data *) channel->private_data; 535 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 536 537 if (--channel->refcount > 0) 538 return 0; 539 540 #ifndef NO_IO_CACHE 541 retval = flush_cached_blocks(channel, data, 0); 542 #endif 543 544 if (close(data->dev) < 0) 545 retval = errno; 546 free_cache(data); 547 548 ext2fs_free_mem(&channel->private_data); 549 if (channel->name) 550 ext2fs_free_mem(&channel->name); 551 ext2fs_free_mem(&channel); 552 return retval; 553 } 554 555 static errcode_t unix_set_blksize(io_channel channel, int blksize) 556 { 557 struct unix_private_data *data; 558 errcode_t retval; 559 560 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 561 data = (struct unix_private_data *) channel->private_data; 562 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 563 564 if (channel->block_size != blksize) { 565 #ifndef NO_IO_CACHE 566 if ((retval = flush_cached_blocks(channel, data, 0))) 567 return retval; 568 #endif 569 570 channel->block_size = blksize; 571 free_cache(data); 572 if ((retval = alloc_cache(channel, data))) 573 return retval; 574 } 575 return 0; 576 } 577 578 579 static errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 580 int count, void *buf) 581 { 582 struct unix_private_data *data; 583 struct unix_cache *cache, *reuse[READ_DIRECT_SIZE]; 584 errcode_t retval; 585 char *cp; 586 int i, j; 587 588 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 589 data = (struct unix_private_data *) channel->private_data; 590 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 591 592 #ifdef NO_IO_CACHE 593 return raw_read_blk(channel, data, block, count, buf); 594 #else 595 /* 596 * If we're doing an odd-sized read or a very large read, 597 * flush out the cache and then do a direct read. 598 */ 599 if (count < 0 || count > WRITE_DIRECT_SIZE) { 600 if ((retval = flush_cached_blocks(channel, data, 0))) 601 return retval; 602 return raw_read_blk(channel, data, block, count, buf); 603 } 604 605 cp = buf; 606 while (count > 0) { 607 /* If it's in the cache, use it! */ 608 if ((cache = find_cached_block(data, block, &reuse[0]))) { 609 #ifdef DEBUG 610 printf("Using cached block %lu\n", block); 611 #endif 612 memcpy(cp, cache->buf, channel->block_size); 613 count--; 614 block++; 615 cp += channel->block_size; 616 continue; 617 } 618 /* 619 * Find the number of uncached blocks so we can do a 620 * single read request 621 */ 622 for (i=1; i < count; i++) 623 if (find_cached_block(data, block+i, &reuse[i])) 624 break; 625 #ifdef DEBUG 626 printf("Reading %d blocks starting at %lu\n", i, block); 627 #endif 628 if ((retval = raw_read_blk(channel, data, block, i, cp))) 629 return retval; 630 631 /* Save the results in the cache */ 632 for (j=0; j < i; j++) { 633 count--; 634 cache = reuse[j]; 635 reuse_cache(channel, data, cache, block++); 636 memcpy(cache->buf, cp, channel->block_size); 637 cp += channel->block_size; 638 } 639 } 640 return 0; 641 #endif /* NO_IO_CACHE */ 642 } 643 644 static errcode_t unix_read_blk(io_channel channel, unsigned long block, 645 int count, void *buf) 646 { 647 return unix_read_blk64(channel, block, count, buf); 648 } 649 650 static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 651 int count, const void *buf) 652 { 653 struct unix_private_data *data; 654 struct unix_cache *cache, *reuse; 655 errcode_t retval = 0; 656 const char *cp; 657 int writethrough; 658 659 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 660 data = (struct unix_private_data *) channel->private_data; 661 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 662 663 #ifdef NO_IO_CACHE 664 return raw_write_blk(channel, data, block, count, buf); 665 #else 666 /* 667 * If we're doing an odd-sized write or a very large write, 668 * flush out the cache completely and then do a direct write. 669 */ 670 if (count < 0 || count > WRITE_DIRECT_SIZE) { 671 if ((retval = flush_cached_blocks(channel, data, 1))) 672 return retval; 673 return raw_write_blk(channel, data, block, count, buf); 674 } 675 676 /* 677 * For a moderate-sized multi-block write, first force a write 678 * if we're in write-through cache mode, and then fill the 679 * cache with the blocks. 680 */ 681 writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; 682 if (writethrough) 683 retval = raw_write_blk(channel, data, block, count, buf); 684 685 cp = buf; 686 while (count > 0) { 687 cache = find_cached_block(data, block, &reuse); 688 if (!cache) { 689 cache = reuse; 690 reuse_cache(channel, data, cache, block); 691 } 692 memcpy(cache->buf, cp, channel->block_size); 693 cache->dirty = !writethrough; 694 count--; 695 block++; 696 cp += channel->block_size; 697 } 698 return retval; 699 #endif /* NO_IO_CACHE */ 700 } 701 702 static errcode_t unix_write_blk(io_channel channel, unsigned long block, 703 int count, const void *buf) 704 { 705 return unix_write_blk64(channel, block, count, buf); 706 } 707 708 static errcode_t unix_write_byte(io_channel channel, unsigned long offset, 709 int size, const void *buf) 710 { 711 struct unix_private_data *data; 712 errcode_t retval = 0; 713 ssize_t actual; 714 715 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 716 data = (struct unix_private_data *) channel->private_data; 717 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 718 719 #ifndef NO_IO_CACHE 720 /* 721 * Flush out the cache completely 722 */ 723 if ((retval = flush_cached_blocks(channel, data, 1))) 724 return retval; 725 #endif 726 727 if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0) 728 return errno; 729 730 actual = write(data->dev, buf, size); 731 if (actual != size) 732 return EXT2_ET_SHORT_WRITE; 733 734 return 0; 735 } 736 737 /* 738 * Flush data buffers to disk. 739 */ 740 static errcode_t unix_flush(io_channel channel) 741 { 742 struct unix_private_data *data; 743 errcode_t retval = 0; 744 745 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 746 data = (struct unix_private_data *) channel->private_data; 747 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 748 749 #ifndef NO_IO_CACHE 750 retval = flush_cached_blocks(channel, data, 0); 751 #endif 752 fsync(data->dev); 753 return retval; 754 } 755 756 static errcode_t unix_set_option(io_channel channel, const char *option, 757 const char *arg) 758 { 759 struct unix_private_data *data; 760 unsigned long long tmp; 761 char *end; 762 763 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 764 data = (struct unix_private_data *) channel->private_data; 765 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 766 767 if (!strcmp(option, "offset")) { 768 if (!arg) 769 return EXT2_ET_INVALID_ARGUMENT; 770 771 tmp = strtoull(arg, &end, 0); 772 if (*end) 773 return EXT2_ET_INVALID_ARGUMENT; 774 data->offset = tmp; 775 if (data->offset < 0) 776 return EXT2_ET_INVALID_ARGUMENT; 777 return 0; 778 } 779 return EXT2_ET_INVALID_ARGUMENT; 780 } 781