X-Git-Url: https://git.cameronkatri.com/pw-darwin.git/blobdiff_plain/359769889d017e0d5ac6423fe9b719998c2d5d66..6b46c62f4663c84790120a4e74e155a6ef16b41c:/libutil/flopen.c diff --git a/libutil/flopen.c b/libutil/flopen.c index 1eb59a0..485eee4 100644 --- a/libutil/flopen.c +++ b/libutil/flopen.c @@ -1,5 +1,7 @@ /*- - * Copyright (c) 2007 Dag-Erling Coïdan Smørgrav + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2007-2009 Dag-Erling Coïdan Smørgrav * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,16 +30,27 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include -#include #include +#include -int -flopen(const char *path, int flags, ...) +#include + +/* + * Reliably open and lock a file. + * + * Please do not modify this code without first reading the revision history + * and discussing your changes with . Don't be fooled by the + * code's apparent simplicity; there would be no need for this function if it + * was easy to get right. + */ +static int +vflopenat(int dirfd, const char *path, int flags, va_list ap) { - int fd, operation, serrno; + int fd, operation, serrno, trunc; struct stat sb, fsb; mode_t mode; @@ -47,46 +60,88 @@ flopen(const char *path, int flags, ...) mode = 0; if (flags & O_CREAT) { - va_list ap; - - va_start(ap, flags); - mode = va_arg(ap, int); /* mode_t promoted to int */ - va_end(ap); + mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */ } - operation = LOCK_EX; - if (flags & O_NONBLOCK) - operation |= LOCK_NB; + operation = LOCK_EX; + if (flags & O_NONBLOCK) + operation |= LOCK_NB; + + trunc = (flags & O_TRUNC); + flags &= ~O_TRUNC; for (;;) { - if ((fd = open(path, flags, mode)) == -1) + if ((fd = openat(dirfd, path, flags, mode)) == -1) /* non-existent or no access */ return (-1); if (flock(fd, operation) == -1) { /* unsupported or interrupted */ serrno = errno; - close(fd); + (void)close(fd); errno = serrno; return (-1); } - if (stat(path, &sb) == -1) { + if (fstatat(dirfd, path, &sb, 0) == -1) { /* disappeared from under our feet */ - close(fd); + (void)close(fd); continue; } if (fstat(fd, &fsb) == -1) { /* can't happen [tm] */ serrno = errno; - close(fd); + (void)close(fd); errno = serrno; return (-1); } if (sb.st_dev != fsb.st_dev || sb.st_ino != fsb.st_ino) { /* changed under our feet */ - close(fd); + (void)close(fd); continue; } + if (trunc && ftruncate(fd, 0) != 0) { + /* can't happen [tm] */ + serrno = errno; + (void)close(fd); + errno = serrno; + return (-1); + } + /* + * The following change is provided as a specific example to + * avoid. + */ +#if 0 + if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { + serrno = errno; + (void)close(fd); + errno = serrno; + return (-1); + } +#endif return (fd); } } + +int +flopen(const char *path, int flags, ...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = vflopenat(AT_FDCWD, path, flags, ap); + va_end(ap); + return (ret); +} + +int +flopenat(int dirfd, const char *path, int flags, ...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = vflopenat(dirfd, path, flags, ap); + va_end(ap); + return (ret); +}