1 /* $NetBSD: subr.c,v 1.17 2012/03/21 10:10:36 matt 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/extattr.h> 37 38 #include "perfuse_priv.h" 39 40 struct perfuse_ns_map { 41 const char *pnm_ns; 42 const size_t pnm_nslen; 43 const int pnm_native_ns; 44 }; 45 46 #define PERFUSE_NS_MAP(ns, native_ns) \ 47 { ns ".", sizeof(ns), native_ns } 48 49 static size_t node_path(puffs_cookie_t, char *, size_t); 50 51 struct puffs_node * 52 perfuse_new_pn(struct puffs_usermount *pu, const char *name, 53 struct puffs_node *parent) 54 { 55 struct puffs_node *pn; 56 struct perfuse_node_data *pnd; 57 58 if ((pnd = malloc(sizeof(*pnd))) == NULL) 59 DERR(EX_OSERR, "%s: malloc failed", __func__); 60 61 if ((pn = puffs_pn_new(pu, pnd)) == NULL) 62 DERR(EX_SOFTWARE, "%s: puffs_pn_new failed", __func__); 63 64 (void)memset(pnd, 0, sizeof(*pnd)); 65 pnd->pnd_rfh = FUSE_UNKNOWN_FH; 66 pnd->pnd_wfh = FUSE_UNKNOWN_FH; 67 pnd->pnd_nodeid = PERFUSE_UNKNOWN_NODEID; 68 pnd->pnd_fuse_nlookup = 1; 69 pnd->pnd_puffs_nlookup = 1; 70 pnd->pnd_parent = parent; 71 pnd->pnd_pn = (puffs_cookie_t)pn; 72 (void)strlcpy(pnd->pnd_name, name, MAXPATHLEN); 73 TAILQ_INIT(&pnd->pnd_pcq); 74 TAILQ_INIT(&pnd->pnd_children); 75 76 if (parent != NULL) { 77 struct perfuse_node_data *parent_pnd; 78 79 parent_pnd = PERFUSE_NODE_DATA(parent); 80 TAILQ_INSERT_TAIL(&parent_pnd->pnd_children, pnd, pnd_next); 81 82 parent_pnd->pnd_childcount++; 83 } 84 85 return pn; 86 } 87 88 void 89 perfuse_destroy_pn(struct puffs_node *pn) 90 { 91 struct perfuse_node_data *pnd; 92 93 pnd = PERFUSE_NODE_DATA(pn); 94 95 if (pnd->pnd_parent != NULL) { 96 struct perfuse_node_data *parent_pnd; 97 98 parent_pnd = PERFUSE_NODE_DATA(pnd->pnd_parent); 99 TAILQ_REMOVE(&parent_pnd->pnd_children, pnd, pnd_next); 100 } 101 102 if ((pnd = puffs_pn_getpriv(pn)) != NULL) { 103 if (pnd->pnd_parent != NULL) 104 PERFUSE_NODE_DATA(pnd->pnd_parent)->pnd_childcount--; 105 106 if (pnd->pnd_dirent != NULL) 107 free(pnd->pnd_dirent); 108 109 if (pnd->pnd_all_fd != NULL) 110 free(pnd->pnd_all_fd); 111 #ifdef PERFUSE_DEBUG 112 if (pnd->pnd_flags & PND_OPEN) 113 DERRX(EX_SOFTWARE, "%s: file open", __func__); 114 115 if (!TAILQ_EMPTY(&pnd->pnd_pcq)) 116 DERRX(EX_SOFTWARE, "%s: non empty pnd_pcq", __func__); 117 118 if (pnd == NULL) 119 DERRX(EX_SOFTWARE, "%s: pnd == NULL ???", __func__); 120 #endif /* PERFUSE_DEBUG */ 121 122 free(pnd); 123 } 124 125 puffs_pn_put(pn); 126 127 return; 128 } 129 130 131 void 132 perfuse_new_fh(puffs_cookie_t opc, uint64_t fh, int mode) 133 { 134 struct perfuse_node_data *pnd; 135 136 pnd = PERFUSE_NODE_DATA(opc); 137 138 if (mode & FWRITE) { 139 if (pnd->pnd_flags & PND_WFH) 140 DERRX(EX_SOFTWARE, "%s: opc = %p, write fh already set", 141 __func__, (void *)opc); 142 pnd->pnd_wfh = fh; 143 pnd->pnd_flags |= PND_WFH; 144 } 145 146 if (mode & FREAD) { 147 if (pnd->pnd_flags & PND_RFH) 148 DERRX(EX_SOFTWARE, "%s: opc = %p, read fh already set", 149 __func__, (void *)opc); 150 pnd->pnd_rfh = fh; 151 pnd->pnd_flags |= PND_RFH; 152 } 153 154 return; 155 } 156 157 void 158 perfuse_destroy_fh(puffs_cookie_t opc, uint64_t fh) 159 { 160 struct perfuse_node_data *pnd; 161 162 pnd = PERFUSE_NODE_DATA(opc); 163 164 if (fh == pnd->pnd_rfh) { 165 if (!(pnd->pnd_flags & PND_RFH) && (fh != FUSE_UNKNOWN_FH)) 166 DERRX(EX_SOFTWARE, 167 "%s: opc = %p, unset rfh = %"PRIx64"", 168 __func__, (void *)opc, fh); 169 pnd->pnd_rfh = FUSE_UNKNOWN_FH; 170 pnd->pnd_flags &= ~PND_RFH; 171 } 172 173 if (fh == pnd->pnd_wfh) { 174 if (!(pnd->pnd_flags & PND_WFH) && (fh != FUSE_UNKNOWN_FH)) 175 DERRX(EX_SOFTWARE, 176 "%s: opc = %p, unset wfh = %"PRIx64"", 177 __func__, (void *)opc, fh); 178 pnd->pnd_wfh = FUSE_UNKNOWN_FH; 179 pnd->pnd_flags &= ~PND_WFH; 180 } 181 182 return; 183 } 184 185 uint64_t 186 perfuse_get_fh(puffs_cookie_t opc, int mode) 187 { 188 struct perfuse_node_data *pnd; 189 190 pnd = PERFUSE_NODE_DATA(opc); 191 192 if (mode & FWRITE) { 193 if (pnd->pnd_flags & PND_WFH) 194 return pnd->pnd_wfh; 195 } 196 197 if (mode & FREAD) { 198 if (pnd->pnd_flags & PND_RFH) 199 return pnd->pnd_rfh; 200 201 if (pnd->pnd_flags & PND_WFH) 202 return pnd->pnd_wfh; 203 204 } 205 206 return FUSE_UNKNOWN_FH; 207 } 208 209 static size_t 210 node_path(puffs_cookie_t opc, char *buf, size_t buflen) 211 { 212 struct perfuse_node_data *pnd; 213 size_t written; 214 215 pnd = PERFUSE_NODE_DATA(opc); 216 if (pnd->pnd_parent == opc) 217 return 0; 218 219 written = node_path(pnd->pnd_parent, buf, buflen); 220 buf += written; 221 buflen -= written; 222 223 return written + snprintf(buf, buflen, "/%s", pnd->pnd_name); 224 } 225 226 char * 227 perfuse_node_path(puffs_cookie_t opc) 228 { 229 static char buf[MAXPATHLEN + 1]; 230 231 if (node_path(opc, buf, sizeof(buf)) == 0) 232 sprintf(buf, "/"); 233 234 return buf; 235 } 236 237 const char * 238 perfuse_native_ns(const int attrnamespace, const char *attrname, 239 char *fuse_attrname) 240 { 241 const struct perfuse_ns_map *pnm; 242 const struct perfuse_ns_map perfuse_ns_map[] = { 243 PERFUSE_NS_MAP("trusted", EXTATTR_NAMESPACE_SYSTEM), 244 PERFUSE_NS_MAP("security", EXTATTR_NAMESPACE_SYSTEM), 245 PERFUSE_NS_MAP("system", EXTATTR_NAMESPACE_SYSTEM), 246 PERFUSE_NS_MAP("user", EXTATTR_NAMESPACE_USER), 247 { NULL, 0, EXTATTR_NAMESPACE_USER }, 248 }; 249 250 /* 251 * If attribute has a reserved Linux namespace (e.g.: trusted.foo) 252 * and that namespace matches the requested native namespace 253 * we have nothing to do. 254 * Otherwise we have either: 255 * (system|trusted|security).* with user namespace: prepend user. 256 * anything else with system napespace: prepend system. 257 */ 258 for (pnm = perfuse_ns_map; pnm->pnm_ns; pnm++) { 259 if (strncmp(attrname, pnm->pnm_ns, pnm->pnm_nslen) != 0) 260 continue; 261 262 if (attrnamespace == pnm->pnm_native_ns) 263 return attrname; 264 265 /* (system|trusted|security).* with user namespace */ 266 if (attrnamespace == EXTATTR_NAMESPACE_USER) { 267 (void)snprintf(fuse_attrname, LINUX_XATTR_NAME_MAX, 268 "user.%s", attrname); 269 return (const char *)fuse_attrname; 270 } 271 } 272 273 /* anything else with system napespace */ 274 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) { 275 (void)snprintf(fuse_attrname, LINUX_XATTR_NAME_MAX, 276 "system.%s", attrname); 277 return (const char *)fuse_attrname; 278 } 279 280 return (const char *)attrname; 281 } 282