This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / gnu / libexec / uucp / libunix / move.c
CommitLineData
41c799d4
C
1/* move.c
2 Move a file.
3
4 Copyright (C) 1991, 1992 Ian Lance Taylor
5
6 This file is part of the Taylor UUCP package.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 The author of the program may be contacted at ian@airs.com or
23 c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
24 */
25
26#include "uucp.h"
27
28#include "uudefs.h"
29#include "sysdep.h"
30#include "system.h"
31
32#include <errno.h>
33
34#if HAVE_FCNTL_H
35#include <fcntl.h>
36#else
37#if HAVE_SYS_FILE_H
38#include <sys/file.h>
39#endif
40#endif
41\f
42/* Move (rename) a file from one name to another. This routine will
43 optionally create necessary directories, and fpublic indicates
44 whether the new directories should be publically accessible or not.
45 If fcheck is true, it will try to determine whether the named user
46 has write access to the new file. */
47
48boolean
49fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser)
50 const char *zorig;
51 const char *zto;
52 boolean fmkdirs;
53 boolean fpublic;
54 boolean fcheck;
55 const char *zuser;
56{
57 struct stat s;
58 int o;
59
60 DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
61 "fsysdep_move_file: Moving %s to %s", zorig, zto);
62
63 /* Optionally make sure that zuser has write access on the
64 directory. */
65 if (fcheck)
66 {
67 char *zcopy;
68 char *zslash;
69
70 zcopy = zbufcpy (zto);
71 zslash = strrchr (zcopy, '/');
72 if (zslash == zcopy)
73 zslash[1] = '\0';
74 else
75 *zslash = '\0';
76
77 if (stat (zcopy, &s) != 0)
78 {
79 ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno));
80 (void) remove (zorig);
81 ubuffree (zcopy);
82 return FALSE;
83 }
84 if (! fsuser_access (&s, W_OK, zuser))
85 {
86 ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
87 (void) remove (zorig);
88 ubuffree (zcopy);
89 return FALSE;
90 }
91 ubuffree (zcopy);
92
93 /* A malicious user now has a few milliseconds to change a
94 symbolic link to a directory uucp has write permission on but
95 the user does not (the obvious choice being /usr/lib/uucp).
96 The only certain method I can come up with to close this race
97 is to fork an suid process which takes on the users identity
98 and does the actual copy. This is sufficiently high overhead
99 that I'm not going to do it. */
100 }
101
102 /* We try to use rename to move the file. */
103
104 if (rename (zorig, zto) == 0)
105 return TRUE;
106
107 if (fmkdirs && errno == ENOENT)
108 {
109 if (! fsysdep_make_dirs (zto, fpublic))
110 {
111 (void) remove (zorig);
112 return FALSE;
113 }
114 if (rename (zorig, zto) == 0)
115 return TRUE;
116 }
117
118#if HAVE_RENAME
119 /* On some systems the system call rename seems to fail for
120 arbitrary reasons. To get around this, we always try to copy the
121 file by hand if the rename failed. */
122 errno = EXDEV;
123#endif
124
125 /* If we can't link across devices, we must copy the file by hand. */
126 if (errno != EXDEV)
127 {
128 ulog (LOG_ERROR, "rename (%s, %s): %s", zorig, zto,
129 strerror (errno));
130 (void) remove (zorig);
131 return FALSE;
132 }
133
134 /* Copy the file. */
135 if (stat ((char *) zorig, &s) < 0)
136 {
137 ulog (LOG_ERROR, "stat (%s): %s", zorig, strerror (errno));
138 (void) remove (zorig);
139 return FALSE;
140 }
141
142 /* Make sure the file gets the right mode by creating it before we
143 call fcopy_file. */
144 (void) remove (zto);
145 o = creat ((char *) zto, s.st_mode);
146 if (o < 0)
147 {
148 if (fmkdirs && errno == ENOENT)
149 {
150 if (! fsysdep_make_dirs (zto, fpublic))
151 {
152 (void) remove (zorig);
153 return FALSE;
154 }
155 o = creat ((char *) zto, s.st_mode);
156 }
157 if (o < 0)
158 {
159 ulog (LOG_ERROR, "creat (%s): %s", zto, strerror (errno));
160 (void) remove (zorig);
161 return FALSE;
162 }
163 }
164 (void) close (o);
165
166 if (! fcopy_file (zorig, zto, fpublic, fmkdirs))
167 {
168 (void) remove (zorig);
169 return FALSE;
170 }
171
172 if (remove (zorig) != 0)
173 ulog (LOG_ERROR, "remove (%s): %s", zorig, strerror (errno));
174
175 return TRUE;
176}