1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2002-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2016-2018 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation and included
10 in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * Kern Sibbald, October MMII
24 */
25 /**
26 * @file
27 * Encode and decode standard Unix attributes
28 */
29
30 #include "include/bareos.h"
31 #include "lib/scan.h"
32
33 /**
34 * Encode a stat structure into a base64 character string
35 * All systems must create such a structure.
36 * In addition, we tack on the LinkFI, which is non-zero in
37 * the case of a hard linked file that has no data. This
38 * is a File Index pointing to the link that does have the
39 * data (always the first one encountered in a save).
40 * You may piggyback attributes on this packet by encoding
41 * them in the encode_attribsEx() subroutine, but this is
42 * not recommended.
43 */
EncodeStat(char * buf,struct stat * statp,int stat_size,int32_t LinkFI,int data_stream)44 void EncodeStat(char* buf,
45 struct stat* statp,
46 int stat_size,
47 int32_t LinkFI,
48 int data_stream)
49 {
50 char* p = buf;
51
52 /*
53 * We read the stat packet so make sure the caller's conception
54 * is the same as ours. They can be different if LARGEFILE is not
55 * the same when compiling this library and the calling program.
56 */
57 ASSERT(stat_size == (int)sizeof(struct stat));
58
59 /**
60 * Encode a stat packet. I should have done this more intelligently
61 * with a length so that it could be easily expanded.
62 */
63 p += ToBase64((int64_t)statp->st_dev, p);
64 *p++ = ' '; /* separate fields with a space */
65 p += ToBase64((int64_t)statp->st_ino, p);
66 *p++ = ' ';
67 p += ToBase64((int64_t)statp->st_mode, p);
68 *p++ = ' ';
69 p += ToBase64((int64_t)statp->st_nlink, p);
70 *p++ = ' ';
71 p += ToBase64((int64_t)statp->st_uid, p);
72 *p++ = ' ';
73 p += ToBase64((int64_t)statp->st_gid, p);
74 *p++ = ' ';
75 p += ToBase64((int64_t)statp->st_rdev, p);
76 *p++ = ' ';
77 p += ToBase64((int64_t)statp->st_size, p);
78 *p++ = ' ';
79 #ifndef HAVE_MINGW
80 p += ToBase64((int64_t)statp->st_blksize, p);
81 *p++ = ' ';
82 p += ToBase64((int64_t)statp->st_blocks, p);
83 *p++ = ' ';
84 #else
85 p += ToBase64((int64_t)0, p); /* output place holder */
86 *p++ = ' ';
87 p += ToBase64((int64_t)0, p); /* output place holder */
88 *p++ = ' ';
89 #endif
90 p += ToBase64((int64_t)statp->st_atime, p);
91 *p++ = ' ';
92 p += ToBase64((int64_t)statp->st_mtime, p);
93 *p++ = ' ';
94 p += ToBase64((int64_t)statp->st_ctime, p);
95 *p++ = ' ';
96 p += ToBase64((int64_t)LinkFI, p);
97 *p++ = ' ';
98
99 #ifdef HAVE_CHFLAGS
100 /* FreeBSD function */
101 p += ToBase64((int64_t)statp->st_flags, p); /* output st_flags */
102 #else
103 p += ToBase64((int64_t)0, p); /* output place holder */
104 #endif
105 *p++ = ' ';
106 p += ToBase64((int64_t)data_stream, p);
107 *p = 0;
108 return;
109 }
110
111 /* Do casting according to unknown type to keep compiler happy */
112 #ifdef HAVE_TYPEOF
113 # define plug(st, val) st = (typeof st)val
114 #else
115 # if !HAVE_GCC & HAVE_SUN_OS
116 /* Sun compiler does not handle templates correctly */
117 # define plug(st, val) st = val
118 # elif __sgi
119 # define plug(st, val) st = val
120 # else
121 /* Use templates to do the casting */
122 template <class T>
plug(T & st,uint64_t val)123 void plug(T& st, uint64_t val)
124 {
125 st = static_cast<T>(val);
126 }
127 # endif
128 #endif
129
130 /**
131 * Decode a stat packet from base64 characters
132 */
DecodeStat(char * buf,struct stat * statp,int stat_size,int32_t * LinkFI)133 int DecodeStat(char* buf, struct stat* statp, int stat_size, int32_t* LinkFI)
134 {
135 char* p = buf;
136 int64_t val;
137
138 /*
139 * We store into the stat packet so make sure the caller's conception
140 * is the same as ours. They can be different if LARGEFILE is not
141 * the same when compiling this library and the calling program.
142 */
143 ASSERT(stat_size == (int)sizeof(struct stat));
144 memset(statp, 0, stat_size);
145
146 p += FromBase64(&val, p);
147 plug(statp->st_dev, val);
148 p++;
149 p += FromBase64(&val, p);
150 plug(statp->st_ino, val);
151 p++;
152 p += FromBase64(&val, p);
153 plug(statp->st_mode, val);
154 p++;
155 p += FromBase64(&val, p);
156 plug(statp->st_nlink, val);
157 p++;
158 p += FromBase64(&val, p);
159 plug(statp->st_uid, val);
160 p++;
161 p += FromBase64(&val, p);
162 plug(statp->st_gid, val);
163 p++;
164 p += FromBase64(&val, p);
165 plug(statp->st_rdev, val);
166 p++;
167 p += FromBase64(&val, p);
168 plug(statp->st_size, val);
169 p++;
170 #ifndef HAVE_MINGW
171 p += FromBase64(&val, p);
172 plug(statp->st_blksize, val);
173 p++;
174 p += FromBase64(&val, p);
175 plug(statp->st_blocks, val);
176 p++;
177 #else
178 p += FromBase64(&val, p);
179 // plug(statp->st_blksize, val);
180 p++;
181 p += FromBase64(&val, p);
182 // plug(statp->st_blocks, val);
183 p++;
184 #endif
185 p += FromBase64(&val, p);
186 plug(statp->st_atime, val);
187 p++;
188 p += FromBase64(&val, p);
189 plug(statp->st_mtime, val);
190 p++;
191 p += FromBase64(&val, p);
192 plug(statp->st_ctime, val);
193
194 /* Optional FileIndex of hard linked file data */
195 if (*p == ' ' || (*p != 0 && *(p + 1) == ' ')) {
196 p++;
197 p += FromBase64(&val, p);
198 *LinkFI = (uint32_t)val;
199 } else {
200 *LinkFI = 0;
201 return 0;
202 }
203
204 /* FreeBSD user flags */
205 if (*p == ' ' || (*p != 0 && *(p + 1) == ' ')) {
206 p++;
207 p += FromBase64(&val, p);
208 #ifdef HAVE_CHFLAGS
209 plug(statp->st_flags, val);
210 } else {
211 statp->st_flags = 0;
212 #endif
213 }
214
215 /* Look for data stream id */
216 if (*p == ' ' || (*p != 0 && *(p + 1) == ' ')) {
217 p++;
218 p += FromBase64(&val, p);
219 } else {
220 val = 0;
221 }
222 return (int)val;
223 }
224
225 /**
226 * Decode a LinkFI field of encoded stat packet
227 */
DecodeLinkFI(char * buf,struct stat * statp,int stat_size)228 int32_t DecodeLinkFI(char* buf, struct stat* statp, int stat_size)
229 {
230 char* p = buf;
231 int64_t val;
232 /*
233 * We store into the stat packet so make sure the caller's conception
234 * is the same as ours. They can be different if LARGEFILE is not
235 * the same when compiling this library and the calling program.
236 */
237 ASSERT(stat_size == (int)sizeof(struct stat));
238
239 SkipNonspaces(&p); /* st_dev */
240 p++; /* skip space */
241 SkipNonspaces(&p); /* st_ino */
242 p++;
243 p += FromBase64(&val, p);
244 plug(statp->st_mode, val); /* st_mode */
245 p++;
246 SkipNonspaces(&p); /* st_nlink */
247 p++;
248 SkipNonspaces(&p); /* st_uid */
249 p++;
250 SkipNonspaces(&p); /* st_gid */
251 p++;
252 SkipNonspaces(&p); /* st_rdev */
253 p++;
254 SkipNonspaces(&p); /* st_size */
255 p++;
256 SkipNonspaces(&p); /* st_blksize */
257 p++;
258 SkipNonspaces(&p); /* st_blocks */
259 p++;
260 SkipNonspaces(&p); /* st_atime */
261 p++;
262 SkipNonspaces(&p); /* st_mtime */
263 p++;
264 SkipNonspaces(&p); /* st_ctime */
265
266 /* Optional FileIndex of hard linked file data */
267 if (*p == ' ' || (*p != 0 && *(p + 1) == ' ')) {
268 p++;
269 p += FromBase64(&val, p);
270 return (int32_t)val;
271 }
272 return 0;
273 }
274