Whamcloud - gitweb
libext2fs: Remove #include of <linux/types.h> from fiemap.h
[tools/e2fsprogs.git] / lib / ext2fs / unix_io.c
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 Library
14  * General Public License, version 2.
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 }