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