diff options
Diffstat (limited to 'sysdeps/posix/posix_fallocate.c')
-rw-r--r-- | sysdeps/posix/posix_fallocate.c | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/sysdeps/posix/posix_fallocate.c b/sysdeps/posix/posix_fallocate.c index 838e7a0..cbaeb49 100644 --- a/sysdeps/posix/posix_fallocate.c +++ b/sysdeps/posix/posix_fallocate.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000, 2003 Free Software Foundation, Inc. +/* Copyright (C) 2000, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -29,9 +29,8 @@ posix_fallocate (int fd, __off_t offset, __off_t len) { struct stat64 st; struct statfs f; - size_t step; - /* `off_tī is a signed type. Therefore we can determine whether + /* `off_t' is a signed type. Therefore we can determine whether OFFSET + LEN is too large if it is a negative value. */ if (offset < 0 || len < 0) return EINVAL; @@ -47,24 +46,48 @@ posix_fallocate (int fd, __off_t offset, __off_t len) if (! S_ISREG (st.st_mode)) return ENODEV; + if (len == 0) + { + if (st.st_size < offset) + { + int ret = __ftruncate (fd, offset); + + if (ret != 0) + ret = errno; + return ret; + } + return 0; + } + /* We have to know the block size of the filesystem to get at least some sort of performance. */ if (__fstatfs (fd, &f) != 0) return errno; - /* Align OFFSET to block size and adjust LEN. */ - step = (offset + f.f_bsize - 1) % ~f.f_bsize; - offset += step; + /* Try to play safe. */ + if (f.f_bsize == 0) + f.f_bsize = 512; /* Write something to every block. */ - while (len > step) + for (offset += (len - 1) % f.f_bsize; len > 0; offset += f.f_bsize) { - len -= step; + len -= f.f_bsize; + + if (offset < st.st_size) + { + unsigned char c; + ssize_t rsize = __pread (fd, &c, 1, offset); + + if (rsize < 0) + return errno; + /* If there is a non-zero byte, the block must have been + allocated already. */ + else if (rsize == 1 && c != 0) + continue; + } if (__pwrite (fd, "", 1, offset) != 1) return errno; - - offset += step; } return 0; |