1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2003-2011 Free Software Foundation Europe e.V.
5    Copyright (C) 2016-2018 Bareos GmbH & Co. KG
6 
7    This program is Free Software; you can redistribute it and/or
8    modify it under the terms of version three of the GNU Affero General Public
9    License as published by the Free Software Foundation and included
10    in the file LICENSE.
11 
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15    Affero General Public License for more details.
16 
17    You should have received a copy of the GNU Affero General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301, USA.
21 */
22 /*
23  * Kern Sibbald, June MMIII  (code pulled from filed/restore.c and updated)
24  */
25 /**
26  * @file
27  * attr.c  Unpack an Attribute record returned from the tape
28  */
29 
30 #include "include/bareos.h"
31 #include "include/jcr.h"
32 #include "lib/breg.h"
33 #include "lib/edit.h"
34 #include "lib/util.h"
35 
36 static const int debuglevel = 150;
37 
new_attr(JobControlRecord * jcr)38 Attributes* new_attr(JobControlRecord* jcr)
39 {
40   Attributes* attr = (Attributes*)malloc(sizeof(Attributes));
41   memset(attr, 0, sizeof(Attributes));
42   attr->ofname = GetPoolMemory(PM_FNAME);
43   attr->olname = GetPoolMemory(PM_FNAME);
44   attr->attrEx = GetPoolMemory(PM_FNAME);
45   attr->jcr = jcr;
46   attr->uid = getuid();
47   return attr;
48 }
49 
FreeAttr(Attributes * attr)50 void FreeAttr(Attributes* attr)
51 {
52   FreePoolMemory(attr->olname);
53   FreePoolMemory(attr->ofname);
54   FreePoolMemory(attr->attrEx);
55   free(attr);
56 }
57 
UnpackAttributesRecord(JobControlRecord * jcr,int32_t stream,char * rec,int32_t reclen,Attributes * attr)58 int UnpackAttributesRecord(JobControlRecord* jcr,
59                            int32_t stream,
60                            char* rec,
61                            int32_t reclen,
62                            Attributes* attr)
63 {
64   char* p;
65   int object_len;
66   /*
67    * An Attributes record consists of:
68    *    File_index
69    *    Type   (FT_types)
70    *    Filename
71    *    Attributes
72    *    Link name (if file linked i.e. FT_LNK)
73    *    Extended attributes (Win32)
74    *  plus optional values determined by AR_ flags in upper bits of Type
75    *    Data_stream
76    *
77    */
78   attr->stream = stream;
79   Dmsg1(debuglevel, "Attr: %s\n", rec);
80   if (sscanf(rec, "%d %d", &attr->file_index, &attr->type) != 2) {
81     Jmsg(jcr, M_FATAL, 0, _("Error scanning attributes: %s\n"), rec);
82     Dmsg1(debuglevel, "\nError scanning attributes. %s\n", rec);
83     return 0;
84   }
85   Dmsg2(debuglevel, "Got Attr: FilInx=%d type=%d\n", attr->file_index,
86         attr->type);
87   /*
88    * Note AR_DATA_STREAM should never be set since it is encoded
89    *  at the end of the attributes.
90    */
91   if (attr->type & AR_DATA_STREAM) {
92     attr->data_stream = 1;
93   } else {
94     attr->data_stream = 0;
95   }
96   attr->type &= FT_MASK; /* keep only type bits */
97   p = rec;
98   while (*p++ != ' ') /* skip record file index */
99   {}
100   while (*p++ != ' ') /* skip type */
101   {}
102 
103   attr->fname = p;  /* set filname position */
104   while (*p++ != 0) /* skip filename */
105   {}
106   attr->attr = p;   /* set attributes position */
107   while (*p++ != 0) /* skip attributes */
108   {}
109   attr->lname = p;  /* set link position */
110   while (*p++ != 0) /* skip link */
111   {}
112   attr->delta_seq = 0;
113   if (attr->type == FT_RESTORE_FIRST) {
114     /* We have an object, so do a binary copy */
115     object_len = reclen + rec - p;
116     attr->attrEx = CheckPoolMemorySize(attr->attrEx, object_len + 1);
117     memcpy(attr->attrEx, p, object_len);
118     /* Add a EOS for those who attempt to print the object */
119     p = attr->attrEx + object_len;
120     *p = 0;
121   } else {
122     PmStrcpy(attr->attrEx, p); /* copy extended attributes, if any */
123     if (attr->data_stream) {
124       int64_t val;
125       while (*p++ != 0) /* skip extended attributes */
126       {}
127       FromBase64(&val, p);
128       attr->data_stream = (int32_t)val;
129     } else {
130       while (*p++ != 0) /* skip extended attributes */
131       {}
132       if (p - rec < reclen) {
133         attr->delta_seq = str_to_int32(p); /* delta_seq */
134       }
135     }
136   }
137   Dmsg8(debuglevel,
138         "unpack_attr FI=%d Type=%d fname=%s attr=%s lname=%s attrEx=%s "
139         "datastr=%d delta_seq=%d\n",
140         attr->file_index, attr->type, attr->fname, attr->attr, attr->lname,
141         attr->attrEx, attr->data_stream, attr->delta_seq);
142   *attr->ofname = 0;
143   *attr->olname = 0;
144   return 1;
145 }
146 
147 #if defined(HAVE_WIN32)
StripDoubleSlashes(char * fname)148 static void StripDoubleSlashes(char* fname)
149 {
150   char* p = fname;
151   while (p && *p) {
152     p = strpbrk(p, "/\\");
153     if (p != NULL) {
154       if (IsPathSeparator(p[1])) { strcpy(p, p + 1); }
155       p++;
156     }
157   }
158 }
159 #endif
160 
161 /**
162  * Build attr->ofname from attr->fname and
163  *       attr->olname from attr->olname
164  */
BuildAttrOutputFnames(JobControlRecord * jcr,Attributes * attr)165 void BuildAttrOutputFnames(JobControlRecord* jcr, Attributes* attr)
166 {
167   /*
168    * Prepend the where directory so that the
169    * files are put where the user wants.
170    *
171    * We do a little jig here to handle Win32 files with
172    *   a drive letter -- we simply change the drive
173    *   from, for example, c: to c/ for
174    *   every filename if a prefix is supplied.
175    *
176    */
177 
178   if (jcr->where_bregexp) {
179     char* ret;
180     ApplyBregexps(attr->fname, jcr->where_bregexp, &ret);
181     PmStrcpy(attr->ofname, ret);
182 
183     if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
184       /* Always add prefix to hard links (FT_LNKSAVED) and
185        *  on user request to soft links
186        */
187 
188       if ((attr->type == FT_LNKSAVED || jcr->prefix_links)) {
189         ApplyBregexps(attr->lname, jcr->where_bregexp, &ret);
190         PmStrcpy(attr->olname, ret);
191 
192       } else {
193         PmStrcpy(attr->olname, attr->lname);
194       }
195     }
196 
197   } else if (jcr->where[0] == 0) {
198     PmStrcpy(attr->ofname, attr->fname);
199     PmStrcpy(attr->olname, attr->lname);
200 
201   } else {
202     const char* fn;
203     int wherelen = strlen(jcr->where);
204     PmStrcpy(attr->ofname, jcr->where); /* copy prefix */
205 #if defined(HAVE_WIN32)
206     if (attr->fname[1] == ':') { attr->fname[1] = '/'; /* convert : to / */ }
207 #endif
208     fn = attr->fname; /* take whole name */
209     /* Ensure where is terminated with a slash */
210     if (!IsPathSeparator(jcr->where[wherelen - 1]) && !IsPathSeparator(fn[0])) {
211       PmStrcat(attr->ofname, "/");
212     }
213     PmStrcat(attr->ofname, fn); /* copy rest of name */
214     /*
215      * Fixup link name -- if it is an absolute path
216      */
217     if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
218       bool add_link;
219       /* Always add prefix to hard links (FT_LNKSAVED) and
220        *  on user request to soft links
221        */
222       if (IsPathSeparator(attr->lname[0])
223           && (attr->type == FT_LNKSAVED || jcr->prefix_links)) {
224         PmStrcpy(attr->olname, jcr->where);
225         add_link = true;
226       } else {
227         attr->olname[0] = 0;
228         add_link = false;
229       }
230       fn = attr->lname; /* take whole name */
231       /* Ensure where is terminated with a slash */
232       if (add_link && !IsPathSeparator(jcr->where[wherelen - 1])
233           && !IsPathSeparator(fn[0])) {
234         PmStrcat(attr->olname, "/");
235       }
236       PmStrcat(attr->olname, fn); /* copy rest of link */
237     }
238   }
239 #if defined(HAVE_WIN32)
240   StripDoubleSlashes(attr->ofname);
241   StripDoubleSlashes(attr->olname);
242 #endif
243 }
244 
245 extern char* getuser(uid_t uid, char* name, int len);
246 extern char* getgroup(gid_t gid, char* name, int len);
247 
attr_stat_to_str(PoolMem & resultbuffer,JobControlRecord * jcr,Attributes * attr)248 static const char* attr_stat_to_str(PoolMem& resultbuffer,
249                                     JobControlRecord* jcr,
250                                     Attributes* attr)
251 {
252   char buf[5000];
253   char ec1[30];
254   char en1[30], en2[30];
255   char* p;
256   guid_list* guid;
257 
258   if (attr->type
259       == FT_DELETED) { /* TODO: change this to get last seen values */
260     resultbuffer.strcat(
261         "----------   - -        -                - ---------- --------");
262     return resultbuffer.c_str();
263   }
264 
265   if (!jcr->id_list) { jcr->id_list = new_guid_list(); }
266   guid = jcr->id_list;
267   p = encode_mode(attr->statp.st_mode, buf);
268   p += sprintf(p, "  %2d ", (uint32_t)attr->statp.st_nlink);
269   p += sprintf(p, "%-8.8s %-8.8s",
270                guid->uid_to_name(attr->statp.st_uid, en1, sizeof(en1)),
271                guid->gid_to_name(attr->statp.st_gid, en2, sizeof(en2)));
272   p += sprintf(p, "%12.12s ", edit_int64(attr->statp.st_size, ec1));
273   p = encode_time(attr->statp.st_ctime, p);
274 
275   resultbuffer.strcat(buf);
276   return resultbuffer.c_str();
277 }
278 
attr_file_to_str(PoolMem & resultbuffer,Attributes * attr)279 static const char* attr_file_to_str(PoolMem& resultbuffer, Attributes* attr)
280 {
281   resultbuffer.strcat(attr->ofname);
282   if (attr->type == FT_LNK) {
283     resultbuffer.strcat(" -> ");
284     resultbuffer.strcat(attr->olname);
285   }
286   return resultbuffer.c_str();
287 }
288 
289 
attr_to_str(PoolMem & resultbuffer,JobControlRecord * jcr,Attributes * attr)290 const char* attr_to_str(PoolMem& resultbuffer,
291                         JobControlRecord* jcr,
292                         Attributes* attr)
293 {
294   attr_stat_to_str(resultbuffer, jcr, attr);
295   resultbuffer.strcat("\n");
296   attr_file_to_str(resultbuffer, attr);
297 
298   return resultbuffer.c_str();
299 }
300 
301 
attr_to_ls_output(PoolMem & resultbuffer,JobControlRecord * jcr,Attributes * attr)302 static const char* attr_to_ls_output(PoolMem& resultbuffer,
303                                      JobControlRecord* jcr,
304                                      Attributes* attr)
305 {
306   attr_stat_to_str(resultbuffer, jcr, attr);
307   resultbuffer.strcat("  ");
308   attr_file_to_str(resultbuffer, attr);
309   resultbuffer.strcat("\n");
310 
311   return resultbuffer.c_str();
312 }
313 
314 /**
315  * Print an ls style message, also send M_RESTORED
316  */
PrintLsOutput(JobControlRecord * jcr,Attributes * attr)317 void PrintLsOutput(JobControlRecord* jcr, Attributes* attr)
318 {
319   PoolMem resultbuffer(PM_MESSAGE);
320   attr_to_ls_output(resultbuffer, jcr, attr);
321   Dmsg1(debuglevel, "%s", resultbuffer.c_str());
322   Jmsg(jcr, M_RESTORED, 1, "%s", resultbuffer.c_str());
323 }
324