maint: use COPYING.LIB version 2.1
[libguestfs.git] / daemon / tar.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <fcntl.h>
25
26 #include "../src/guestfs_protocol.h"
27 #include "daemon.h"
28 #include "actions.h"
29
30 static int
31 fwrite_cb (void *fp_ptr, const void *buf, int len)
32 {
33   FILE *fp = *(FILE **)fp_ptr;
34   return fwrite (buf, len, 1, fp) == 1 ? 0 : -1;
35 }
36
37 /* Has one FileIn parameter. */
38 int
39 do_tar_in (char *dir)
40 {
41   int err, r;
42   FILE *fp;
43   char *cmd;
44
45   if (!root_mounted || dir[0] != '/') {
46     cancel_receive ();
47     reply_with_error ("tar-in: root must be mounted and path must be absolute");
48     return -1;
49   }
50
51   /* "tar -C /sysroot%s -xf -" but we have to quote the dir. */
52   if (asprintf_nowarn (&cmd, "tar -C %R -xf -", dir) == -1) {
53     err = errno;
54     cancel_receive ();
55     errno = err;
56     reply_with_perror ("asprintf");
57     return -1;
58   }
59
60   if (verbose)
61     fprintf (stderr, "%s\n", cmd);
62
63   fp = popen (cmd, "w");
64   if (fp == NULL) {
65     err = errno;
66     cancel_receive ();
67     errno = err;
68     reply_with_perror ("%s", cmd);
69     free (cmd);
70     return -1;
71   }
72   free (cmd);
73
74   r = receive_file (fwrite_cb, &fp);
75   if (r == -1) {                /* write error */
76     err = errno;
77     cancel_receive ();
78     errno = err;
79     reply_with_perror ("write: %s", dir);
80     pclose (fp);
81     return -1;
82   }
83   if (r == -2) {                /* cancellation from library */
84     pclose (fp);
85     /* Do NOT send any error. */
86     return -1;
87   }
88
89   if (pclose (fp) != 0) {
90     err = errno;
91     cancel_receive ();
92     errno = err;
93     reply_with_perror ("pclose: %s", dir);
94     return -1;
95   }
96
97   return 0;
98 }
99
100 /* Has one FileOut parameter. */
101 int
102 do_tar_out (char *dir)
103 {
104   int r;
105   FILE *fp;
106   char *cmd;
107   char buf[GUESTFS_MAX_CHUNK_SIZE];
108
109   NEED_ROOT (-1);
110   ABS_PATH (dir, -1);
111
112   /* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
113   if (asprintf_nowarn (&cmd, "tar -C %R -cf - .", dir) == -1) {
114     reply_with_perror ("asprintf");
115     return -1;
116   }
117
118   if (verbose)
119     fprintf (stderr, "%s\n", cmd);
120
121   fp = popen (cmd, "r");
122   if (fp == NULL) {
123     reply_with_perror ("%s", cmd);
124     free (cmd);
125     return -1;
126   }
127   free (cmd);
128
129   /* Now we must send the reply message, before the file contents.  After
130    * this there is no opportunity in the protocol to send any error
131    * message back.  Instead we can only cancel the transfer.
132    */
133   reply (NULL, NULL);
134
135   while ((r = fread (buf, 1, sizeof buf, fp)) > 0) {
136     if (send_file_write (buf, r) < 0) {
137       pclose (fp);
138       return -1;
139     }
140   }
141
142   if (ferror (fp)) {
143     perror (dir);
144     send_file_end (1);          /* Cancel. */
145     pclose (fp);
146     return -1;
147   }
148
149   if (pclose (fp) != 0) {
150     perror (dir);
151     send_file_end (1);          /* Cancel. */
152     return -1;
153   }
154
155   send_file_end (0);            /* Normal end of file. */
156   return 0;
157 }
158
159 /* Has one FileIn parameter. */
160 int
161 do_tgz_in (char *dir)
162 {
163   int err, r;
164   FILE *fp;
165   char *cmd;
166
167   if (!root_mounted || dir[0] != '/') {
168     cancel_receive ();
169     reply_with_error ("tar-in: root must be mounted and path must be absolute");
170     return -1;
171   }
172
173   /* "tar -C /sysroot%s -zxf -" but we have to quote the dir. */
174   if (asprintf_nowarn (&cmd, "tar -C %R -zxf -", dir) == -1) {
175     err = errno;
176     cancel_receive ();
177     errno = err;
178     reply_with_perror ("asprintf");
179     return -1;
180   }
181
182   if (verbose)
183     fprintf (stderr, "%s\n", cmd);
184
185   fp = popen (cmd, "w");
186   if (fp == NULL) {
187     err = errno;
188     cancel_receive ();
189     errno = err;
190     reply_with_perror ("%s", cmd);
191     free (cmd);
192     return -1;
193   }
194   free (cmd);
195
196   r = receive_file (fwrite_cb, &fp);
197   if (r == -1) {                /* write error */
198     err = errno;
199     cancel_receive ();
200     errno = err;
201     reply_with_perror ("write: %s", dir);
202     pclose (fp);
203     return -1;
204   }
205   if (r == -2) {                /* cancellation from library */
206     pclose (fp);
207     /* Do NOT send any error. */
208     return -1;
209   }
210
211   if (pclose (fp) != 0) {
212     err = errno;
213     cancel_receive ();
214     errno = err;
215     reply_with_perror ("pclose: %s", dir);
216     return -1;
217   }
218
219   return 0;
220 }
221
222 /* Has one FileOut parameter. */
223 int
224 do_tgz_out (char *dir)
225 {
226   int r;
227   FILE *fp;
228   char *cmd;
229   char buf[GUESTFS_MAX_CHUNK_SIZE];
230
231   NEED_ROOT (-1);
232   ABS_PATH (dir, -1);
233
234   /* "tar -C /sysroot%s -zcf - ." but we have to quote the dir. */
235   if (asprintf_nowarn (&cmd, "tar -C %R -zcf - .", dir) == -1) {
236     reply_with_perror ("asprintf");
237     return -1;
238   }
239
240   if (verbose)
241     fprintf (stderr, "%s\n", cmd);
242
243   fp = popen (cmd, "r");
244   if (fp == NULL) {
245     reply_with_perror ("%s", cmd);
246     free (cmd);
247     return -1;
248   }
249   free (cmd);
250
251   /* Now we must send the reply message, before the file contents.  After
252    * this there is no opportunity in the protocol to send any error
253    * message back.  Instead we can only cancel the transfer.
254    */
255   reply (NULL, NULL);
256
257   while ((r = fread (buf, 1, sizeof buf, fp)) > 0) {
258     if (send_file_write (buf, r) < 0) {
259       pclose (fp);
260       return -1;
261     }
262   }
263
264   if (ferror (fp)) {
265     perror (dir);
266     send_file_end (1);          /* Cancel. */
267     pclose (fp);
268     return -1;
269   }
270
271   if (pclose (fp) != 0) {
272     perror (dir);
273     send_file_end (1);          /* Cancel. */
274     return -1;
275   }
276
277   send_file_end (0);            /* Normal end of file. */
278   return 0;
279 }