2 Bacula® - The Network Backup Solution
4 Copyright (C) 2003-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 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 Bacula® is a registered trademark of Kern Sibbald.
17 * attr.c Unpack an Attribute record returned from the tape
19 * Kern Sibbald, June MMIII (code pulled from filed/restore.c and updated)
28 static const int dbglvl = 150;
30 ATTR *new_attr(JCR *jcr)
32 ATTR *attr = (ATTR *)malloc(sizeof(ATTR));
33 memset(attr, 0, sizeof(ATTR));
34 attr->ofname = get_pool_memory(PM_FNAME);
35 attr->olname = get_pool_memory(PM_FNAME);
36 attr->attrEx = get_pool_memory(PM_FNAME);
42 void free_attr(ATTR *attr)
44 free_pool_memory(attr->olname);
45 free_pool_memory(attr->ofname);
46 free_pool_memory(attr->attrEx);
50 int unpack_attributes_record(JCR *jcr, int32_t stream, char *rec, int32_t reclen, ATTR *attr)
55 * An Attributes record consists of:
60 * Link name (if file linked i.e. FT_LNK)
61 * Extended attributes (Win32)
62 * plus optional values determined by AR_ flags in upper bits of Type
66 attr->stream = stream;
67 Dmsg1(dbglvl, "Attr: %s\n", rec);
68 if (sscanf(rec, "%d %d", &attr->file_index, &attr->type) != 2) {
69 Jmsg(jcr, M_FATAL, 0, _("Error scanning attributes: %s\n"), rec);
70 Dmsg1(dbglvl, "\nError scanning attributes. %s\n", rec);
73 Dmsg2(dbglvl, "Got Attr: FilInx=%d type=%d\n", attr->file_index, attr->type);
75 * Note AR_DATA_STREAM should never be set since it is encoded
76 * at the end of the attributes.
78 if (attr->type & AR_DATA_STREAM) {
79 attr->data_stream = 1;
81 attr->data_stream = 0;
83 attr->type &= FT_MASK; /* keep only type bits */
85 while (*p++ != ' ') /* skip record file index */
87 while (*p++ != ' ') /* skip type */
90 attr->fname = p; /* set filname position */
91 while (*p++ != 0) /* skip filename */
93 attr->attr = p; /* set attributes position */
94 while (*p++ != 0) /* skip attributes */
96 attr->lname = p; /* set link position */
97 while (*p++ != 0) /* skip link */
100 if (attr->type == FT_RESTORE_FIRST) {
101 /* We have an object, so do a binary copy */
102 object_len = reclen + rec - p;
103 attr->attrEx = check_pool_memory_size(attr->attrEx, object_len + 1);
104 memcpy(attr->attrEx, p, object_len);
105 /* Add a EOS for those who attempt to print the object */
106 p = attr->attrEx + object_len;
109 pm_strcpy(attr->attrEx, p); /* copy extended attributes, if any */
110 if (attr->data_stream) {
112 while (*p++ != 0) /* skip extended attributes */
114 from_base64(&val, p);
115 attr->data_stream = (int32_t)val;
117 while (*p++ != 0) /* skip extended attributes */
119 if (p - rec < reclen) {
120 attr->delta_seq = str_to_int32(p); /* delta_seq */
124 Dmsg8(dbglvl, "unpack_attr FI=%d Type=%d fname=%s attr=%s lname=%s attrEx=%s datastr=%d delta_seq=%d\n",
125 attr->file_index, attr->type, attr->fname, attr->attr, attr->lname,
126 attr->attrEx, attr->data_stream, attr->delta_seq);
132 #if defined(HAVE_WIN32)
133 static void strip_double_slashes(char *fname)
137 p = strpbrk(p, "/\\");
139 if (IsPathSeparator(p[1])) {
149 * Build attr->ofname from attr->fname and
150 * attr->olname from attr->olname
152 void build_attr_output_fnames(JCR *jcr, ATTR *attr)
155 * Prepend the where directory so that the
156 * files are put where the user wants.
158 * We do a little jig here to handle Win32 files with
159 * a drive letter -- we simply change the drive
160 * from, for example, c: to c/ for
161 * every filename if a prefix is supplied.
165 if (jcr->where_bregexp) {
167 apply_bregexps(attr->fname, jcr->where_bregexp, &ret);
168 pm_strcpy(attr->ofname, ret);
170 if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
171 /* Always add prefix to hard links (FT_LNKSAVED) and
172 * on user request to soft links
175 if ((attr->type == FT_LNKSAVED || jcr->prefix_links)) {
176 apply_bregexps(attr->lname, jcr->where_bregexp, &ret);
177 pm_strcpy(attr->olname, ret);
180 pm_strcpy(attr->olname, attr->lname);
184 } else if (jcr->where[0] == 0) {
185 pm_strcpy(attr->ofname, attr->fname);
186 pm_strcpy(attr->olname, attr->lname);
190 int wherelen = strlen(jcr->where);
191 pm_strcpy(attr->ofname, jcr->where); /* copy prefix */
192 #if defined(HAVE_WIN32)
193 if (attr->fname[1] == ':') {
194 attr->fname[1] = '/'; /* convert : to / */
197 fn = attr->fname; /* take whole name */
198 /* Ensure where is terminated with a slash */
199 if (!IsPathSeparator(jcr->where[wherelen-1]) && !IsPathSeparator(fn[0])) {
200 pm_strcat(attr->ofname, "/");
202 pm_strcat(attr->ofname, fn); /* copy rest of name */
204 * Fixup link name -- if it is an absolute path
206 if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
208 /* Always add prefix to hard links (FT_LNKSAVED) and
209 * on user request to soft links
211 if (IsPathSeparator(attr->lname[0]) &&
212 (attr->type == FT_LNKSAVED || jcr->prefix_links)) {
213 pm_strcpy(attr->olname, jcr->where);
220 #if defined(HAVE_WIN32)
221 if (attr->lname[1] == ':') {
222 attr->lname[1] = '/'; /* turn : into / */
225 fn = attr->lname; /* take whole name */
226 /* Ensure where is terminated with a slash */
228 !IsPathSeparator(jcr->where[wherelen-1]) &&
229 !IsPathSeparator(fn[0])) {
230 pm_strcat(attr->olname, "/");
232 pm_strcat(attr->olname, fn); /* copy rest of link */
235 #if defined(HAVE_WIN32)
236 strip_double_slashes(attr->ofname);
237 strip_double_slashes(attr->olname);
241 extern char *getuser(uid_t uid, char *name, int len);
242 extern char *getgroup(gid_t gid, char *name, int len);
245 * Print an ls style message, also send M_RESTORED
247 void print_ls_output(JCR *jcr, ATTR *attr)
251 char en1[30], en2[30];
255 if (attr->type == FT_DELETED) { /* TODO: change this to get last seen values */
256 bsnprintf(buf, sizeof(buf),
257 "---------- - - - - ---------- -------- %s\n", attr->ofname);
258 Dmsg1(dbglvl, "%s", buf);
259 Jmsg(jcr, M_RESTORED, 1, "%s", buf);
264 jcr->id_list = new_guid_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);
276 for (f=attr->ofname; *f && (p-buf) < (int)sizeof(buf)-10; ) {
279 if (attr->type == FT_LNK) {
285 for (f=attr->olname; *f && (p-buf) < (int)sizeof(buf)-10; ) {
291 Dmsg1(dbglvl, "%s", buf);
292 Jmsg(jcr, M_RESTORED, 1, "%s", buf);