]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/attr.c
Backport from BEE
[bacula/bacula] / bacula / src / lib / attr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2003-2014 Free Software Foundation Europe e.V.
5
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.
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    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *   attr.c  Unpack an Attribute record returned from the tape
18  *
19  *    Kern Sibbald, June MMIII  (code pulled from filed/restore.c and updated)
20  *
21  */
22
23
24 #include "bacula.h"
25 #include "jcr.h"
26 #include "lib/breg.h"
27
28 static const int dbglvl = 150;
29
30 ATTR *new_attr(JCR *jcr)
31 {
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);
37    attr->jcr = jcr;
38    attr->uid = getuid();
39    return attr;
40 }
41
42 void free_attr(ATTR *attr)
43 {
44    free_pool_memory(attr->olname);
45    free_pool_memory(attr->ofname);
46    free_pool_memory(attr->attrEx);
47    free(attr);
48 }
49
50 int unpack_attributes_record(JCR *jcr, int32_t stream, char *rec, int32_t reclen, ATTR *attr)
51 {
52    char *p;
53    int object_len;
54    /*
55     * An Attributes record consists of:
56     *    File_index
57     *    Type   (FT_types)
58     *    Filename
59     *    Attributes
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
63     *    Data_stream
64     *
65     */
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);
71       return 0;
72    }
73    Dmsg2(dbglvl, "Got Attr: FilInx=%d type=%d\n", attr->file_index, attr->type);
74    /*
75     * Note AR_DATA_STREAM should never be set since it is encoded
76     *  at the end of the attributes.
77     */
78    if (attr->type & AR_DATA_STREAM) {
79       attr->data_stream = 1;
80    } else {
81       attr->data_stream = 0;
82    }
83    attr->type &= FT_MASK;             /* keep only type bits */
84    p = rec;
85    while (*p++ != ' ')               /* skip record file index */
86       { }
87    while (*p++ != ' ')               /* skip type */
88       { }
89
90    attr->fname = p;                   /* set filname position */
91    while (*p++ != 0)                  /* skip filename */
92       { }
93    attr->attr = p;                    /* set attributes position */
94    while (*p++ != 0)                  /* skip attributes */
95       { }
96    attr->lname = p;                   /* set link position */
97    while (*p++ != 0)                  /* skip link */
98       { }
99    attr->delta_seq = 0;
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;
107       *p = 0;
108    } else {
109       pm_strcpy(attr->attrEx, p);     /* copy extended attributes, if any */
110       if (attr->data_stream) {
111          int64_t val;
112          while (*p++ != 0)            /* skip extended attributes */
113             { }
114          from_base64(&val, p);
115          attr->data_stream = (int32_t)val;
116       } else {
117          while (*p++ != 0)            /* skip extended attributes */
118             { }
119          if (p - rec < reclen) {
120             attr->delta_seq = str_to_int32(p); /* delta_seq */
121          }
122       }
123    }
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);
127    *attr->ofname = 0;
128    *attr->olname = 0;
129    return 1;
130 }
131
132 #if defined(HAVE_WIN32)
133 static void strip_double_slashes(char *fname)
134 {
135    char *p = fname;
136    while (p && *p) {
137       p = strpbrk(p, "/\\");
138       if (p != NULL) {
139          if (IsPathSeparator(p[1])) {
140             strcpy(p, p+1);
141          }
142          p++;
143       }
144    }
145 }
146 #endif
147
148 /*
149  * Build attr->ofname from attr->fname and
150  *       attr->olname from attr->olname
151  */
152 void build_attr_output_fnames(JCR *jcr, ATTR *attr)
153 {
154    /*
155     * Prepend the where directory so that the
156     * files are put where the user wants.
157     *
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.
162     *
163     */
164
165    if (jcr->where_bregexp) {
166       char *ret;
167       apply_bregexps(attr->fname, jcr->where_bregexp, &ret);
168       pm_strcpy(attr->ofname, ret);
169
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
173           */
174
175          if ((attr->type == FT_LNKSAVED || jcr->prefix_links)) {
176             apply_bregexps(attr->lname, jcr->where_bregexp, &ret);
177             pm_strcpy(attr->olname, ret);
178
179          } else {
180             pm_strcpy(attr->olname, attr->lname);
181          }
182       }
183
184    } else if (jcr->where[0] == 0) {
185       pm_strcpy(attr->ofname, attr->fname);
186       pm_strcpy(attr->olname, attr->lname);
187
188    } else {
189       const char *fn;
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 / */
195       }
196 #endif
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, "/");
201       }
202       pm_strcat(attr->ofname, fn); /* copy rest of name */
203       /*
204        * Fixup link name -- if it is an absolute path
205        */
206       if (attr->type == FT_LNKSAVED || attr->type == FT_LNK) {
207          bool add_link;
208          /* Always add prefix to hard links (FT_LNKSAVED) and
209           *  on user request to soft links
210           */
211          if (IsPathSeparator(attr->lname[0]) &&
212              (attr->type == FT_LNKSAVED || jcr->prefix_links)) {
213             pm_strcpy(attr->olname, jcr->where);
214             add_link = true;
215          } else {
216             attr->olname[0] = 0;
217             add_link = false;
218          }
219
220 #if defined(HAVE_WIN32)
221          if (attr->lname[1] == ':') {
222             attr->lname[1] = '/';    /* turn : into / */
223          }
224 #endif
225          fn = attr->lname;       /* take whole name */
226          /* Ensure where is terminated with a slash */
227          if (add_link &&
228             !IsPathSeparator(jcr->where[wherelen-1]) &&
229             !IsPathSeparator(fn[0])) {
230             pm_strcat(attr->olname, "/");
231          }
232          pm_strcat(attr->olname, fn);     /* copy rest of link */
233       }
234    }
235 #if defined(HAVE_WIN32)
236    strip_double_slashes(attr->ofname);
237    strip_double_slashes(attr->olname);
238 #endif
239 }
240
241 extern char *getuser(uid_t uid, char *name, int len);
242 extern char *getgroup(gid_t gid, char *name, int len);
243
244 /*
245  * Print an ls style message, also send M_RESTORED
246  */
247 void print_ls_output(JCR *jcr, ATTR *attr)
248 {
249    char buf[5000];
250    char ec1[30];
251    char en1[30], en2[30];
252    char *p, *f;
253    guid_list *guid;
254
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);
260       return;
261    }
262
263    if (!jcr->id_list) {
264       jcr->id_list = new_guid_list();
265    }
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    *p++ = ' ';
275    *p++ = ' ';
276    for (f=attr->ofname; *f && (p-buf) < (int)sizeof(buf)-10; ) {
277       *p++ = *f++;
278    }
279    if (attr->type == FT_LNK) {
280       *p++ = ' ';
281       *p++ = '-';
282       *p++ = '>';
283       *p++ = ' ';
284       /* Copy link name */
285       for (f=attr->olname; *f && (p-buf) < (int)sizeof(buf)-10; ) {
286          *p++ = *f++;
287       }
288    }
289    *p++ = '\n';
290    *p = 0;
291    Dmsg1(dbglvl, "%s", buf);
292    Jmsg(jcr, M_RESTORED, 1, "%s", buf);
293 }