1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many 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    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 
20 
21 #ifndef __BVFS_H_
22 #define __BVFS_H_ 1
23 
24 
25 /*
26  * This object can be use to browse the catalog
27  *
28  * Bvfs fs;
29  * fs.set_jobid(10);
30  * fs.update_cache();
31  * fs.ch_dir("/");
32  * fs.ls_dirs();
33  * fs.ls_files();
34  */
35 
36 /* Helper for result handler */
37 typedef enum {
38    BVFS_FILE_RECORD  = 'F',
39    BVFS_DIR_RECORD   = 'D',
40    BVFS_FILE_VERSION = 'V',
41    BVFS_VOLUME_LIST  = 'L',
42    BVFS_DELTA_RECORD = 'd',
43 } bvfs_handler_type;
44 
45 typedef enum {
46    BVFS_Type    = 0,            /* Could be D, F, V, L */
47    BVFS_PathId  = 1,
48    BVFS_FilenameId = 5,         /* No longer in use, use fileid instead */
49 
50    BVFS_Name    = 2,
51    BVFS_JobId   = 3,
52 
53    BVFS_LStat   = 4,            /* Can be empty for missing directories */
54    BVFS_FileId  = 5,            /* Can be empty for missing directories */
55 
56    /* Only if Path record */
57    BVFS_FileIndex = 6,
58 
59    /* Only if File Version record */
60    BVFS_Md5     = 6,
61    BVFS_VolName = 7,
62    BVFS_VolInchanger = 8,
63 
64    /* Only if Delta record */
65    BVFS_DeltaSeq = 6,
66    BVFS_JobTDate = 7
67 } bvfs_row_index;
68 
69 class Bvfs {
70 
71 public:
72    Bvfs(JCR *j, BDB *mdb);
73    virtual ~Bvfs();
74 
set_compute_delta(bool val)75    void set_compute_delta(bool val) {
76       compute_delta = val;
77    };
78 
79    /* Return the number of jobids after the filter */
80    int set_jobid(JobId_t id);
81    int set_jobids(char *ids);
82 
get_jobids()83    char *get_jobids() {
84       return jobids;
85    }
86 
set_limit(uint32_t max)87    void set_limit(uint32_t max) {
88       limit = max;
89    }
90 
set_offset(uint32_t nb)91    void set_offset(uint32_t nb) {
92       offset = nb;
93    }
94 
set_pattern(char * p)95    void set_pattern(char *p) {
96       uint32_t len = strlen(p);
97       pattern = check_pool_memory_size(pattern, len*2+1);
98       db->bdb_escape_string(jcr, pattern, p, len);
99    }
100 
set_filename(char * p)101    void set_filename(char *p) {
102       uint32_t len = strlen(p);
103       filename = check_pool_memory_size(filename, len*2+1);
104       db->bdb_escape_string(jcr, filename, p, len);
105    }
106 
107    /* Get the root point */
108    DBId_t get_root();
109 
110    /* It's much better to access Path though their PathId, it
111     * avoids mistakes with string encoding
112     */
113    bool ch_dir(DBId_t pathid);
114 
115    /*
116     * Returns true if the directory exists
117     */
118    bool ch_dir(const char *path);
119 
120    bool ls_files();             /* Returns true if we have more files to read */
121    bool ls_dirs();              /* Returns true if we have more dir to read */
122    void ls_special_dirs();      /* get . and .. */
get_all_file_versions(DBId_t pathid,FileId_t fnid,char * client)123    void get_all_file_versions(DBId_t pathid, FileId_t fnid, char *client) {
124       alist clients(1, not_owned_by_alist);
125       clients.append(client);
126       get_all_file_versions(pathid, fnid, &clients);
127    };
128    void get_all_file_versions(DBId_t pathid, FileId_t fnid, alist *clients);
129 
130    void update_cache();
131 
132    /* bfileview */
133    void fv_update_cache();
134 
set_see_all_versions(bool val)135    void set_see_all_versions(bool val) {
136       see_all_versions = val;
137    }
138 
set_see_copies(bool val)139    void set_see_copies(bool val) {
140       see_copies = val;
141    }
142 
143    int filter_jobid();         /* Call after set_username, returns the number of jobids */
144 
set_username(char * user)145    void set_username(char *user) {
146       if (user) {
147          username = bstrdup(user);
148       }
149    };
150 
151    char *escape_list(alist *list);
152 
copy_acl(alist * list)153    bool copy_acl(alist *list) {
154       if (!list ||
155           (list->size() > 0 &&
156            (strcasecmp((char *)list->get(0), "*all*") == 0)))
157       {
158          return false;
159       }
160       return true;
161    };
162 
163    /* Keep a pointer to various ACLs */
set_job_acl(alist * lst)164    void set_job_acl(alist *lst) {
165       job_acl = copy_acl(lst)?lst:NULL;
166       use_acl = true;
167    };
set_fileset_acl(alist * lst)168    void set_fileset_acl(alist *lst) {
169       fileset_acl = copy_acl(lst)?lst:NULL;
170       use_acl = true;
171    };
172    /* For client, we copy ACL from ClientACL and RestoreClientACL
173     * (bvfs is handling only Restore)
174     */
set_client_acl(alist * client,alist * restore)175    void set_client_acl(alist *client, alist *restore) {
176       client_acl = New(alist(10, not_owned_by_alist));
177 
178       /* Everything is authorized */
179       if (client && client->size() == 1
180           && strcasecmp((char*)client->get(0), "*all*") == 0)
181       {
182          /* nothing to do */
183 
184       /* Everything is authorized */
185       } else if (restore && restore->size() == 1
186                  && strcasecmp((char*)restore->get(0), "*all*") == 0)
187       {
188          /* nothing to do */
189 
190       } else {
191          /* We copy one by one */
192          char *elt;
193          if (client) {
194             foreach_alist(elt, client) {
195                client_acl->append(elt);
196             }
197          }
198          if (restore) {
199             foreach_alist(elt, restore) {
200                client_acl->append(elt);
201             }
202          }
203       }
204       /* Nothing in the list, we can keep an empty one */
205       if (client_acl->size() == 0) {
206          delete client_acl;
207          client_acl = NULL;
208       }
209       use_acl = true;
210    };
set_pool_acl(alist * lst)211    void set_pool_acl(alist *lst) {
212       pool_acl = copy_acl(lst)?lst:NULL;
213       use_acl = true;
214    };
set_handler(DB_RESULT_HANDLER * h,void * ctx)215    void set_handler(DB_RESULT_HANDLER *h, void *ctx) {
216       list_entries = h;
217       user_data = ctx;
218    };
219 
get_pwd()220    DBId_t get_pwd() {
221       return pwd_id;
222    };
223 
get_attr()224    ATTR *get_attr() {
225       return attr;
226    }
227 
get_jcr()228    JCR *get_jcr() {
229       return jcr;
230    }
231 
reset_offset()232    void reset_offset() {
233       offset=0;
234    }
235 
next_offset()236    void next_offset() {
237       offset+=limit;
238    }
239 
240    /* Clear all cache */
241    void clear_cache();
242 
243    /* Compute restore list */
244    bool compute_restore_list(char *fileid, char *dirid, char *output_table);
245 
246    /* Drop previous restore list */
247    bool drop_restore_list(char *output_table);
248 
249    /* for internal use */
250    int _handle_path(void *, int, char **);
251 
252    /* Handle Delta parts if any */
253    void insert_missing_delta(char *output_table, int64_t *res);
254 
255    /* Handle hardlinks if any */
256    bool insert_hardlinks(char *output_table);
257 
258    /* Handle hardlinks if any */
259    bool insert_hardlinks_fast(char *output_table);
260 
261    /* Check if this function can be used */
262    bool can_use_insert_hardlinks_fast();
263 
264    /* Get a list of volumes */
265    void get_volumes(FileId_t fileid);
266 
267    /* Get Delta parts of a file */
268    bool get_delta(FileId_t fileid);
269 
270    /* Query handler to check UID of the file with the current uid/gid */
271    int checkuid_cb(int fields, char **row);
272 
273    /* Query handler to check hardlinks */
274    int checkhardlinks_cb(int fields, char **row);
275 
276    /* Check if the parent directories are accessible */
277    bool check_path_access(DBId_t pathid);
278 
279    /* Check if the full path is authorized by the current set of ACLs */
280    bool check_full_path_access(int nb, sellist *sel, db_list_ctx *toexcl);
281 
set_uid(uid_t u,gid_t g)282    void set_uid(uid_t u, gid_t g) {
283       if (u == 0) {
284          return;
285       }
286       if (!uid_acl) {
287          uid_acl = New(alist(5, not_owned_by_alist));
288          gid_acl = New(alist(5, not_owned_by_alist));
289       }
290       uid_acl->append((void*)(intptr_t)u);
291       gid_acl->append((void*)(intptr_t)g);
292       use_acl = true;
293    };
294    alist *uid_acl;
295    alist *gid_acl;
296    alist *dir_acl;
297 
298    int  check_dirs;             /* When it's 1, we check the against directory_acl */
299    bool can_access(struct stat *st);
300    bool can_access_dir(const char *path);
301    bool check_permissions(char *output_table);
302 
303    bool delete_fileid(char *fileids);
304 
305 private:
306    Bvfs(const Bvfs &);               /* prohibit pass by value */
307    Bvfs & operator = (const Bvfs &); /* prohibit class assignment */
308 
309    JCR *jcr;
310    BDB *db;
311    POOLMEM *jobids;
312    char *username;              /* Used with Bweb */
313 
314    POOLMEM *prev_dir; /* ls_dirs query returns all versions, take the 1st one */
315    POOLMEM *pattern;
316    POOLMEM *filename;
317 
318    POOLMEM *tmp;
319    POOLMEM *escaped_list;
320 
321    /* Pointer to Console ACL */
322    alist *job_acl;
323    alist *client_acl;
324    alist *restoreclient_acl;
325    alist *fileset_acl;
326    alist *pool_acl;
327    char  *last_dir_acl;
328 
329    htable *hardlinks;           /* Check if we already saw a given hardlink */
330    alist  *missing_hardlinks;   /* list with all the missing jobid/fileindex1 */
331 
332    ATTR *attr;                /* Can be use by handler to call decode_stat() */
333 
334    uint32_t limit;
335    uint32_t offset;
336    uint32_t nb_record;          /* number of records of the last query */
337    DBId_t pwd_id;               /* Current pathid */
338 
339    bool see_all_versions;
340    bool see_copies;
341    bool compute_delta;
342 
343    /* Restrict the ouput with some uid/gid */
344    db_list_ctx fileid_to_delete; /* used also by check_path_access */
345    bool need_to_check_permissions();
346    bool use_acl;
347 
348    /* bfileview */
349    void fv_get_big_files(int64_t pathid, int64_t min_size, int32_t limit);
350    void fv_update_size_and_count(int64_t pathid, int64_t size, int64_t count);
351    void fv_compute_size_and_count(int64_t pathid, int64_t *size, int64_t *count);
352    void fv_get_current_size_and_count(int64_t pathid, int64_t *size, int64_t *count);
353    void fv_get_size_and_count(int64_t pathid, int64_t *size, int64_t *count);
354 
355    DB_RESULT_HANDLER *list_entries;
356    void *user_data;
357 };
358 
359 #define bvfs_is_dir(row) ((row)[BVFS_Type][0] == BVFS_DIR_RECORD)
360 #define bvfs_is_file(row) ((row)[BVFS_Type][0] == BVFS_FILE_RECORD)
361 #define bvfs_is_version(row) ((row)[BVFS_Type][0] == BVFS_FILE_VERSION)
362 #define bvfs_is_volume_list(row) ((row)[BVFS_Type][0] == BVFS_VOLUME_LIST)
363 #define bvfs_is_delta_list(row) ((row)[BVFS_Type][0] == BVFS_DELTA_RECORD)
364 
365 void bvfs_update_fv_cache(JCR *jcr, BDB *mdb, char *jobids);
366 int bvfs_update_path_hierarchy_cache(JCR *jcr, BDB *mdb, char *jobids);
367 void bvfs_update_cache(JCR *jcr, BDB *mdb);
368 char *bvfs_parent_dir(char *path);
369 
370 /* Return the basename of the with the trailing /  (update the given string)
371  * TODO: see in the rest of bacula if we don't have
372  * this function already
373  */
374 char *bvfs_basename_dir(char *path);
375 
376 #endif /* __BVFS_H_ */
377