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