1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * attr.c Unpack an Attribute record returned from the tape
21 *
22 * Kern Sibbald, June MMIII (code pulled from filed/restore.c and updated)
23 *
24 */
25
26
27 #include "bacula.h"
28 #include "jcr.h"
29 #include "lib/breg.h"
30
31 static const int dbglvl = 150;
32
new_attr(JCR * jcr)33 ATTR *new_attr(JCR *jcr)
34 {
35 ATTR *attr = (ATTR *)malloc(sizeof(ATTR));
36 memset(attr, 0, sizeof(ATTR));
37 attr->ofname = get_pool_memory(PM_FNAME);
38 attr->olname = get_pool_memory(PM_FNAME);
39 attr->attrEx = get_pool_memory(PM_FNAME);
40 attr->jcr = jcr;
41 attr->uid = getuid();
42 return attr;
43 }
44
free_attr(ATTR * attr)45 void free_attr(ATTR *attr)
46 {
47 free_pool_memory(attr->olname);
48 free_pool_memory(attr->ofname);
49 free_pool_memory(attr->attrEx);
50 free(attr);
51 }
52
unpack_attributes_record(JCR * jcr,int32_t stream,char * rec,int32_t reclen,ATTR * attr)53 int unpack_attributes_record(JCR *jcr, int32_t stream, char *rec, int32_t reclen, ATTR *attr)
54 {
55 char *p;
56 int object_len;
57 /*
58 * An Attributes record consists of:
59 * File_index
60 * Type (FT_types)
61 * Filename
62 * Attributes
63 * Link name (if file linked i.e. FT_LNK)
64 * Extended attributes (Win32)
65 * plus optional values determined by AR_ flags in upper bits of Type
66 * Data_stream
67 *
68 */
69 attr->stream = stream;
70 Dmsg1(dbglvl, "Attr: %s\n", rec);
71 if (sscanf(rec, "%d %d", &attr->file_index, &attr->type) != 2) {
72 Jmsg(jcr, M_FATAL, 0, _("Error scanning attributes: %s\n"), rec);
73 Dmsg1(dbglvl, "\nError scanning attributes. %s\n", rec);
74 return 0;
75 }
76 Dmsg2(dbglvl, "Got Attr: FilInx=%d type=%d\n", attr->file_index, attr->type);
77 /*
78 * Note AR_DATA_STREAM should never be set since it is encoded
79 * at the end of the attributes.
80 */
81 if (attr->type & AR_DATA_STREAM) {
82 attr->data_stream = 1;
83 } else {
84 attr->data_stream = 0;
85 }
86 attr->type &= FT_MASK; /* keep only type bits */
87 p = rec;
88 while (*p++ != ' ') /* skip record file index */
89 { }
90 while (*p++ != ' ') /* skip type */
91 { }
92
93 attr->fname = p; /* set filename position */
94 while (*p++ != 0) /* skip filename */
95 { }
96 attr->attr = p; /* set attributes position */
97 while (*p++ != 0) /* skip attributes */
98 { }
99 attr->lname = p; /* set link position */
100 while (*p++ != 0) /* skip link */
101 { }
102 attr->delta_seq = 0;
103 if (attr->type == FT_RESTORE_FIRST) {
104 /* We have an object, so do a binary copy */
105 object_len = reclen + rec - p;
106 attr->attrEx = check_pool_memory_size(attr->attrEx, object_len + 1);
107 memcpy(attr->attrEx, p, object_len);
108 /* Add a EOS for those who attempt to print the object */
109 p = attr->attrEx + object_len;
110 *p = 0;
111 } else {
112 pm_strcpy(attr->attrEx, p); /* copy extended attributes, if any */
113 if (attr->data_stream) {
114 int64_t val;
115 while (*p++ != 0) /* skip extended attributes */
116 { }
117 from_base64(&val, p);
118 attr->data_stream = (int32_t)val;
119 } else {
120 while (*p++ != 0) /* skip extended attributes */
121 { }
122 if (p - rec < reclen) {
123 attr->delta_seq = str_to_int32(p); /* delta_seq */
124 }
125 }
126 }
127 Dmsg8(dbglvl, "unpack_attr FI=%d Type=%d fname=%s attr=%s lname=%s attrEx=%s datastr=%d delta_seq=%d\n",
128 attr->file_index, attr->type, attr->fname, attr->attr, attr->lname,
129 attr->attrEx, attr->data_stream, attr->delta_seq);
130 *attr->ofname = 0;
131 *attr->olname = 0;
132 return 1;
133 }
134
135 #if defined(HAVE_WIN32)
strip_double_slashes(char * fname)136 static void strip_double_slashes(char *fname)
137 {
138 char *p = fname;
139 while (p && *p) {
140 p = strpbrk(p, "/\\");
141 if (p != NULL) {
142 if (IsPathSeparator(p[1])) {
143 strcpy(p, p+1);
144 }
145 p++;
146 }
147 }
148 }
149 #endif
150
151 /*
152 * Build attr->ofname from attr->fname and
153 * attr->olname from attr->olname
154 */
build_attr_output_fnames(JCR * jcr,ATTR * attr)155 void build_attr_output_fnames(JCR *jcr, ATTR *attr)
156 {
157 /*
158 * Prepend the where directory so that the
159 * files are put where the user wants.
160 *
161 * We do a little jig here to handle Win32 files with
162 * a drive letter -- we simply change the drive
163 * from, for example, c: to c/ for
164 * every filename if a prefix is supplied.
165 *
166 */
167
168 if (jcr->where_bregexp) {
169 char *ret;
170 apply_bregexps(attr->fname, &attr->statp, jcr->where_bregexp, &ret);
171 pm_strcpy(attr->ofname, ret);
172
173 if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
174 /* Always add prefix to hard links (FT_LNKSAVED) and
175 * on user request to soft links
176 */
177
178 if ((attr->type == FT_LNKSAVED || jcr->prefix_links)) {
179 apply_bregexps(attr->lname, &attr->statp, jcr->where_bregexp, &ret);
180 pm_strcpy(attr->olname, ret);
181
182 } else {
183 pm_strcpy(attr->olname, attr->lname);
184 }
185 }
186
187 } else if (jcr->where[0] == 0) {
188 pm_strcpy(attr->ofname, attr->fname);
189 pm_strcpy(attr->olname, attr->lname);
190
191 } else {
192 const char *fn;
193 int wherelen = strlen(jcr->where);
194 pm_strcpy(attr->ofname, jcr->where); /* copy prefix */
195 #if defined(HAVE_WIN32)
196 if (attr->fname[1] == ':') {
197 attr->fname[1] = '/'; /* convert : to / */
198 }
199 #endif
200 fn = attr->fname; /* take whole name */
201 /* Ensure where is terminated with a slash */
202 if (!IsPathSeparator(jcr->where[wherelen-1]) && !IsPathSeparator(fn[0])) {
203 pm_strcat(attr->ofname, "/");
204 }
205 pm_strcat(attr->ofname, fn); /* copy rest of name */
206 /*
207 * Fixup link name -- if it is an absolute path
208 */
209 if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
210 bool add_link;
211 /* Always add prefix to hard links (FT_LNKSAVED) and
212 * on user request to soft links
213 */
214 if (IsPathSeparator(attr->lname[0]) &&
215 (attr->type == FT_LNKSAVED || jcr->prefix_links)) {
216 pm_strcpy(attr->olname, jcr->where);
217 add_link = true;
218 } else {
219 attr->olname[0] = 0;
220 add_link = false;
221 }
222
223 #if defined(HAVE_WIN32)
224 if (attr->lname[1] == ':') {
225 attr->lname[1] = '/'; /* turn : into / */
226 }
227 #endif
228 fn = attr->lname; /* take whole name */
229 /* Ensure where is terminated with a slash */
230 if (add_link &&
231 !IsPathSeparator(jcr->where[wherelen-1]) &&
232 !IsPathSeparator(fn[0])) {
233 pm_strcat(attr->olname, "/");
234 }
235 pm_strcat(attr->olname, fn); /* copy rest of link */
236 }
237 }
238 #if defined(HAVE_WIN32)
239 strip_double_slashes(attr->ofname);
240 strip_double_slashes(attr->olname);
241 #endif
242 }
243
244 extern char *getuser(uid_t uid, char *name, int len);
245 extern char *getgroup(gid_t gid, char *name, int len);
246
247 /*
248 * Print an ls style message, also send M_RESTORED/M_SAVED
249 */
print_ls_output(JCR * jcr,ATTR * attr,int message_type)250 void print_ls_output(JCR *jcr, ATTR *attr, int message_type /* M_RESTORED */)
251 {
252 char buf[5000];
253 char ec1[30];
254 char en1[30], en2[30];
255 char *p, *f;
256 guid_list *guid;
257
258 /* No need to compute everything if it's not required */
259 if (!chk_dbglvl(dbglvl) && !is_message_type_set(jcr, message_type)) {
260 return;
261 }
262
263 if (attr->type == FT_DELETED) { /* TODO: change this to get last seen values */
264 bsnprintf(buf, sizeof(buf),
265 "-*DELETED- - - - - ---------- -------- %s\n", attr->ofname);
266 Dmsg1(dbglvl, "%s", buf);
267 Jmsg(jcr, message_type, 1, "%s", buf);
268 return;
269 }
270
271 if (!jcr->id_list) {
272 jcr->id_list = new_guid_list();
273 }
274 guid = jcr->id_list;
275 p = encode_mode(attr->statp.st_mode, buf);
276 p += sprintf(p, " %2d ", (uint32_t)attr->statp.st_nlink);
277 p += sprintf(p, "%-8.8s %-8.8s",
278 guid->uid_to_name(attr->statp.st_uid, en1, sizeof(en1)),
279 guid->gid_to_name(attr->statp.st_gid, en2, sizeof(en2)));
280 p += sprintf(p, " %18.18s ", edit_int64(attr->statp.st_size, ec1));
281 p = encode_time(attr->statp.st_ctime, p);
282 *p++ = ' ';
283 *p++ = ' ';
284 for (f=attr->ofname; *f && (p-buf) < (int)sizeof(buf)-10; ) {
285 *p++ = *f++;
286 }
287 if (attr->type == FT_LNK) {
288 *p++ = ' ';
289 *p++ = '-';
290 *p++ = '>';
291 *p++ = ' ';
292 /* Copy link name */
293 for (f=attr->olname; *f && (p-buf) < (int)sizeof(buf)-10; ) {
294 *p++ = *f++;
295 }
296 }
297 *p++ = '\n';
298 *p = 0;
299 Dmsg1(dbglvl, "%s", buf);
300 Jmsg(jcr, message_type, 1, "%s", buf);
301 }
302