]> andersk Git - moira.git/blob - update/get_file.c
handle "noclobber" and "user" config options; receive mode as arg
[moira.git] / update / get_file.c
1 /*
2  *      $Source$
3  *      $Header$
4  */
5 /*  (c) Copyright 1988 by the Massachusetts Institute of Technology. */
6 /*  For copying and distribution information, please see the file */
7 /*  <mit-copyright.h>. */
8
9 #ifndef lint
10 static char *rcsid_get_file_c = "$Header$";
11 #endif  lint
12
13 #include <mit-copyright.h>
14 #include <stdio.h>
15 #include <gdb.h>
16 #include <ctype.h>
17 #include <sys/param.h>
18 #include <sys/file.h>
19 #include <moira.h>
20 #include "update.h"
21
22 #ifndef MIN
23 #define MIN(a,b)    (((a) < (b))?(a):(b))
24 #endif /* MIN */
25
26 extern CONNECTION conn;
27 char buf[BUFSIZ];
28
29 extern int code, errno, uid;
30
31 extern int have_authorization, have_file, done;
32
33 int get_block();
34
35 /*
36  * get_file()
37  *
38  * arguments:
39  *      char *pathname
40  *              file to receive
41  *      int file_size
42  *              number of bytes
43  *      int checksum
44  *              linear checksum of bytes
45  *
46  * syntax:
47  * (initial protocol already done)
48  * <<< (int)code        (can we accept the file?)
49  * >>> (STRING)data
50  * <<< (int)code
51  * >>> (STRING)data
52  * <<< (int)code
53  * ...
54  * >>> (STRING)data     (last data block)
55  * <<< (int)code        (from read, write, checksum verify)
56  *
57  * returns:
58  *      int
59  *              0 for success, 1 for failure
60  *
61  * function:
62  *      perform initial preparations and receive file as
63  * a single string, storing it into <pathname>
64  *
65  */
66
67 int
68 get_file(pathname, file_size, checksum, mode)
69     char *pathname;
70     int file_size;
71     int checksum;
72     int mode;
73 {
74     int fd, n_written;
75     int found_checksum;
76     
77     if (!have_authorization) {
78         reject_call(MR_PERM);
79         return(1);
80     }
81     if (done)                   /* re-initialize data */
82         initialize();
83     if (setreuid(0, uid) < 0) {
84         com_err(whoami, errno, "Unable to setuid to %d\n", uid);
85         exit(1);
86     }
87     /* unlink old file */
88     if (!config_lookup("noclobber"))
89       (void) unlink(pathname);
90     /* open file descriptor */
91     fd = open(pathname, O_CREAT|O_EXCL|O_WRONLY, mode);
92     if (fd == -1) {
93         code = errno;
94         sprintf(buf, "%s: creating file %s (get_file)",
95                 error_message(code), pathname);
96         mr_log_error(buf);
97         report_error("reporting file creation error (get_file)");
98         if (setuid(0) < 0) {
99             com_err(whoami, errno, "Unable to setuid back to %d\n", 0);
100             exit(1);
101         }
102         return(1);
103     }
104     /* check to see if we've got the disk space */
105     n_written = 0;
106     while (n_written < file_size) {
107         register int n_wrote;
108         n_wrote = write(fd, buf, sizeof(buf));
109         if (n_wrote == -1) {
110             code = errno;
111             sprintf(buf, "%s: verifying free disk space for %s (get_file)",
112                     error_message(code), pathname);
113             mr_log_error(buf);
114             /* do all we can to free the space */
115             (void) unlink(pathname);
116             (void) ftruncate(fd, 0);
117             (void) close(fd);
118             report_error("reporting test-write error (get_file)");
119             if (setuid(0) < 0) {
120                 com_err(whoami, errno, "Unable to setuid back to %d\n", 0);
121                 exit(1);
122             }
123             return(1);
124         }
125         n_written += n_wrote;
126     }
127     lseek(fd, 0, L_SET);
128     if (send_ok())
129         lose("sending okay for file transfer (get_file)");
130     n_written = 0;
131     while (n_written < file_size && code == 0) {
132         int n_got = get_block(fd, file_size - n_written);
133         if (n_got == -1) {
134             /* get_block has already printed a message */
135             unlink(pathname);
136             if (setuid(0) < 0) {
137                 com_err(whoami, errno, "Unable to setuid back to %d\n", 0);
138                 exit(1);
139             }
140             return(1);
141         }
142         n_written += n_got;
143         if (n_written != file_size)
144             if (send_ok())
145                 lose("receiving data");
146     }
147     if (code) {
148         code = connection_errno(conn);
149         report_error("reading file (get_file)");
150         if (setuid(0) < 0) {
151             com_err(whoami, errno, "Unable to setuid back to %d\n", 0);
152             exit(1);
153         }
154         return(1);
155     }
156     fsync(fd);
157     ftruncate(fd, file_size);
158     fsync(fd);
159     close(fd);
160     if (setuid(0) < 0) {
161         com_err(whoami, errno, "Unable to setuid back to %d\n", 0);
162         exit(1);
163     }
164     /* validate checksum */
165     found_checksum = checksum_file(pathname);
166     if (checksum != found_checksum) {
167         code = MR_MISSINGFILE;
168         com_err(whoami, code, ": expected = %d, found = %d",
169                 checksum, found_checksum);
170         report_error("checksum error");
171         return(1);
172     }
173     /* send ack or nack */
174     have_file = 1;
175     if (send_ok()) {
176         code = connection_errno(conn);
177         (void) unlink(pathname);
178         lose("sending ok after file transfer (get_file)");
179         return(1);
180     }
181     return(0);
182 }
183
184 static int
185 get_block(fd, max_size)
186     int fd;
187     int max_size;
188 {
189     STRING data;
190     int n_read, n;
191
192     code = receive_object(conn, (char *)&data, STRING_T);
193     if (code) {
194         code = connection_errno(conn);
195         lose("receiving data file (get_file)");
196     }
197     n_read = MIN(MAX_STRING_SIZE(data), max_size);
198     n = 0;
199     while (n < n_read) {
200         register int n_wrote;
201         n_wrote = write(fd, STRING_DATA(data)+n,
202                         n_read-n);
203         if (n_wrote == -1) {
204             code = errno;
205             sprintf(buf, "%s: writing file (get_file)", error_message(code));
206             mr_log_error(buf);
207             string_free(&data);
208             report_error("reporting write error (get_file)");
209             close(fd);
210             return(-1);
211         }
212         n += n_wrote;
213     }
214     string_free(&data);
215     return(n);
216 }
This page took 0.249695 seconds and 5 git commands to generate.