/* Truncate PATH to LENGTH bytes. */ int __truncate (const char *path, off_t length) { int fd, ret, save; fd = __open (path, O_WRONLY | (length == 0 ? O_TRUNC : 0)); if (fd < 0) return -1; if (length == 0) ret = 0; else ret = __ftruncate (fd, length); save = errno; (void) __close (fd); if (ret < 0) __set_errno (save); return ret; }
int posix_fallocate (int fd, __off_t offset, __off_t len) { struct stat64 st; if (offset < 0 || len < 0) return EINVAL; /* Perform overflow check. The outer cast relies on a GCC extension. */ if ((__off_t) ((uint64_t) offset + (uint64_t) len) < 0) return EFBIG; /* pwrite below will not do the right thing in O_APPEND mode. */ { int flags = __fcntl (fd, F_GETFL, 0); if (flags < 0 || (flags & O_APPEND) != 0) return EBADF; } /* We have to make sure that this is really a regular file. */ if (__fxstat64 (_STAT_VER, fd, &st) != 0) return EBADF; if (S_ISFIFO (st.st_mode)) return ESPIPE; if (! S_ISREG (st.st_mode)) return ENODEV; if (len == 0) { /* This is racy, but there is no good way to satisfy a zero-length allocation request. */ if (st.st_size < offset) { int ret = __ftruncate (fd, offset); if (ret != 0) ret = errno; return ret; } return 0; } /* Minimize data transfer for network file systems, by issuing single-byte write requests spaced by the file system block size. (Most local file systems have fallocate support, so this fallback code is not used there.) */ unsigned increment; { struct statfs64 f; if (__fstatfs64 (fd, &f) != 0) return errno; if (f.f_bsize == 0) increment = 512; else if (f.f_bsize < 4096) increment = f.f_bsize; else /* NFS does not propagate the block size of the underlying storage and may report a much larger value which would still leave holes after the loop below, so we cap the increment at 4096. */ increment = 4096; } /* Write a null byte to every block. This is racy; we currently lack a better option. Compare-and-swap against a file mapping might additional local races, but requires interposition of a signal handler to catch SIGBUS. */ for (offset += (len - 1) % increment; len > 0; offset += increment) { len -= increment; 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; } return 0; }
int __ftruncate64 (int fd, off64_t length) { return __ftruncate(fd, (off_t)length); }
/* * This function provides 64-bit offset padding that * is not supplied by GCC 1.X but is supplied by GCC 2.X. */ int ftruncate(int fd, off_t length) { return __ftruncate(fd, 0, length); }