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