1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1990-2012 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                                                                      *
19***********************************************************************/
20#pragma prototyped
21/*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * sync all outstanding file operations for file opened on fd
26 * if file==0 then fd used
27 * if fd<0 then file used
28 * if mode<0 then fd not created
29 *
30 * NOTE: this is an unfortunate NFS workaround that should be done by fsync()
31 */
32
33#include "colib.h"
34
35#include <ls.h>
36
37#include "FEATURE/nfsd"
38
39int
40cosync(Coshell_t* co, const char* file, int fd, int mode)
41{
42#if defined(_cmd_nfsd)
43	if (!co || (co->flags & CO_SERVER))
44	{
45		char	tmp[PATH_MAX];
46
47		if (file && *file)
48		{
49			register const char*	s;
50			register char*		t;
51			register char*		b;
52			int			td;
53
54			/*
55			 * writing to a dir apparently flushes the
56			 * attribute cache for all entries in the dir
57			 */
58
59			s = file;
60			b = t = tmp;
61			while (t < &tmp[sizeof(tmp) - 1])
62			{
63				if (!(*t = *s++)) break;
64				if (*t++ == '/') b = t;
65			}
66			s = "..nfs..botch..";
67			t = b;
68			while (t < &tmp[sizeof(tmp) - 1] && (*t++ = *s++));
69			*t = 0;
70			if ((td = open(tmp, O_WRONLY|O_CREAT|O_TRUNC|O_cloexec, 0)) >= 0)
71				close(td);
72			unlink(tmp);
73			if (fd >= 0 && mode >= 0)
74			{
75				if ((td = open(file, mode|O_cloexec)) < 0)
76					return(-1);
77				close(fd);
78				dup2(td, fd);
79				close(td);
80			}
81		}
82#if defined(F_SETLK)
83		else
84		{
85			int		clean = 0;
86			struct flock	lock;
87
88			if (fd < 0)
89			{
90				if (!file || mode < 0 || (fd = open(file, O_RDONLY|O_cloexec)) < 0) return(-1);
91				clean = 1;
92			}
93
94			/*
95			 * this sets the VNOCACHE flag across NFS
96			 */
97
98			lock.l_type = F_RDLCK;
99			lock.l_whence = 0;
100			lock.l_start = 0;
101			lock.l_len = 1;
102			if (!fcntl(fd, F_SETLK, &lock))
103			{
104				lock.l_type = F_UNLCK;
105				fcntl(fd, F_SETLK, &lock);
106			}
107			if (clean) close(fd);
108
109			/*
110			 * 4.1 has a bug that lets VNOCACHE linger after unlock
111			 * VNOCACHE inhibits mapping which kills exec
112			 * the double rename flushes the incore vnode (and VNOCACHE)
113			 *
114			 * this kind of stuff doesn't happen with *real* file systems
115			 */
116
117			if (file && *file)
118			{
119				strcpy(tmp, file);
120				fd = strlen(tmp) - 1;
121				tmp[fd] = (tmp[fd] == '*') ? '?' : '*';
122				if (!rename(file, tmp)) rename(tmp, file);
123			}
124		}
125#endif
126	}
127#endif
128	return(0);
129}
130