/*
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Check if the file was modified from below us.
* If so, invalidate page cache. This is the only
* sensible place we can do this in.
*/
if (pn->pn_va.va_mtime.tv_sec != PUFFS_VNOVAL)
if (pn->pn_va.va_mtime.tv_sec != vap->va_mtime.tv_sec
&& pn->pn_va.va_type == VREG)
puffs_inval_pagecache_node(pu, pn);
/*
* Well, the following is O(n^2), so feel free to improve if it
* gets too taxing on your system.
*/
/*
* note: for the "getattr in batch" to work, this must be before
* the attribute-getting. Otherwise times for first entries in
* large directories might expire before the directory itself and
* result in one-by-one attribute fetching.
*/
psn->dentread = time(NULL);
/* check for EOF */
if (psbuf_get_type(pb) == SSH_FXP_STATUS) {
rv = psbuf_expect_status(pb);
goto out;
}
rv = psbuf_expect_name(pb, &count);
if (rv)
goto out;
for (; count--; idx++) {
if (idx == psn->denttot)
allocdirs(psn);
if ((rv = psbuf_get_str(pb,
&psn->dir[idx].entryname, NULL)))
goto out;
if ((rv = psbuf_get_str(pb, &longname, NULL)) != 0)
goto out;
if ((rv = psbuf_get_vattr(pb, &psn->dir[idx].va)) != 0)
goto out;
if (sscanf(longname, "%*s%d",
&psn->dir[idx].va.va_nlink) != 1) {
rv = EPROTO;
goto out;
}
free(longname);
longname = NULL;
/*
* In case of DOT, copy the attributes (mostly
* because we want the link count for the root dir).
*/
if (strcmp(psn->dir[idx].entryname, ".") == 0) {
setpnva(pu, pn, &psn->dir[idx].va);
}
/*
* Check if we already have a psshfs_dir for the
* name we are processing. If so, use the old one.
* If not, create a new one
*/
testd = lookup(olddir, nent, psn->dir[idx].entryname);
if (testd) {
psn->dir[idx].entry = testd->entry;
/*
* Has entry. Update attributes to what
* we just got from the server.
*/
if (testd->entry) {
setpnva(pu, testd->entry,
&psn->dir[idx].va);
psn->dir[idx].va.va_fileid
= testd->entry->pn_va.va_fileid;
/*
* No entry. This can happen in two cases:
* 1) the file was created "behind our back"
* on the server
* 2) we do two readdirs before we instantiate
* the node (or run with -t 0).
*
* Cache attributes from the server in
* case we want to instantiate this node
* soon. Also preserve the old inode number
* which was given when the dirent was created.
*/
} else {
psn->dir[idx].va.va_fileid
= testd->va.va_fileid;
testd->va = psn->dir[idx].va;
}
/*
* Null out entry from directory. Do not treat a missing entry
* as an invariant error, since the node might be removed from
* under us, and we might do a readdir before the reclaim resulting
* in no directory entry in the parent directory.
*/
dent = lookup_by_entry(psn_parent->dir, psn_parent->dentnext, pn);
if (dent)
dent->entry = NULL;
if (pn->pn_va.va_type == VDIR) {
freedircache(psn->dir, psn->dentnext);
psn->denttot = psn->dentnext = 0;
}
if (psn->symlink)
free(psn->symlink);