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