Commit | Line | Data |
---|---|---|
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 | ||
48 | boolean | |
49 | fsysdep_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 | } |