]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/restore.c
7e3da87f8c5f5c3bcfcaab5b8965f386bd8b78e0
[bacula/bacula] / bacula / src / filed / restore.c
1 /*
2  *  Bacula File Daemon  restore.c Restorefiles.
3  *
4  *    Kern Sibbald, November MM
5  *
6  */
7 /*
8    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2 of
13    the License, or (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public
21    License along with this program; if not, write to the Free
22    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23    MA 02111-1307, USA.
24
25  */
26
27 #include "bacula.h"
28 #include "filed.h"
29
30 /* Data received from Storage Daemon */
31 static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
32
33 /* Forward referenced functions */
34 static void print_ls_output(JCR *jcr, char *fname, char *lname, int type, struct stat *statp);
35
36 #define RETRY 10                      /* retry wait time */
37
38 /* 
39  * Restore the requested files.
40  * 
41  */
42 void do_restore(JCR *jcr, char *addr, int port)
43 {
44    int wherelen;
45    BSOCK *sd;
46    char *fname;                       /* original file name */
47    char *ofile;                       /* output name with possible prefix */
48    char *lname;                       /* link name */
49    int32_t stream;
50    uint32_t size;
51    uint32_t VolSessionId, VolSessionTime, file_index;
52    uint32_t record_file_index;
53    struct stat statp;
54    int extract = FALSE;
55    int ofd = -1;
56    int type;
57    uint32_t total = 0;
58    
59    wherelen = strlen(jcr->where);
60
61    sd = jcr->store_bsock;
62    jcr->JobStatus = JS_Running;
63
64    if (!bnet_set_buffer_size(sd, MAX_NETWORK_BUFFER_SIZE, BNET_SETBUF_READ)) {
65       return;
66    }
67
68    fname = (char *) get_pool_memory(PM_FNAME);
69    ofile = (char *) get_pool_memory(PM_FNAME);
70    lname = (char *) get_pool_memory(PM_FNAME);
71
72    /* 
73     * Get a record from the Storage daemon
74     */
75    while (bnet_recv(sd) > 0) {
76       /*
77        * First we expect a Stream Record Header 
78        */
79       if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index,
80           &stream, &size) != 5) {
81          Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg);
82          free_pool_memory(fname);
83          free_pool_memory(ofile);
84          free_pool_memory(lname);
85          return;
86       }
87       Dmsg2(30, "Got hdr: FilInx=%d Stream=%d.\n", file_index, stream);
88
89       /* 
90        * Now we expect the Stream Data
91        */
92       if (bnet_recv(sd) < 0) {
93          Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd));
94       }
95       if (size != ((uint32_t) sd->msglen)) {
96          Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size);
97          free_pool_memory(fname);
98          free_pool_memory(ofile);
99          free_pool_memory(lname);
100          return;
101       }
102       Dmsg1(30, "Got stream data, len=%d\n", sd->msglen);
103
104       /* File Attributes stream */
105       if (stream == STREAM_UNIX_ATTRIBUTES) {
106          char *ap, *lp;
107
108          Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
109          /* If extracting, it was from previous stream, so
110           * close the output file.
111           */
112          if (extract) {
113             if (ofd < 0) {
114                Emsg0(M_ABORT, 0, _("Logic error output file should be open\n"));
115             }
116             close(ofd);
117             ofd = -1;
118             extract = FALSE;
119             set_statp(jcr, fname, ofile, lname, type, &statp);
120             Dmsg0(30, "Stop extracting.\n");
121          }
122
123          if ((int)sizeof_pool_memory(fname) <  sd->msglen) {
124             fname = (char *) realloc_pool_memory(fname, sd->msglen + 1);
125          }
126          if (sizeof_pool_memory(ofile) < sizeof_pool_memory(fname) + wherelen + 1) {
127             ofile = (char *) realloc_pool_memory(ofile, sizeof_pool_memory(fname) + wherelen + 1);
128          }
129          if ((int)sizeof_pool_memory(lname) < sd->msglen) {
130             ofile = (char *) realloc_pool_memory(ofile, sd->msglen + 1);
131          }
132          *fname = 0;
133          *lname = 0;
134
135          /*              
136           * An Attributes record consists of:
137           *    File_index
138           *    Type   (FT_types)
139           *    Filename
140           *    Attributes
141           *    Link name (if file linked i.e. FT_LNK)
142           *
143           */
144          if (sscanf(sd->msg, "%d %d %s", &record_file_index, &type, fname) != 3) {
145             Emsg1(M_FATAL, 0, _("Error scanning record header: %s\n"), sd->msg);
146             /** ****FIXME**** need to cleanup */
147             Dmsg0(0, "\nError scanning header\n");
148             return;  
149          }
150          Dmsg3(30, "Got Attr: FilInx=%d type=%d fname=%s\n", record_file_index,
151             type, fname);
152          if (record_file_index != file_index) {
153             Emsg2(M_ABORT, 0, _("Record header file index %ld not equal record index %ld\n"),
154                file_index, record_file_index);
155             Dmsg0(0, "File index error\n");
156          }
157          ap = sd->msg;
158          /* Skip to attributes */
159          while (*ap++ != 0) {
160             ;
161          }
162          /* Skip to Link name */
163          if (type == FT_LNK) {
164             lp = ap;
165             while (*lp++ != 0) {
166                ;
167             }
168             strcat(lname, lp);        /* "save" link name */
169          } else {
170             *lname = 0;
171          }
172
173          decode_stat(ap, &statp);
174          /*
175           * Prepend the where directory so that the
176           * files are put where the user wants.
177           *
178           * We do a little jig here to handle Win32 files with
179           * a drive letter.  
180           *   If where is null and we are running on a win32 client,
181           *      change nothing.
182           *   Otherwise, if the second character of the filename is a
183           *   colon (:), change it into a slash (/) -- this creates
184           *   a reasonable pathname on most systems.
185           */
186          if (jcr->where[0] == 0 && win32_client) {
187             strcpy(ofile, fname);
188          } else {
189             strcpy(ofile, jcr->where);
190             if (fname[1] == ':') {
191                fname[1] = '/';
192                strcat(ofile, fname);
193                fname[1] = ':';
194             } else {
195                strcat(ofile, fname);
196             }
197          }
198
199          Dmsg1(30, "Outfile=%s\n", ofile);
200          print_ls_output(jcr, ofile, lname, type, &statp);
201
202          extract = create_file(jcr, fname, ofile, lname, type, &statp, &ofd);
203          Dmsg1(40, "Extract=%d\n", extract);
204          if (extract) {
205             jcr->JobFiles++;
206          }
207          jcr->num_files_examined++;
208
209       /* Data stream */
210       } else if (stream == STREAM_FILE_DATA) {
211          if (extract) {
212             Dmsg2(30, "Write %d bytes, total before write=%d\n", sd->msglen, total);
213             if (write(ofd, sd->msg, sd->msglen) != sd->msglen) {
214                Dmsg0(0, "===Write error===\n");
215                Jmsg2(jcr, M_ERROR, 0, "Write error on %s: %s\n", ofile, strerror(errno));
216                free_pool_memory(fname);
217                free_pool_memory(ofile);
218                free_pool_memory(lname);
219                return;
220             }
221             total += sd->msglen;
222             jcr->JobBytes += sd->msglen;
223          }
224
225       /* If extracting, wierd stream (not 1 or 2), close output file anyway */
226       } else if (extract) {
227          Dmsg1(30, "Found wierd stream %d\n", stream);
228          if (ofd < 0) {
229             Emsg0(M_ABORT, 0, _("Logic error output file should be open\n"));
230          }
231          close(ofd);
232          ofd = -1;
233          extract = FALSE;
234          set_statp(jcr, fname, ofile, lname, type, &statp);
235       } else if (stream != STREAM_MD5_SIGNATURE) {
236          Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
237       }
238    }
239
240    /* If output file is still open, it was the last one in the
241     * archive since we just hit an end of file, so close the file. 
242     */
243    if (ofd >= 0) {
244       close(ofd);
245       set_statp(jcr, fname, ofile, lname, type, &statp);
246    }
247
248    free_pool_memory(fname);
249    free_pool_memory(ofile);
250    free_pool_memory(lname);
251    Dmsg2(10, "End Do Restore. Files=%d Bytes=%" lld "\n", jcr->JobFiles,
252       jcr->JobBytes);
253 }          
254
255 extern char *getuser(uid_t uid);
256 extern char *getgroup(gid_t gid);
257
258 /*
259  * Print an ls style message, also send INFO
260  */
261 static void print_ls_output(JCR *jcr, char *fname, char *lname, int type, struct stat *statp)
262 {
263    /* ********FIXME******** make memory pool */
264    char buf[1000]; 
265    char *p, *f;
266    int n;
267
268    p = encode_mode(statp->st_mode, buf);
269    n = sprintf(p, "  %2d ", (uint32_t)statp->st_nlink);
270    p += n;
271    n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid));
272    p += n;
273    n = sprintf(p, "%8" lld " ", (uint64_t)statp->st_size);
274    p += n;
275    p = encode_time(statp->st_ctime, p);
276    *p++ = ' ';
277    *p++ = ' ';
278    for (f=fname; *f; )
279       *p++ = *f++;
280    if (type == FT_LNK) {
281       *p++ = ' ';
282       *p++ = '-';
283       *p++ = '>';
284       *p++ = ' ';
285       /* Copy link name */
286       for (f=lname; *f; )
287          *p++ = *f++;
288    }
289    *p++ = '\n';
290    *p = 0;
291    Dmsg0(20, buf);
292    Jmsg(jcr, M_INFO, 0, buf);
293 }