2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * attr.c Unpack an Attribute record returned from the tape
22 * Kern Sibbald, June MMIII (code pulled from filed/restore.c and updated)
31 static const int dbglvl = 150;
33 ATTR *new_attr(JCR *jcr)
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);
45 void free_attr(ATTR *attr)
47 free_pool_memory(attr->olname);
48 free_pool_memory(attr->ofname);
49 free_pool_memory(attr->attrEx);
53 int unpack_attributes_record(JCR *jcr, int32_t stream, char *rec, int32_t reclen, ATTR *attr)
58 * An Attributes record consists of:
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
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);
76 Dmsg2(dbglvl, "Got Attr: FilInx=%d type=%d\n", attr->file_index, attr->type);
78 * Note AR_DATA_STREAM should never be set since it is encoded
79 * at the end of the attributes.
81 if (attr->type & AR_DATA_STREAM) {
82 attr->data_stream = 1;
84 attr->data_stream = 0;
86 attr->type &= FT_MASK; /* keep only type bits */
88 while (*p++ != ' ') /* skip record file index */
90 while (*p++ != ' ') /* skip type */
93 attr->fname = p; /* set filename position */
94 while (*p++ != 0) /* skip filename */
96 attr->attr = p; /* set attributes position */
97 while (*p++ != 0) /* skip attributes */
99 attr->lname = p; /* set link position */
100 while (*p++ != 0) /* skip link */
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;
112 pm_strcpy(attr->attrEx, p); /* copy extended attributes, if any */
113 if (attr->data_stream) {
115 while (*p++ != 0) /* skip extended attributes */
117 from_base64(&val, p);
118 attr->data_stream = (int32_t)val;
120 while (*p++ != 0) /* skip extended attributes */
122 if (p - rec < reclen) {
123 attr->delta_seq = str_to_int32(p); /* delta_seq */
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);
135 #if defined(HAVE_WIN32)
136 static void strip_double_slashes(char *fname)
140 p = strpbrk(p, "/\\");
142 if (IsPathSeparator(p[1])) {
152 * Build attr->ofname from attr->fname and
153 * attr->olname from attr->olname
155 void build_attr_output_fnames(JCR *jcr, ATTR *attr)
158 * Prepend the where directory so that the
159 * files are put where the user wants.
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.
168 if (jcr->where_bregexp) {
170 apply_bregexps(attr->fname, jcr->where_bregexp, &ret);
171 pm_strcpy(attr->ofname, ret);
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
178 if ((attr->type == FT_LNKSAVED || jcr->prefix_links)) {
179 apply_bregexps(attr->lname, jcr->where_bregexp, &ret);
180 pm_strcpy(attr->olname, ret);
183 pm_strcpy(attr->olname, attr->lname);
187 } else if (jcr->where[0] == 0) {
188 pm_strcpy(attr->ofname, attr->fname);
189 pm_strcpy(attr->olname, attr->lname);
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 / */
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, "/");
205 pm_strcat(attr->ofname, fn); /* copy rest of name */
207 * Fixup link name -- if it is an absolute path
209 if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
211 /* Always add prefix to hard links (FT_LNKSAVED) and
212 * on user request to soft links
214 if (IsPathSeparator(attr->lname[0]) &&
215 (attr->type == FT_LNKSAVED || jcr->prefix_links)) {
216 pm_strcpy(attr->olname, jcr->where);
223 #if defined(HAVE_WIN32)
224 if (attr->lname[1] == ':') {
225 attr->lname[1] = '/'; /* turn : into / */
228 fn = attr->lname; /* take whole name */
229 /* Ensure where is terminated with a slash */
231 !IsPathSeparator(jcr->where[wherelen-1]) &&
232 !IsPathSeparator(fn[0])) {
233 pm_strcat(attr->olname, "/");
235 pm_strcat(attr->olname, fn); /* copy rest of link */
238 #if defined(HAVE_WIN32)
239 strip_double_slashes(attr->ofname);
240 strip_double_slashes(attr->olname);
244 extern char *getuser(uid_t uid, char *name, int len);
245 extern char *getgroup(gid_t gid, char *name, int len);
248 * Print an ls style message, also send M_RESTORED
250 void print_ls_output(JCR *jcr, ATTR *attr)
254 char en1[30], en2[30];
258 if (attr->type == FT_DELETED) { /* TODO: change this to get last seen values */
259 bsnprintf(buf, sizeof(buf),
260 "---------- - - - - ---------- -------- %s\n", attr->ofname);
261 Dmsg1(dbglvl, "%s", buf);
262 Jmsg(jcr, M_RESTORED, 1, "%s", buf);
267 jcr->id_list = new_guid_list();
270 p = encode_mode(attr->statp.st_mode, buf);
271 p += sprintf(p, " %2d ", (uint32_t)attr->statp.st_nlink);
272 p += sprintf(p, "%-8.8s %-8.8s",
273 guid->uid_to_name(attr->statp.st_uid, en1, sizeof(en1)),
274 guid->gid_to_name(attr->statp.st_gid, en2, sizeof(en2)));
275 p += sprintf(p, "%12.12s ", edit_int64(attr->statp.st_size, ec1));
276 p = encode_time(attr->statp.st_ctime, p);
279 for (f=attr->ofname; *f && (p-buf) < (int)sizeof(buf)-10; ) {
282 if (attr->type == FT_LNK) {
288 for (f=attr->olname; *f && (p-buf) < (int)sizeof(buf)-10; ) {
294 Dmsg1(dbglvl, "%s", buf);
295 Jmsg(jcr, M_RESTORED, 1, "%s", buf);