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