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