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