1/* opensr.c 2 Open files for sending and receiving. 3 4 Copyright (C) 1991, 1992, 1993, 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 21 22 The author of the program may be contacted at ian@airs.com. 23 */ 24 25#include "uucp.h" 26 27#include "uudefs.h" 28#include "uuconf.h" 29#include "system.h" 30#include "sysdep.h" 31 32#include <errno.h> 33 34#if HAVE_TIME_H 35#include <time.h> 36#endif 37 38#if HAVE_FCNTL_H 39#include <fcntl.h> 40#else 41#if HAVE_SYS_FILE_H 42#include <sys/file.h> 43#endif 44#endif 45 46#ifndef O_RDONLY 47#define O_RDONLY 0 48#define O_WRONLY 1 49#define O_RDWR 2 50#endif 51 52#ifndef O_NOCTTY 53#define O_NOCTTY 0 54#endif 55 56#ifndef FD_CLOEXEC 57#define FD_CLOEXEC 1 58#endif 59 60#ifndef time 61extern time_t time (); 62#endif 63 64/* Open a file to send to another system, and return the mode and 65 the size. */ 66 67openfile_t 68esysdep_open_send (qsys, zfile, fcheck, zuser) 69 const struct uuconf_system *qsys ATTRIBUTE_UNUSED; 70 const char *zfile; 71 boolean fcheck; 72 const char *zuser; 73{ 74 struct stat s; 75 openfile_t e; 76 int o; 77 78 if (fsysdep_directory (zfile)) 79 { 80 ulog (LOG_ERROR, "%s: is a directory", zfile); 81 return EFILECLOSED; 82 } 83 84#if USE_STDIO 85 e = fopen (zfile, BINREAD); 86 if (e == NULL) 87 { 88 ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); 89 return NULL; 90 } 91 o = fileno (e); 92#else 93 e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0); 94 if (e == -1) 95 { 96 ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno)); 97 return -1; 98 } 99 o = e; 100#endif 101 102 if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) 103 { 104 ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); 105 (void) ffileclose (e); 106 return EFILECLOSED; 107 } 108 109 if (fstat (o, &s) == -1) 110 { 111 ulog (LOG_ERROR, "fstat: %s", strerror (errno)); 112 s.st_mode = 0666; 113 } 114 115 /* We have to recheck the file permission, although we probably 116 checked it already, because otherwise there would be a window in 117 which somebody could change the contents of a symbolic link to 118 point to some file which was only readable by uucp. */ 119 if (fcheck) 120 { 121 if (! fsuser_access (&s, R_OK, zuser)) 122 { 123 ulog (LOG_ERROR, "%s: %s", zfile, strerror (EACCES)); 124 (void) ffileclose (e); 125 return EFILECLOSED; 126 } 127 } 128 129 return e; 130} 131 132/* Get a temporary file name to receive into. We use the ztemp 133 argument to pick the file name, so that we restart the file if the 134 transmission is aborted. */ 135 136char * 137zsysdep_receive_temp (qsys, zto, ztemp, frestart) 138 const struct uuconf_system *qsys; 139 const char *zto ATTRIBUTE_UNUSED; 140 const char *ztemp; 141 boolean frestart; 142{ 143 if (frestart 144 && ztemp != NULL 145 && *ztemp == 'D' 146 && strcmp (ztemp, "D.0") != 0) 147 return zsappend3 (".Temp", qsys->uuconf_zname, ztemp); 148 else 149 return zstemp_file (qsys); 150} 151 152/* The number of seconds in one week. We must cast to long for this 153 to be calculated correctly on a machine with 16 bit ints. */ 154#define SECS_PER_WEEK ((long) 7 * (long) 24 * (long) 60 * (long) 60) 155 156/* Open a temporary file to receive into. This should, perhaps, check 157 that we have write permission on the receiving directory, but it 158 doesn't. */ 159 160openfile_t 161esysdep_open_receive (qsys, zto, ztemp, zreceive, pcrestart) 162 const struct uuconf_system *qsys ATTRIBUTE_UNUSED; 163 const char *zto ATTRIBUTE_UNUSED; 164 const char *ztemp; 165 const char *zreceive; 166 long *pcrestart; 167{ 168 int o; 169 openfile_t e; 170 171 /* If we used the ztemp argument in zsysdep_receive_temp, above, 172 then we will have a name consistent across conversations. In 173 that case, we may have already received some portion of this 174 file. */ 175 o = -1; 176 if (pcrestart != NULL) 177 *pcrestart = -1; 178 if (pcrestart != NULL 179 && ztemp != NULL 180 && *ztemp == 'D' 181 && strcmp (ztemp, "D.0") != 0) 182 { 183 o = open ((char *) zreceive, O_WRONLY); 184 if (o >= 0) 185 { 186 struct stat s; 187 188 /* For safety, we insist on the file being less than 1 week 189 old. This can still catch people, unfortunately. I 190 don't know of any good solution to the problem of old 191 files hanging around. If anybody has a file they want 192 restarted, and they know about this issue, they can touch 193 it to bring it up to date. */ 194 if (fstat (o, &s) < 0 195 || s.st_mtime + SECS_PER_WEEK < time ((time_t *) NULL)) 196 { 197 (void) close (o); 198 o = -1; 199 } 200 else 201 { 202 DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, 203 "esysdep_open_receive: Reusing %s", 204 zreceive); 205 *pcrestart = (long) s.st_size; 206 } 207 } 208 } 209 210 if (o < 0) 211 o = creat ((char *) zreceive, IPRIVATE_FILE_MODE); 212 213 if (o < 0) 214 { 215 if (errno == ENOENT) 216 { 217 if (! fsysdep_make_dirs (zreceive, FALSE)) 218 return EFILECLOSED; 219 o = creat ((char *) zreceive, IPRIVATE_FILE_MODE); 220 } 221 if (o < 0) 222 { 223 ulog (LOG_ERROR, "creat during esysdep_open_receive (%s): %s", zreceive, strerror (errno)); 224 return EFILECLOSED; 225 } 226 } 227 228 if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) 229 { 230 ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); 231 (void) close (o); 232 (void) remove (zreceive); 233 return EFILECLOSED; 234 } 235 236#if USE_STDIO 237 e = fdopen (o, (char *) BINWRITE); 238 239 if (e == NULL) 240 { 241 ulog (LOG_ERROR, "fdopen (%s): %s", zreceive, strerror (errno)); 242 (void) close (o); 243 (void) remove (zreceive); 244 return EFILECLOSED; 245 } 246#else 247 e = o; 248#endif 249 250 return e; 251} 252