1 /*
2  * Copyright (C) 2020-2021 Bareos GmbH & Co. KG
3  * Copyright (C) 2010 SCALITY SA. All rights reserved.
4  * http://www.scality.com
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  * Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  *
13  * Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY SCALITY SA ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL SCALITY SA OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and documentation
30  * are those of the authors and should not be interpreted as representing
31  * official policies, either expressed or implied, of SCALITY SA.
32  *
33  * https://github.com/scality/Droplet
34  */
35 #include "dropletp.h"
36 #include <droplet/posix/posix.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #include <dirent.h>
41 #include <sys/types.h>
42 #include <linux/xattr.h>
43 #include <utime.h>
44 #include <pwd.h>
45 #include <grp.h>
46 
47 //#define DPRINTF(fmt,...) fprintf(stderr, fmt, ##__VA_ARGS__)
48 #define DPRINTF(fmt, ...)
49 
50 struct metadata_conven {
51   dpl_dict_t* metadata;
52   dpl_sysmd_t* sysmdp;
53 };
54 
cb_posix_get_metadatum_from_xattr_value(dpl_dict_var_t * var,void * cb_arg)55 static dpl_status_t cb_posix_get_metadatum_from_xattr_value(dpl_dict_var_t* var,
56                                                             void* cb_arg)
57 {
58   struct metadata_conven* mc = (struct metadata_conven*)cb_arg;
59   return dpl_dict_add_value(mc->metadata, var->key, var->val, 0);
60 }
61 
dpl_posix_get_metadatum_from_value(const char * key,dpl_value_t * val,dpl_metadatum_func_t metadatum_func,void * cb_arg,dpl_dict_t * metadata,dpl_sysmd_t * sysmdp)62 dpl_status_t dpl_posix_get_metadatum_from_value(
63     const char* key,
64     dpl_value_t* val,
65     dpl_metadatum_func_t metadatum_func,
66     void* cb_arg,
67     dpl_dict_t* metadata,
68     dpl_sysmd_t* sysmdp)
69 {
70   dpl_status_t ret, ret2;
71   int iret;
72   char buf[256];
73   struct metadata_conven mc = {.metadata = metadata, .sysmdp = sysmdp};
74 
75   if (sysmdp) {
76     if (!strcmp(key, "atime")) {
77       assert(val->type == DPL_VALUE_STRING);
78       sysmdp->atime = strtoul(dpl_sbuf_get_str(val->string), NULL, 0);
79       sysmdp->mask |= DPL_SYSMD_MASK_ATIME;
80     } else if (!strcmp(key, "mtime")) {
81       assert(val->type == DPL_VALUE_STRING);
82       sysmdp->mtime = strtoul(dpl_sbuf_get_str(val->string), NULL, 0);
83       sysmdp->mask |= DPL_SYSMD_MASK_MTIME;
84     } else if (!strcmp(key, "ctime")) {
85       assert(val->type == DPL_VALUE_STRING);
86       sysmdp->ctime = strtoul(dpl_sbuf_get_str(val->string), NULL, 0);
87       sysmdp->mask |= DPL_SYSMD_MASK_CTIME;
88     } else if (!strcmp(key, "size")) {
89       assert(val->type == DPL_VALUE_STRING);
90       sysmdp->size = strtoul(dpl_sbuf_get_str(val->string), NULL, 0);
91       sysmdp->mask |= DPL_SYSMD_MASK_SIZE;
92     } else if (!strcmp(key, "uid")) {
93       uid_t uid;
94       struct passwd pwd, *pwdp;
95 
96       assert(val->type == DPL_VALUE_STRING);
97       uid = atoi(dpl_sbuf_get_str(val->string));
98       iret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pwdp);
99       if (iret == -1) {
100         perror("getpwuid");
101         ret = DPL_FAILURE;
102         goto end;
103       }
104       snprintf(sysmdp->owner, sizeof(sysmdp->owner), "%s", pwdp->pw_name);
105       sysmdp->mask |= DPL_SYSMD_MASK_OWNER;
106     } else if (!strcmp(key, "gid")) {
107       gid_t gid;
108       struct group grp, *grpp;
109 
110       assert(val->type == DPL_VALUE_STRING);
111       gid = atoi(dpl_sbuf_get_str(val->string));
112       iret = getgrgid_r(gid, &grp, buf, sizeof(buf), &grpp);
113       if (iret == -1) {
114         perror("getgrgid");
115         ret = DPL_FAILURE;
116         goto end;
117       }
118       snprintf(sysmdp->group, sizeof(sysmdp->group), "%s", grpp->gr_name);
119       sysmdp->mask |= DPL_SYSMD_MASK_GROUP;
120     } else if (!strcmp(key, "ino")) {
121       assert(val->type == DPL_VALUE_STRING);
122       snprintf(sysmdp->id, sizeof(sysmdp->id), "%s",
123                dpl_sbuf_get_str(val->string));
124       sysmdp->mask |= DPL_SYSMD_MASK_ID;
125     }
126   }
127 
128   if (!strcmp(key, "xattr")) {
129     // this is the metadata object
130     if (DPL_VALUE_SUBDICT != val->type) {
131       ret = DPL_EINVAL;
132       goto end;
133     }
134 
135     if (metadata) {
136       if (metadatum_func) {
137         ret2 = metadatum_func(cb_arg, key, val);
138         if (DPL_SUCCESS != ret2) {
139           ret = ret2;
140           goto end;
141         }
142       }
143 
144       // add xattr's md into metadata
145       ret2 = dpl_dict_iterate(val->subdict,
146                               cb_posix_get_metadatum_from_xattr_value, &mc);
147       if (DPL_SUCCESS != ret2) {
148         ret = ret2;
149         goto end;
150       }
151     }
152   }
153 
154   ret = DPL_SUCCESS;
155 
156 end:
157 
158   return ret;
159 }
160 
cb_values_iterate(dpl_dict_var_t * var,void * cb_arg)161 static dpl_status_t cb_values_iterate(dpl_dict_var_t* var, void* cb_arg)
162 {
163   struct metadata_conven* mc = (struct metadata_conven*)cb_arg;
164 
165   return dpl_posix_get_metadatum_from_value(var->key, var->val, NULL, NULL,
166                                             mc->metadata, mc->sysmdp);
167 }
168 
169 /**
170  * get metadata from values
171  *
172  * @param values
173  * @param metadatap
174  * @param sysmdp
175  *
176  * @return
177  */
dpl_posix_get_metadata_from_values(const dpl_dict_t * values,dpl_dict_t ** metadatap,dpl_sysmd_t * sysmdp)178 dpl_status_t dpl_posix_get_metadata_from_values(const dpl_dict_t* values,
179                                                 dpl_dict_t** metadatap,
180                                                 dpl_sysmd_t* sysmdp)
181 {
182   dpl_dict_t* metadata = NULL;
183   dpl_status_t ret, ret2;
184   struct metadata_conven mc;
185 
186   if (metadatap) {
187     metadata = dpl_dict_new(13);
188     if (NULL == metadata) {
189       ret = DPL_ENOMEM;
190       goto end;
191     }
192   }
193 
194   memset(&mc, 0, sizeof(mc));
195   mc.metadata = metadata;
196   mc.sysmdp = sysmdp;
197 
198   if (sysmdp) sysmdp->mask = 0;
199 
200   ret2 = dpl_dict_iterate(values, cb_values_iterate, &mc);
201   if (DPL_SUCCESS != ret2) {
202     ret = ret2;
203     goto end;
204   }
205 
206   if (NULL != metadatap) {
207     *metadatap = metadata;
208     metadata = NULL;
209   }
210 
211   ret = DPL_SUCCESS;
212 
213 end:
214 
215   if (NULL != metadata) dpl_dict_free(metadata);
216 
217   return ret;
218 }
219