Fix macOS posix_fallocate().

The fallback ftruncate() call was wrong, because posix_fallocate()
will never shrink a file, but ftruncate() will. Also, if that failed,
we didn't turn errno into a return code.

Also the fcntl() was wrong. In my defense, here's the documentation:

     The position modes (fst_posmode) for the F_PREALLOCATE command indicate
     how to use the offset field.  The modes are as follows:

           F_PEOFPOSMODE   Allocate from the physical end of file.  In this
                           case, fst_length indicates the number of newly
                           allocated bytes desired.

           F_VOLPOSMODE    Allocate from the volume offset.

I think the new version is right, though it's obviously a lot more
conservative than the real posix_fallocate(), but I don't think
it's possible to do better?

Also add tests for some of the prior failures.

Fixes #472.
This commit is contained in:
Elliott Hughes 2023-12-14 20:53:35 -08:00 committed by Rob Landley
parent 20d5dade3a
commit d908031520
2 changed files with 14 additions and 5 deletions

View File

@ -380,18 +380,19 @@ int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev)
}
// As of 10.15, macOS offers an fcntl F_PREALLOCATE rather than fallocate()
// or posix_fallocate() calls.
// or posix_fallocate() calls. The fcntl only (as the name implies)
// pre-allocates, so we also need to ftruncate() afterwards.
int posix_fallocate(int fd, off_t offset, off_t length)
{
int e = errno, result;
int e = errno, result = 0;
fstore_t f;
f.fst_flags = F_ALLOCATEALL;
f.fst_posmode = F_PEOFPOSMODE;
f.fst_offset = offset;
f.fst_length = length;
f.fst_offset = 0;
f.fst_length = offset + length;
if (fcntl(fd, F_PREALLOCATE, &f) == -1) result = errno;
else result = ftruncate(fd, length);
else if (ftruncate(fd, maxof(offset+length, fdlength(fd)))) result = errno;
errno = e;
return result;
}

8
tests/fallocate.test Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
#testing "name" "command" "result" "infile" "stdin"
rm -f foo
testcmd 'simple' '-l 123 foo && stat -c %s foo' '123\n' '' ''
testcmd 'shorter' '-l 12 foo && stat -c %s foo' '123\n' '' ''
testcmd 'longer' '-o 200 -l 12 foo && stat -c %s foo' '212\n' '' ''