1 /* $NetBSD: subr.c,v 1.20 2014/08/10 03:22:33 manu Exp $ */ 2 3 /*- 4 * Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <err.h> 31 #include <errno.h> 32 #include <sysexits.h> 33 #include <syslog.h> 34 #include <puffs.h> 35 #include <paths.h> 36 #include <sys/hash.h> 37 #include <sys/extattr.h> 38 39 #include "perfuse_priv.h" 40 41 struct perfuse_ns_map { 42 const char *pnm_ns; 43 const size_t pnm_nslen; 44 const int pnm_native_ns; 45 }; 46 47 #define PERFUSE_NS_MAP(ns, native_ns) \ 48 { ns ".", sizeof(ns), native_ns } 49 50 static __inline struct perfuse_node_hashlist *perfuse_nidhash(struct 51 perfuse_state *, uint64_t); 52 53 struct puffs_node * 54 perfuse_new_pn(struct puffs_usermount *pu, const char *name, 55 struct puffs_node *parent) 56 { 57 struct perfuse_state *ps = puffs_getspecific(pu); 58 struct puffs_node *pn; 59 struct perfuse_node_data *pnd; 60 61 if ((pnd = malloc(sizeof(*pnd))) == NULL) 62 DERR(EX_OSERR, "%s: malloc failed", __func__); 63 64 if ((pn = puffs_pn_new(pu, pnd)) == NULL) 65 DERR(EX_SOFTWARE, "%s: puffs_pn_new failed", __func__); 66 67 (void)memset(pnd, 0, sizeof(*pnd)); 68 pnd->pnd_rfh = FUSE_UNKNOWN_FH; 69 pnd->pnd_wfh = FUSE_UNKNOWN_FH; 70 pnd->pnd_nodeid = PERFUSE_UNKNOWN_NODEID; 71 if (parent != NULL) { 72 pnd->pnd_parent_nodeid = PERFUSE_NODE_DATA(parent)->pnd_nodeid; 73 } else { 74 pnd->pnd_parent_nodeid = FUSE_ROOT_ID; 75 } 76 pnd->pnd_fuse_nlookup = 0; 77 pnd->pnd_puffs_nlookup = 0; 78 pnd->pnd_pn = (puffs_cookie_t)pn; 79 if (strcmp(name, "..") != 0) 80 (void)strlcpy(pnd->pnd_name, name, MAXPATHLEN); 81 else 82 pnd->pnd_name[0] = 0; /* anonymous for now */ 83 TAILQ_INIT(&pnd->pnd_pcq); 84 85 puffs_pn_setpriv(pn, pnd); 86 87 ps->ps_nodecount++; 88 89 return pn; 90 } 91 92 void 93 perfuse_destroy_pn(struct puffs_usermount *pu, struct puffs_node *pn) 94 { 95 struct perfuse_state *ps = puffs_getspecific(pu); 96 struct perfuse_node_data *pnd; 97 98 if ((pnd = puffs_pn_getpriv(pn)) != NULL) { 99 if (pnd->pnd_all_fd != NULL) 100 free(pnd->pnd_all_fd); 101 102 if (pnd->pnd_dirent != NULL) 103 free(pnd->pnd_dirent); 104 105 #ifdef PERFUSE_DEBUG 106 if (pnd->pnd_flags & PND_OPEN) 107 DERRX(EX_SOFTWARE, "%s: file open", __func__); 108 109 if (!TAILQ_EMPTY(&pnd->pnd_pcq)) 110 DERRX(EX_SOFTWARE, "%s: non empty pnd_pcq", __func__); 111 112 pnd->pnd_flags |= PND_INVALID; 113 #endif /* PERFUSE_DEBUG */ 114 115 free(pnd); 116 } 117 118 puffs_pn_put(pn); 119 120 ps->ps_nodecount--; 121 122 return; 123 } 124 125 void 126 perfuse_new_fh(puffs_cookie_t opc, uint64_t fh, int mode) 127 { 128 struct perfuse_node_data *pnd; 129 130 pnd = PERFUSE_NODE_DATA(opc); 131 132 if (mode & FWRITE) { 133 if (pnd->pnd_flags & PND_WFH) 134 DERRX(EX_SOFTWARE, "%s: opc = %p, write fh already set", 135 __func__, (void *)opc); 136 pnd->pnd_wfh = fh; 137 pnd->pnd_flags |= PND_WFH; 138 } 139 140 if (mode & FREAD) { 141 if (pnd->pnd_flags & PND_RFH) 142 DERRX(EX_SOFTWARE, "%s: opc = %p, read fh already set", 143 __func__, (void *)opc); 144 pnd->pnd_rfh = fh; 145 pnd->pnd_flags |= PND_RFH; 146 } 147 148 return; 149 } 150 151 void 152 perfuse_destroy_fh(puffs_cookie_t opc, uint64_t fh) 153 { 154 struct perfuse_node_data *pnd; 155 156 pnd = PERFUSE_NODE_DATA(opc); 157 158 if (fh == pnd->pnd_rfh) { 159 if (!(pnd->pnd_flags & PND_RFH) && (fh != FUSE_UNKNOWN_FH)) 160 DERRX(EX_SOFTWARE, 161 "%s: opc = %p, unset rfh = %"PRIx64"", 162 __func__, (void *)opc, fh); 163 pnd->pnd_rfh = FUSE_UNKNOWN_FH; 164 pnd->pnd_flags &= ~PND_RFH; 165 } 166 167 if (fh == pnd->pnd_wfh) { 168 if (!(pnd->pnd_flags & PND_WFH) && (fh != FUSE_UNKNOWN_FH)) 169 DERRX(EX_SOFTWARE, 170 "%s: opc = %p, unset wfh = %"PRIx64"", 171 __func__, (void *)opc, fh); 172 pnd->pnd_wfh = FUSE_UNKNOWN_FH; 173 pnd->pnd_flags &= ~PND_WFH; 174 } 175 176 return; 177 } 178 179 uint64_t 180 perfuse_get_fh(puffs_cookie_t opc, int mode) 181 { 182 struct perfuse_node_data *pnd; 183 184 pnd = PERFUSE_NODE_DATA(opc); 185 186 if (mode & FWRITE) { 187 if (pnd->pnd_flags & PND_WFH) 188 return pnd->pnd_wfh; 189 } 190 191 if (mode & FREAD) { 192 if (pnd->pnd_flags & PND_RFH) 193 return pnd->pnd_rfh; 194 195 if (pnd->pnd_flags & PND_WFH) 196 return pnd->pnd_wfh; 197 198 } 199 200 return FUSE_UNKNOWN_FH; 201 } 202 203 /* ARGSUSED0 */ 204 char * 205 perfuse_node_path(struct perfuse_state *ps, puffs_cookie_t opc) 206 { 207 static char buf[MAXPATHLEN + 1]; 208 209 #if 0 210 if (node_path(ps, opc, buf, sizeof(buf)) == 0) 211 sprintf(buf, "/"); 212 #endif 213 sprintf(buf, "%s", PERFUSE_NODE_DATA(opc)->pnd_name); 214 215 return buf; 216 } 217 218 int 219 perfuse_ns_match(const int attrnamespace, const char *attrname) 220 { 221 const char *system_ns[] = { "system.", "trusted.", "security", NULL }; 222 int i; 223 224 for (i = 0; system_ns[i]; i++) { 225 if (strncmp(attrname, system_ns[i], strlen(system_ns[i])) == 0) 226 return (attrnamespace == EXTATTR_NAMESPACE_SYSTEM); 227 } 228 229 return (attrnamespace == EXTATTR_NAMESPACE_USER); 230 } 231 232 const char * 233 perfuse_native_ns(const int attrnamespace, const char *attrname, 234 char *fuse_attrname) 235 { 236 const struct perfuse_ns_map *pnm; 237 const struct perfuse_ns_map perfuse_ns_map[] = { 238 PERFUSE_NS_MAP("trusted", EXTATTR_NAMESPACE_SYSTEM), 239 PERFUSE_NS_MAP("security", EXTATTR_NAMESPACE_SYSTEM), 240 PERFUSE_NS_MAP("system", EXTATTR_NAMESPACE_SYSTEM), 241 PERFUSE_NS_MAP("user", EXTATTR_NAMESPACE_USER), 242 { NULL, 0, EXTATTR_NAMESPACE_USER }, 243 }; 244 245 /* 246 * If attribute has a reserved Linux namespace (e.g.: trusted.foo) 247 * and that namespace matches the requested native namespace 248 * we have nothing to do. 249 * Otherwise we have either: 250 * (system|trusted|security).* with user namespace: prepend user. 251 * anything else with system napespace: prepend system. 252 */ 253 for (pnm = perfuse_ns_map; pnm->pnm_ns; pnm++) { 254 if (strncmp(attrname, pnm->pnm_ns, pnm->pnm_nslen) != 0) 255 continue; 256 257 if (attrnamespace == pnm->pnm_native_ns) 258 return attrname; 259 260 /* (system|trusted|security).* with user namespace */ 261 if (attrnamespace == EXTATTR_NAMESPACE_USER) { 262 (void)snprintf(fuse_attrname, LINUX_XATTR_NAME_MAX, 263 "user.%s", attrname); 264 return (const char *)fuse_attrname; 265 } 266 } 267 268 /* anything else with system napespace */ 269 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) { 270 (void)snprintf(fuse_attrname, LINUX_XATTR_NAME_MAX, 271 "system.%s", attrname); 272 return (const char *)fuse_attrname; 273 } 274 275 return (const char *)attrname; 276 } 277 278 static __inline struct perfuse_node_hashlist * 279 perfuse_nidhash(struct perfuse_state *ps, uint64_t nodeid) 280 { 281 uint32_t hash; 282 283 hash = hash32_buf(&nodeid, sizeof(nodeid), HASH32_BUF_INIT); 284 285 return &ps->ps_nidhash[hash % ps->ps_nnidhash]; 286 } 287 288 struct perfuse_node_data * 289 perfuse_node_bynodeid(struct perfuse_state *ps, uint64_t nodeid) 290 { 291 struct perfuse_node_hashlist *plist; 292 struct perfuse_node_data *pnd; 293 294 plist = perfuse_nidhash(ps, nodeid); 295 296 LIST_FOREACH(pnd, plist, pnd_nident) 297 if (pnd->pnd_nodeid == nodeid) 298 break; 299 300 return pnd; 301 } 302 303 void 304 perfuse_node_cache(struct perfuse_state *ps, puffs_cookie_t opc) 305 { 306 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 307 struct perfuse_node_hashlist *nidlist; 308 309 if (pnd->pnd_flags & PND_REMOVED) 310 DERRX(EX_SOFTWARE, "%s: \"%s\" already removed", 311 __func__, pnd->pnd_name); 312 313 nidlist = perfuse_nidhash(ps, pnd->pnd_nodeid); 314 LIST_INSERT_HEAD(nidlist, pnd, pnd_nident); 315 316 return; 317 } 318 319 void 320 perfuse_cache_flush(puffs_cookie_t opc) 321 { 322 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 323 324 if (pnd->pnd_flags & PND_REMOVED) 325 DERRX(EX_SOFTWARE, "%s: \"%s\" already removed", 326 __func__, pnd->pnd_name); 327 328 LIST_REMOVE(pnd, pnd_nident); 329 330 return; 331 } 332