2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2003-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * attr.c Unpack an Attribute record returned from the tape
23 * Kern Sibbald, June MMIII (code pulled from filed/restore.c and updated)
32 static const int dbglvl = 150;
34 ATTR *new_attr(JCR *jcr)
36 ATTR *attr = (ATTR *)malloc(sizeof(ATTR));
37 memset(attr, 0, sizeof(ATTR));
38 attr->ofname = get_pool_memory(PM_FNAME);
39 attr->olname = get_pool_memory(PM_FNAME);
40 attr->attrEx = get_pool_memory(PM_FNAME);
46 void free_attr(ATTR *attr)
48 free_pool_memory(attr->olname);
49 free_pool_memory(attr->ofname);
50 free_pool_memory(attr->attrEx);
54 int unpack_attributes_record(JCR *jcr, int32_t stream, char *rec, int32_t reclen, ATTR *attr)
59 * An Attributes record consists of:
64 * Link name (if file linked i.e. FT_LNK)
65 * Extended attributes (Win32)
66 * plus optional values determined by AR_ flags in upper bits of Type
70 attr->stream = stream;
71 Dmsg1(dbglvl, "Attr: %s\n", rec);
72 if (sscanf(rec, "%d %d", &attr->file_index, &attr->type) != 2) {
73 Jmsg(jcr, M_FATAL, 0, _("Error scanning attributes: %s\n"), rec);
74 Dmsg1(dbglvl, "\nError scanning attributes. %s\n", rec);
77 Dmsg2(dbglvl, "Got Attr: FilInx=%d type=%d\n", attr->file_index, attr->type);
79 * Note AR_DATA_STREAM should never be set since it is encoded
80 * at the end of the attributes.
82 if (attr->type & AR_DATA_STREAM) {
83 attr->data_stream = 1;
85 attr->data_stream = 0;
87 attr->type &= FT_MASK; /* keep only type bits */
89 while (*p++ != ' ') /* skip record file index */
91 while (*p++ != ' ') /* skip type */
94 attr->fname = p; /* set filename position */
95 while (*p++ != 0) /* skip filename */
97 attr->attr = p; /* set attributes position */
98 while (*p++ != 0) /* skip attributes */
100 attr->lname = p; /* set link position */
101 while (*p++ != 0) /* skip link */
104 if (attr->type == FT_RESTORE_FIRST) {
105 /* We have an object, so do a binary copy */
106 object_len = reclen + rec - p;
107 attr->attrEx = check_pool_memory_size(attr->attrEx, object_len + 1);
108 memcpy(attr->attrEx, p, object_len);
109 /* Add a EOS for those who attempt to print the object */
110 p = attr->attrEx + object_len;
113 pm_strcpy(attr->attrEx, p); /* copy extended attributes, if any */
114 if (attr->data_stream) {
116 while (*p++ != 0) /* skip extended attributes */
118 from_base64(&val, p);
119 attr->data_stream = (int32_t)val;
121 while (*p++ != 0) /* skip extended attributes */
123 if (p - rec < reclen) {
124 attr->delta_seq = str_to_int32(p); /* delta_seq */
128 Dmsg8(dbglvl, "unpack_attr FI=%d Type=%d fname=%s attr=%s lname=%s attrEx=%s datastr=%d delta_seq=%d\n",
129 attr->file_index, attr->type, attr->fname, attr->attr, attr->lname,
130 attr->attrEx, attr->data_stream, attr->delta_seq);
136 #if defined(HAVE_WIN32)
137 static void strip_double_slashes(char *fname)
141 p = strpbrk(p, "/\\");
143 if (IsPathSeparator(p[1])) {
153 * Build attr->ofname from attr->fname and
154 * attr->olname from attr->olname
156 void build_attr_output_fnames(JCR *jcr, ATTR *attr)
159 * Prepend the where directory so that the
160 * files are put where the user wants.
162 * We do a little jig here to handle Win32 files with
163 * a drive letter -- we simply change the drive
164 * from, for example, c: to c/ for
165 * every filename if a prefix is supplied.
169 if (jcr->where_bregexp) {
171 apply_bregexps(attr->fname, jcr->where_bregexp, &ret);
172 pm_strcpy(attr->ofname, ret);
174 if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
175 /* Always add prefix to hard links (FT_LNKSAVED) and
176 * on user request to soft links
179 if ((attr->type == FT_LNKSAVED || jcr->prefix_links)) {
180 apply_bregexps(attr->lname, jcr->where_bregexp, &ret);
181 pm_strcpy(attr->olname, ret);
184 pm_strcpy(attr->olname, attr->lname);
188 } else if (jcr->where[0] == 0) {
189 pm_strcpy(attr->ofname, attr->fname);
190 pm_strcpy(attr->olname, attr->lname);
194 int wherelen = strlen(jcr->where);
195 pm_strcpy(attr->ofname, jcr->where); /* copy prefix */
196 #if defined(HAVE_WIN32)
197 if (attr->fname[1] == ':') {
198 attr->fname[1] = '/'; /* convert : to / */
201 fn = attr->fname; /* take whole name */
202 /* Ensure where is terminated with a slash */
203 if (!IsPathSeparator(jcr->where[wherelen-1]) && !IsPathSeparator(fn[0])) {
204 pm_strcat(attr->ofname, "/");
206 pm_strcat(attr->ofname, fn); /* copy rest of name */
208 * Fixup link name -- if it is an absolute path
210 if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
212 /* Always add prefix to hard links (FT_LNKSAVED) and
213 * on user request to soft links
215 if (IsPathSeparator(attr->lname[0]) &&
216 (attr->type == FT_LNKSAVED || jcr->prefix_links)) {
217 pm_strcpy(attr->olname, jcr->where);
224 #if defined(HAVE_WIN32)
225 if (attr->lname[1] == ':') {
226 attr->lname[1] = '/'; /* turn : into / */
229 fn = attr->lname; /* take whole name */
230 /* Ensure where is terminated with a slash */
232 !IsPathSeparator(jcr->where[wherelen-1]) &&
233 !IsPathSeparator(fn[0])) {
234 pm_strcat(attr->olname, "/");
236 pm_strcat(attr->olname, fn); /* copy rest of link */
239 #if defined(HAVE_WIN32)
240 strip_double_slashes(attr->ofname);
241 strip_double_slashes(attr->olname);
245 extern char *getuser(uid_t uid, char *name, int len);
246 extern char *getgroup(gid_t gid, char *name, int len);
249 * Print an ls style message, also send M_RESTORED
251 void print_ls_output(JCR *jcr, ATTR *attr)
255 char en1[30], en2[30];
259 if (attr->type == FT_DELETED) { /* TODO: change this to get last seen values */
260 bsnprintf(buf, sizeof(buf),
261 "---------- - - - - ---------- -------- %s\n", attr->ofname);
262 Dmsg1(dbglvl, "%s", buf);
263 Jmsg(jcr, M_RESTORED, 1, "%s", buf);
268 jcr->id_list = new_guid_list();
271 p = encode_mode(attr->statp.st_mode, buf);
272 p += sprintf(p, " %2d ", (uint32_t)attr->statp.st_nlink);
273 p += sprintf(p, "%-8.8s %-8.8s",
274 guid->uid_to_name(attr->statp.st_uid, en1, sizeof(en1)),
275 guid->gid_to_name(attr->statp.st_gid, en2, sizeof(en2)));
276 p += sprintf(p, "%12.12s ", edit_int64(attr->statp.st_size, ec1));
277 p = encode_time(attr->statp.st_ctime, p);
280 for (f=attr->ofname; *f && (p-buf) < (int)sizeof(buf)-10; ) {
283 if (attr->type == FT_LNK) {
289 for (f=attr->olname; *f && (p-buf) < (int)sizeof(buf)-10; ) {
295 Dmsg1(dbglvl, "%s", buf);
296 Jmsg(jcr, M_RESTORED, 1, "%s", buf);