varnish-cache/lib/libvarnish/vfl.c
0
/*-
1
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
2
 *
3
 * Copyright (c) 2007-2009 Dag-Erling Coïdan Smørgrav
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer
11
 *    in this position and unchanged.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 * Derived from:
28
 * $FreeBSD: head/lib/libutil/flopen.c 326219 2017-11-26 02:00:33Z pfg $
29
 */
30
31
#include "config.h"
32
33
#include <sys/file.h>
34
#include <sys/stat.h>
35
36
#include <errno.h>
37
#include <fcntl.h>      //lint !e537
38
#include <stdarg.h>
39
#include <unistd.h>
40
41
#include "vfl.h"
42
43
/*
44
 * Reliably open and lock a file.
45
 *
46
 * Please do not modify this code without first reading the revision history
47
 * and discussing your changes with <des@freebsd.org>.  Don't be fooled by the
48
 * code's apparent simplicity; there would be no need for this function if it
49
 * was easy to get right.
50
 */
51
static int
52 45725
vflopenat(int dirfd, const char *path, int flags, va_list ap)
53
{
54
        int fd, operation, serrno, trunc;
55
        struct stat sb, fsb;
56
        mode_t mode;
57
58
#ifdef O_EXLOCK
59 45725
        flags &= ~O_EXLOCK;
60
#endif
61
62 45725
        mode = 0;
63 45725
        if (flags & O_CREAT) {
64 45725
                mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */
65 45725
        }
66
67 45725
        operation = LOCK_EX;
68 45725
        if (flags & O_NONBLOCK)
69 45725
                operation |= LOCK_NB;
70
71 45725
        trunc = (flags & O_TRUNC);
72 45725
        flags &= ~O_TRUNC;
73
74 45725
        for (;;) {
75 45725
                if ((fd = openat(dirfd, path, flags, mode)) == -1)
76
                        /* non-existent or no access */
77 25
                        return (-1);
78 45700
                if (flock(fd, operation) == -1) {
79
                        /* unsupported or interrupted */
80 50
                        serrno = errno;
81 50
                        (void)close(fd);
82 50
                        errno = serrno;
83 50
                        return (-1);
84
                }
85 45650
                if (fstatat(dirfd, path, &sb, 0) == -1) {
86
                        /* disappeared from under our feet */
87 0
                        (void)close(fd);
88 0
                        continue;
89
                }
90 45650
                if (fstat(fd, &fsb) == -1) {
91
                        /* can't happen [tm] */
92 0
                        serrno = errno;
93 0
                        (void)close(fd);
94 0
                        errno = serrno;
95 0
                        return (-1);
96
                }
97 45650
                if (sb.st_dev != fsb.st_dev ||
98 45650
                    sb.st_ino != fsb.st_ino) {
99
                        /* changed under our feet */
100 0
                        (void)close(fd);
101 0
                        continue;
102
                }
103 45650
                if (trunc && ftruncate(fd, 0) != 0) {
104
                        /* can't happen [tm] */
105 0
                        serrno = errno;
106 0
                        (void)close(fd);
107 0
                        errno = serrno;
108 0
                        return (-1);
109
                }
110
                /*
111
                 * The following change is provided as a specific example to
112
                 * avoid.
113
                 */
114
#if 0
115
                if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
116
                        serrno = errno;
117
                        (void)close(fd);
118
                        errno = serrno;
119
                        return (-1);
120
                }
121
#endif
122 45650
                return (fd);
123
        }
124 45725
}
125
126
int
127 45725
VFL_Open(const char *path, int flags, ...)
128
{
129
        va_list ap;
130
        int ret;
131
132 45725
        va_start(ap, flags);
133 45725
        ret = vflopenat(AT_FDCWD, path, flags, ap);
134 45725
        va_end(ap);
135 45725
        return (ret);
136
}