summaryrefslogtreecommitdiffstats
path: root/src/util/sane_link.c
blob: 40fd56d3bad78b8fcbb53144e333889f001d8367 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*++
/* NAME
/*	sane_link 3
/* SUMMARY
/*	sanitize link() error returns
/* SYNOPSIS
/*	#include <sane_fsops.h>
/*
/*	int	sane_link(from, to)
/*	const char *from;
/*	const char *to;
/* DESCRIPTION
/*	sane_link() implements the link(2) system call, and works
/*	around some errors that are possible with NFS file systems.
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*--*/

/* System library. */

#include "sys_defs.h"
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>

/* Utility library. */

#include "msg.h"
#include "sane_fsops.h"
#include "warn_stat.h"

/* sane_link - sanitize link() error returns */

int     sane_link(const char *from, const char *to)
{
    const char *myname = "sane_link";
    int     saved_errno;
    struct stat from_st;
    struct stat to_st;

    /*
     * Normal case: link() succeeds.
     */
    if (link(from, to) >= 0)
	return (0);

    /*
     * Woops. Save errno, and see if the error is an NFS artifact. If it is,
     * pretend the error never happened.
     */
    saved_errno = errno;
    if (stat(from, &from_st) >= 0 && stat(to, &to_st) >= 0
	&& from_st.st_dev == to_st.st_dev
	&& from_st.st_ino == to_st.st_ino) {
	msg_info("%s(%s,%s): worked around spurious NFS error",
		 myname, from, to);
	return (0);
    }

    /*
     * Nope, it didn't. Restore errno and report the error.
     */
    errno = saved_errno;
    return (-1);
}