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