1 1.51 christos /* $NetBSD: subr.c,v 1.51 2012/11/04 22:46:08 christos Exp $ */ 2 1.35 jmmv 3 1.35 jmmv /* 4 1.1 pooka * Copyright (c) 2006 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Redistribution and use in source and binary forms, with or without 7 1.1 pooka * modification, are permitted provided that the following conditions 8 1.35 jmmv * are met: 9 1.35 jmmv * 1. Redistributions of source code must retain the above copyright 10 1.1 pooka * notice, this list of conditions and the following disclaimer. 11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 pooka * notice, this list of conditions and the following disclaimer in the 13 1.1 pooka * documentation and/or other materials provided with the distribution. 14 1.35 jmmv * 15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 pooka * SUCH DAMAGE. 26 1.35 jmmv */ 27 1.35 jmmv 28 1.1 pooka #include <sys/cdefs.h> 29 1.1 pooka #ifndef lint 30 1.51 christos __RCSID("$NetBSD: subr.c,v 1.51 2012/11/04 22:46:08 christos Exp $"); 31 1.1 pooka #endif /* !lint */ 32 1.1 pooka 33 1.51 christos #include <stdio.h> 34 1.1 pooka #include <assert.h> 35 1.25 pooka #include <err.h> 36 1.1 pooka #include <errno.h> 37 1.1 pooka #include <puffs.h> 38 1.1 pooka #include <stdlib.h> 39 1.1 pooka #include <util.h> 40 1.1 pooka 41 1.1 pooka #include "psshfs.h" 42 1.1 pooka #include "sftp_proto.h" 43 1.1 pooka 44 1.1 pooka static void 45 1.1 pooka freedircache(struct psshfs_dir *base, size_t count) 46 1.1 pooka { 47 1.47 pooka size_t i; 48 1.1 pooka 49 1.1 pooka for (i = 0; i < count; i++) { 50 1.1 pooka free(base[i].entryname); 51 1.1 pooka base[i].entryname = NULL; 52 1.1 pooka } 53 1.1 pooka 54 1.1 pooka free(base); 55 1.1 pooka } 56 1.1 pooka 57 1.1 pooka #define ENTRYCHUNK 16 58 1.1 pooka static void 59 1.1 pooka allocdirs(struct psshfs_node *psn) 60 1.1 pooka { 61 1.1 pooka size_t oldtot = psn->denttot; 62 1.1 pooka 63 1.1 pooka psn->denttot += ENTRYCHUNK; 64 1.1 pooka psn->dir = erealloc(psn->dir, 65 1.1 pooka psn->denttot * sizeof(struct psshfs_dir)); 66 1.1 pooka memset(psn->dir + oldtot, 0, ENTRYCHUNK * sizeof(struct psshfs_dir)); 67 1.1 pooka } 68 1.1 pooka 69 1.36 pooka static void 70 1.36 pooka setpnva(struct puffs_usermount *pu, struct puffs_node *pn, 71 1.36 pooka const struct vattr *vap) 72 1.36 pooka { 73 1.48 pooka struct psshfs_ctx *pctx = puffs_getspecific(pu); 74 1.36 pooka struct psshfs_node *psn = pn->pn_data; 75 1.48 pooka struct vattr modva; 76 1.36 pooka 77 1.36 pooka /* 78 1.36 pooka * Check if the file was modified from below us. 79 1.36 pooka * If so, invalidate page cache. This is the only 80 1.36 pooka * sensible place we can do this in. 81 1.36 pooka */ 82 1.36 pooka if (pn->pn_va.va_mtime.tv_sec != PUFFS_VNOVAL) 83 1.36 pooka if (pn->pn_va.va_mtime.tv_sec != vap->va_mtime.tv_sec 84 1.36 pooka && pn->pn_va.va_type == VREG) 85 1.36 pooka puffs_inval_pagecache_node(pu, pn); 86 1.36 pooka 87 1.48 pooka modva = *vap; 88 1.48 pooka if (pctx->domangleuid && modva.va_uid == pctx->mangleuid) 89 1.48 pooka modva.va_uid = pctx->myuid; 90 1.48 pooka if (pctx->domanglegid && modva.va_gid == pctx->manglegid) 91 1.48 pooka modva.va_gid = pctx->mygid; 92 1.48 pooka 93 1.48 pooka puffs_setvattr(&pn->pn_va, &modva); 94 1.36 pooka psn->attrread = time(NULL); 95 1.36 pooka } 96 1.36 pooka 97 1.1 pooka struct psshfs_dir * 98 1.9 pooka lookup(struct psshfs_dir *bdir, size_t ndir, const char *name) 99 1.1 pooka { 100 1.9 pooka struct psshfs_dir *test; 101 1.47 pooka size_t i; 102 1.1 pooka 103 1.1 pooka for (i = 0; i < ndir; i++) { 104 1.9 pooka test = &bdir[i]; 105 1.9 pooka if (test->valid != 1) 106 1.1 pooka continue; 107 1.9 pooka if (strcmp(test->entryname, name) == 0) 108 1.9 pooka return test; 109 1.9 pooka } 110 1.9 pooka 111 1.9 pooka return NULL; 112 1.9 pooka } 113 1.9 pooka 114 1.9 pooka static struct psshfs_dir * 115 1.9 pooka lookup_by_entry(struct psshfs_dir *bdir, size_t ndir, struct puffs_node *entry) 116 1.9 pooka { 117 1.9 pooka struct psshfs_dir *test; 118 1.47 pooka size_t i; 119 1.9 pooka 120 1.9 pooka for (i = 0; i < ndir; i++) { 121 1.9 pooka test = &bdir[i]; 122 1.9 pooka if (test->valid != 1) 123 1.9 pooka continue; 124 1.9 pooka if (test->entry == entry) 125 1.9 pooka return test; 126 1.1 pooka } 127 1.1 pooka 128 1.1 pooka return NULL; 129 1.1 pooka } 130 1.1 pooka 131 1.37 pooka 132 1.37 pooka void 133 1.37 pooka closehandles(struct puffs_usermount *pu, struct psshfs_node *psn, int which) 134 1.37 pooka { 135 1.37 pooka struct psshfs_ctx *pctx = puffs_getspecific(pu); 136 1.37 pooka struct puffs_framebuf *pb1, *pb2; 137 1.37 pooka uint32_t reqid; 138 1.37 pooka 139 1.37 pooka if (psn->fhand_r && (which & HANDLE_READ)) { 140 1.37 pooka assert(psn->lazyopen_r == NULL); 141 1.37 pooka 142 1.37 pooka pb1 = psbuf_makeout(); 143 1.37 pooka reqid = NEXTREQ(pctx); 144 1.37 pooka psbuf_req_data(pb1, SSH_FXP_CLOSE, reqid, 145 1.37 pooka psn->fhand_r, psn->fhand_r_len); 146 1.46 pooka puffs_framev_enqueue_justsend(pu, pctx->sshfd_data, pb1, 1, 0); 147 1.37 pooka free(psn->fhand_r); 148 1.37 pooka psn->fhand_r = NULL; 149 1.37 pooka } 150 1.37 pooka 151 1.37 pooka if (psn->fhand_w && (which & HANDLE_WRITE)) { 152 1.37 pooka assert(psn->lazyopen_w == NULL); 153 1.37 pooka 154 1.37 pooka pb2 = psbuf_makeout(); 155 1.37 pooka reqid = NEXTREQ(pctx); 156 1.37 pooka psbuf_req_data(pb2, SSH_FXP_CLOSE, reqid, 157 1.37 pooka psn->fhand_w, psn->fhand_w_len); 158 1.46 pooka puffs_framev_enqueue_justsend(pu, pctx->sshfd_data, pb2, 1, 0); 159 1.37 pooka free(psn->fhand_w); 160 1.37 pooka psn->fhand_w = NULL; 161 1.37 pooka } 162 1.37 pooka 163 1.37 pooka psn->stat |= PSN_HANDLECLOSE; 164 1.37 pooka } 165 1.37 pooka 166 1.37 pooka void 167 1.37 pooka lazyopen_rresp(struct puffs_usermount *pu, struct puffs_framebuf *pb, 168 1.37 pooka void *arg, int error) 169 1.37 pooka { 170 1.37 pooka struct psshfs_node *psn = arg; 171 1.37 pooka 172 1.37 pooka /* XXX: this is not enough */ 173 1.37 pooka if (psn->stat & PSN_RECLAIMED) { 174 1.37 pooka error = ENOENT; 175 1.37 pooka goto moreout; 176 1.37 pooka } 177 1.37 pooka if (error) 178 1.37 pooka goto out; 179 1.37 pooka 180 1.37 pooka error = psbuf_expect_handle(pb, &psn->fhand_r, &psn->fhand_r_len); 181 1.37 pooka 182 1.37 pooka out: 183 1.37 pooka psn->lazyopen_err_r = error; 184 1.37 pooka psn->lazyopen_r = NULL; 185 1.37 pooka if (error) 186 1.37 pooka psn->stat &= ~PSN_DOLAZY_R; 187 1.37 pooka if (psn->stat & PSN_HANDLECLOSE && (psn->stat & PSN_LAZYWAIT_R) == 0) 188 1.37 pooka closehandles(pu, psn, HANDLE_READ); 189 1.37 pooka moreout: 190 1.37 pooka puffs_framebuf_destroy(pb); 191 1.37 pooka } 192 1.37 pooka 193 1.37 pooka void 194 1.37 pooka lazyopen_wresp(struct puffs_usermount *pu, struct puffs_framebuf *pb, 195 1.37 pooka void *arg, int error) 196 1.37 pooka { 197 1.37 pooka struct psshfs_node *psn = arg; 198 1.37 pooka 199 1.37 pooka /* XXX: this is not enough */ 200 1.37 pooka if (psn->stat & PSN_RECLAIMED) { 201 1.37 pooka error = ENOENT; 202 1.37 pooka goto moreout; 203 1.37 pooka } 204 1.37 pooka if (error) 205 1.37 pooka goto out; 206 1.37 pooka 207 1.37 pooka error = psbuf_expect_handle(pb, &psn->fhand_w, &psn->fhand_w_len); 208 1.37 pooka 209 1.37 pooka out: 210 1.37 pooka psn->lazyopen_err_w = error; 211 1.37 pooka psn->lazyopen_w = NULL; 212 1.37 pooka if (error) 213 1.37 pooka psn->stat &= ~PSN_DOLAZY_W; 214 1.37 pooka if (psn->stat & PSN_HANDLECLOSE && (psn->stat & PSN_LAZYWAIT_W) == 0) 215 1.37 pooka closehandles(pu, psn, HANDLE_WRITE); 216 1.37 pooka moreout: 217 1.37 pooka puffs_framebuf_destroy(pb); 218 1.37 pooka } 219 1.37 pooka 220 1.8 pooka struct readdirattr { 221 1.8 pooka struct psshfs_node *psn; 222 1.8 pooka int idx; 223 1.8 pooka char entryname[MAXPATHLEN+1]; 224 1.8 pooka }; 225 1.8 pooka 226 1.1 pooka int 227 1.38 pooka getpathattr(struct puffs_usermount *pu, const char *path, struct vattr *vap) 228 1.12 pooka { 229 1.38 pooka PSSHFSAUTOVAR(pu); 230 1.12 pooka 231 1.12 pooka psbuf_req_str(pb, SSH_FXP_LSTAT, reqid, path); 232 1.46 pooka GETRESPONSE(pb, pctx->sshfd); 233 1.12 pooka 234 1.12 pooka rv = psbuf_expect_attrs(pb, vap); 235 1.12 pooka 236 1.16 pooka out: 237 1.12 pooka PSSHFSRETURN(rv); 238 1.12 pooka } 239 1.12 pooka 240 1.12 pooka int 241 1.50 pooka getnodeattr(struct puffs_usermount *pu, struct puffs_node *pn, const char *path) 242 1.12 pooka { 243 1.31 pooka struct psshfs_ctx *pctx = puffs_getspecific(pu); 244 1.12 pooka struct psshfs_node *psn = pn->pn_data; 245 1.12 pooka struct vattr va; 246 1.40 pooka int rv; 247 1.12 pooka 248 1.31 pooka if (!psn->attrread || REFRESHTIMEOUT(pctx, time(NULL)-psn->attrread)) { 249 1.50 pooka rv = getpathattr(pu, path ? path : PNPATH(pn), &va); 250 1.40 pooka if (rv) 251 1.40 pooka return rv; 252 1.12 pooka 253 1.36 pooka setpnva(pu, pn, &va); 254 1.12 pooka } 255 1.12 pooka 256 1.12 pooka return 0; 257 1.12 pooka } 258 1.12 pooka 259 1.12 pooka int 260 1.41 pooka sftp_readdir(struct puffs_usermount *pu, struct psshfs_ctx *pctx, 261 1.1 pooka struct puffs_node *pn) 262 1.1 pooka { 263 1.41 pooka struct puffs_cc *pcc = puffs_cc_getcc(pu); 264 1.1 pooka struct psshfs_node *psn = pn->pn_data; 265 1.1 pooka struct psshfs_dir *olddir, *testd; 266 1.14 pooka struct puffs_framebuf *pb; 267 1.1 pooka uint32_t reqid = NEXTREQ(pctx); 268 1.10 pooka uint32_t count, dhandlen; 269 1.1 pooka char *dhand = NULL; 270 1.10 pooka size_t nent; 271 1.29 pooka char *longname = NULL; 272 1.47 pooka size_t idx; 273 1.47 pooka int rv; 274 1.1 pooka 275 1.1 pooka assert(pn->pn_va.va_type == VDIR); 276 1.16 pooka idx = 0; 277 1.16 pooka olddir = psn->dir; 278 1.16 pooka nent = psn->dentnext; 279 1.1 pooka 280 1.32 pooka if (psn->dir && psn->dentread 281 1.32 pooka && !REFRESHTIMEOUT(pctx, time(NULL) - psn->dentread)) 282 1.1 pooka return 0; 283 1.1 pooka 284 1.39 pooka if (psn->dentread) { 285 1.39 pooka if ((rv = puffs_inval_namecache_dir(pu, pn))) 286 1.39 pooka warn("readdir: dcache inval fail %p", pn); 287 1.39 pooka } 288 1.5 pooka 289 1.14 pooka pb = psbuf_makeout(); 290 1.7 pooka psbuf_req_str(pb, SSH_FXP_OPENDIR, reqid, PNPATH(pn)); 291 1.27 pooka if (puffs_framev_enqueue_cc(pcc, pctx->sshfd, pb, 0) == -1) { 292 1.27 pooka rv = errno; 293 1.27 pooka goto wayout; 294 1.27 pooka } 295 1.1 pooka rv = psbuf_expect_handle(pb, &dhand, &dhandlen); 296 1.1 pooka if (rv) 297 1.1 pooka goto wayout; 298 1.1 pooka 299 1.1 pooka /* 300 1.1 pooka * Well, the following is O(n^2), so feel free to improve if it 301 1.1 pooka * gets too taxing on your system. 302 1.1 pooka */ 303 1.1 pooka 304 1.8 pooka /* 305 1.8 pooka * note: for the "getattr in batch" to work, this must be before 306 1.8 pooka * the attribute-getting. Otherwise times for first entries in 307 1.8 pooka * large directories might expire before the directory itself and 308 1.8 pooka * result in one-by-one attribute fetching. 309 1.8 pooka */ 310 1.8 pooka psn->dentread = time(NULL); 311 1.8 pooka 312 1.1 pooka psn->dentnext = 0; 313 1.1 pooka psn->denttot = 0; 314 1.1 pooka psn->dir = NULL; 315 1.1 pooka 316 1.1 pooka for (;;) { 317 1.1 pooka reqid = NEXTREQ(pctx); 318 1.14 pooka psbuf_recycleout(pb); 319 1.1 pooka psbuf_req_data(pb, SSH_FXP_READDIR, reqid, dhand, dhandlen); 320 1.46 pooka GETRESPONSE(pb, pctx->sshfd); 321 1.1 pooka 322 1.1 pooka /* check for EOF */ 323 1.14 pooka if (psbuf_get_type(pb) == SSH_FXP_STATUS) { 324 1.1 pooka rv = psbuf_expect_status(pb); 325 1.1 pooka goto out; 326 1.1 pooka } 327 1.1 pooka rv = psbuf_expect_name(pb, &count); 328 1.1 pooka if (rv) 329 1.1 pooka goto out; 330 1.1 pooka 331 1.1 pooka for (; count--; idx++) { 332 1.1 pooka if (idx == psn->denttot) 333 1.1 pooka allocdirs(psn); 334 1.14 pooka if ((rv = psbuf_get_str(pb, 335 1.14 pooka &psn->dir[idx].entryname, NULL))) 336 1.1 pooka goto out; 337 1.29 pooka if ((rv = psbuf_get_str(pb, &longname, NULL)) != 0) 338 1.1 pooka goto out; 339 1.29 pooka if ((rv = psbuf_get_vattr(pb, &psn->dir[idx].va)) != 0) 340 1.1 pooka goto out; 341 1.1 pooka if (sscanf(longname, "%*s%d", 342 1.1 pooka &psn->dir[idx].va.va_nlink) != 1) { 343 1.1 pooka rv = EPROTO; 344 1.1 pooka goto out; 345 1.1 pooka } 346 1.1 pooka free(longname); 347 1.29 pooka longname = NULL; 348 1.49 pooka 349 1.49 pooka /* 350 1.49 pooka * In case of DOT, copy the attributes (mostly 351 1.49 pooka * because we want the link count for the root dir). 352 1.49 pooka */ 353 1.49 pooka if (strcmp(psn->dir[idx].entryname, ".") == 0) { 354 1.49 pooka setpnva(pu, pn, &psn->dir[idx].va); 355 1.49 pooka } 356 1.1 pooka 357 1.42 pooka /* 358 1.42 pooka * Check if we already have a psshfs_dir for the 359 1.42 pooka * name we are processing. If so, use the old one. 360 1.42 pooka * If not, create a new one 361 1.42 pooka */ 362 1.1 pooka testd = lookup(olddir, nent, psn->dir[idx].entryname); 363 1.1 pooka if (testd) { 364 1.1 pooka psn->dir[idx].entry = testd->entry; 365 1.42 pooka /* 366 1.42 pooka * Has entry. Update attributes to what 367 1.42 pooka * we just got from the server. 368 1.42 pooka */ 369 1.42 pooka if (testd->entry) { 370 1.40 pooka setpnva(pu, testd->entry, 371 1.40 pooka &psn->dir[idx].va); 372 1.45 pooka psn->dir[idx].va.va_fileid 373 1.45 pooka = testd->entry->pn_va.va_fileid; 374 1.42 pooka 375 1.42 pooka /* 376 1.42 pooka * No entry. This can happen in two cases: 377 1.42 pooka * 1) the file was created "behind our back" 378 1.42 pooka * on the server 379 1.42 pooka * 2) we do two readdirs before we instantiate 380 1.42 pooka * the node (or run with -t 0). 381 1.42 pooka * 382 1.42 pooka * Cache attributes from the server in 383 1.42 pooka * case we want to instantiate this node 384 1.44 pooka * soon. Also preserve the old inode number 385 1.44 pooka * which was given when the dirent was created. 386 1.42 pooka */ 387 1.42 pooka } else { 388 1.43 pooka psn->dir[idx].va.va_fileid 389 1.43 pooka = testd->va.va_fileid; 390 1.40 pooka testd->va = psn->dir[idx].va; 391 1.42 pooka } 392 1.42 pooka 393 1.42 pooka /* No previous entry? Initialize this one. */ 394 1.1 pooka } else { 395 1.1 pooka psn->dir[idx].entry = NULL; 396 1.1 pooka psn->dir[idx].va.va_fileid = pctx->nextino++; 397 1.1 pooka } 398 1.40 pooka psn->dir[idx].attrread = psn->dentread; 399 1.1 pooka psn->dir[idx].valid = 1; 400 1.1 pooka } 401 1.1 pooka } 402 1.1 pooka 403 1.1 pooka out: 404 1.1 pooka /* XXX: rv */ 405 1.1 pooka psn->dentnext = idx; 406 1.1 pooka freedircache(olddir, nent); 407 1.1 pooka 408 1.1 pooka reqid = NEXTREQ(pctx); 409 1.14 pooka psbuf_recycleout(pb); 410 1.1 pooka psbuf_req_data(pb, SSH_FXP_CLOSE, reqid, dhand, dhandlen); 411 1.28 pooka puffs_framev_enqueue_justsend(pu, pctx->sshfd, pb, 1, 0); 412 1.11 pooka free(dhand); 413 1.29 pooka free(longname); 414 1.21 pooka 415 1.12 pooka return rv; 416 1.1 pooka 417 1.1 pooka wayout: 418 1.1 pooka free(dhand); 419 1.11 pooka PSSHFSRETURN(rv); 420 1.1 pooka } 421 1.1 pooka 422 1.1 pooka struct puffs_node * 423 1.1 pooka makenode(struct puffs_usermount *pu, struct puffs_node *parent, 424 1.50 pooka const struct psshfs_dir *pd, const struct vattr *vap) 425 1.1 pooka { 426 1.1 pooka struct psshfs_node *psn_parent = parent->pn_data; 427 1.1 pooka struct psshfs_node *psn; 428 1.1 pooka struct puffs_node *pn; 429 1.1 pooka 430 1.1 pooka psn = emalloc(sizeof(struct psshfs_node)); 431 1.1 pooka memset(psn, 0, sizeof(struct psshfs_node)); 432 1.1 pooka 433 1.1 pooka pn = puffs_pn_new(pu, psn); 434 1.1 pooka if (!pn) { 435 1.1 pooka free(psn); 436 1.1 pooka return NULL; 437 1.1 pooka } 438 1.36 pooka setpnva(pu, pn, &pd->va); 439 1.36 pooka setpnva(pu, pn, vap); 440 1.40 pooka psn->attrread = pd->attrread; 441 1.1 pooka 442 1.1 pooka psn->parent = parent; 443 1.1 pooka psn_parent->childcount++; 444 1.1 pooka 445 1.30 pooka TAILQ_INIT(&psn->pw); 446 1.26 pooka 447 1.1 pooka return pn; 448 1.1 pooka } 449 1.1 pooka 450 1.1 pooka struct puffs_node * 451 1.1 pooka allocnode(struct puffs_usermount *pu, struct puffs_node *parent, 452 1.1 pooka const char *entryname, const struct vattr *vap) 453 1.1 pooka { 454 1.13 pooka struct psshfs_ctx *pctx = puffs_getspecific(pu); 455 1.1 pooka struct psshfs_dir *pd; 456 1.3 pooka struct puffs_node *pn; 457 1.1 pooka 458 1.1 pooka pd = direnter(parent, entryname); 459 1.1 pooka 460 1.1 pooka pd->va.va_fileid = pctx->nextino++; 461 1.2 pooka if (vap->va_type == VDIR) { 462 1.1 pooka pd->va.va_nlink = 2; 463 1.2 pooka parent->pn_va.va_nlink++; 464 1.2 pooka } else { 465 1.1 pooka pd->va.va_nlink = 1; 466 1.2 pooka } 467 1.1 pooka 468 1.3 pooka pn = makenode(pu, parent, pd, vap); 469 1.50 pooka if (pn) { 470 1.3 pooka pd->va.va_fileid = pn->pn_va.va_fileid; 471 1.50 pooka pd->entry = pn; 472 1.50 pooka } 473 1.3 pooka 474 1.3 pooka return pn; 475 1.1 pooka } 476 1.1 pooka 477 1.1 pooka struct psshfs_dir * 478 1.1 pooka direnter(struct puffs_node *parent, const char *entryname) 479 1.1 pooka { 480 1.1 pooka struct psshfs_node *psn_parent = parent->pn_data; 481 1.1 pooka struct psshfs_dir *pd; 482 1.1 pooka int i; 483 1.1 pooka 484 1.1 pooka /* create directory entry */ 485 1.1 pooka if (psn_parent->denttot == psn_parent->dentnext) 486 1.1 pooka allocdirs(psn_parent); 487 1.1 pooka 488 1.1 pooka i = psn_parent->dentnext; 489 1.1 pooka pd = &psn_parent->dir[i]; 490 1.1 pooka pd->entryname = estrdup(entryname); 491 1.1 pooka pd->valid = 1; 492 1.8 pooka pd->attrread = 0; 493 1.4 pooka puffs_vattr_null(&pd->va); 494 1.1 pooka psn_parent->dentnext++; 495 1.1 pooka 496 1.1 pooka return pd; 497 1.1 pooka } 498 1.1 pooka 499 1.1 pooka void 500 1.9 pooka doreclaim(struct puffs_node *pn) 501 1.9 pooka { 502 1.9 pooka struct psshfs_node *psn = pn->pn_data; 503 1.9 pooka struct psshfs_node *psn_parent; 504 1.9 pooka struct psshfs_dir *dent; 505 1.9 pooka 506 1.9 pooka psn_parent = psn->parent->pn_data; 507 1.9 pooka psn_parent->childcount--; 508 1.9 pooka 509 1.11 pooka /* 510 1.11 pooka * Null out entry from directory. Do not treat a missing entry 511 1.11 pooka * as an invariant error, since the node might be removed from 512 1.11 pooka * under us, and we might do a readdir before the reclaim resulting 513 1.11 pooka * in no directory entry in the parent directory. 514 1.11 pooka */ 515 1.9 pooka dent = lookup_by_entry(psn_parent->dir, psn_parent->dentnext, pn); 516 1.11 pooka if (dent) 517 1.11 pooka dent->entry = NULL; 518 1.9 pooka 519 1.21 pooka if (pn->pn_va.va_type == VDIR) { 520 1.9 pooka freedircache(psn->dir, psn->dentnext); 521 1.23 pooka psn->denttot = psn->dentnext = 0; 522 1.21 pooka } 523 1.33 pooka if (psn->symlink) 524 1.33 pooka free(psn->symlink); 525 1.9 pooka 526 1.9 pooka puffs_pn_put(pn); 527 1.9 pooka } 528 1.9 pooka 529 1.9 pooka void 530 1.9 pooka nukenode(struct puffs_node *node, const char *entryname, int reclaim) 531 1.1 pooka { 532 1.1 pooka struct psshfs_node *psn, *psn_parent; 533 1.1 pooka struct psshfs_dir *pd; 534 1.1 pooka 535 1.1 pooka psn = node->pn_data; 536 1.1 pooka psn_parent = psn->parent->pn_data; 537 1.1 pooka pd = lookup(psn_parent->dir, psn_parent->dentnext, entryname); 538 1.1 pooka assert(pd != NULL); 539 1.1 pooka pd->valid = 0; 540 1.1 pooka free(pd->entryname); 541 1.1 pooka pd->entryname = NULL; 542 1.1 pooka 543 1.9 pooka if (node->pn_va.va_type == VDIR) 544 1.1 pooka psn->parent->pn_va.va_nlink--; 545 1.6 pooka 546 1.9 pooka if (reclaim) 547 1.9 pooka doreclaim(node); 548 1.1 pooka } 549