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