/*
* Copyright (c) 2007 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.
*/
/*
* set attributes to what is specified. XXX: no rollback in case of failure
*/
static int
processvattr(const char *path, const struct vattr *va, int regular)
{
struct timeval tv[2];
/* XXX: -1 == PUFFS_VNOVAL, but shouldn't trust that */
if (va->va_uid != (unsigned)-1 || va->va_gid != (unsigned)-1)
if (lchown(path, va->va_uid, va->va_gid) == -1)
return errno;
if (va->va_mode != (unsigned)PUFFS_VNOVAL)
if (lchmod(path, va->va_mode) == -1)
return errno;
if (regular && va->va_size != (u_quad_t)PUFFS_VNOVAL)
if (truncate(path, (off_t)va->va_size) == -1)
return errno;
return 0;
}
/*
* Kludge to open files which aren't writable *any longer*. This kinda
* works because the vfs layer does validation checks based on the file's
* permissions to allow writable opening before opening them. However,
* the problem arises if we want to create a file, write to it (cache),
* adjust permissions and then flush the file.
*/
static int
writeableopen(const char *path)
{
struct stat sb;
mode_t origmode;
int sverr = 0;
int fd;
fd = open(path, O_WRONLY);
if (fd == -1) {
if (errno == EACCES) {
if (stat(path, &sb) == -1)
return -1;
origmode = sb.st_mode & ALLPERMS;
/*
* XXX: this is the stupidest crap ever, but:
* getfh() returns the fhandle type, when we are expected to deliver
* the fid type. Just adjust it a bit and stop whining.
*
* Yes, this really really needs fixing. Yes, *REALLY*.
*/
#define FHANDLE_HEADERLEN 8
struct kernfid {
unsigned short fid_len; /* length of data in bytes */
unsigned short fid_reserved; /* compat: historic align */
char fid_data[0]; /* data (variable length) */
};
/*
* This routine only supports file handles which have been issued while
* the server was alive. Not really stable ones, that is.
*/
/*ARGSUSED*/
int
puffs_null_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize,
struct puffs_newinfo *pni)
{
struct puffs_node *pn_res;
int
puffs_null_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc,
struct puffs_newinfo *pni, const struct puffs_cn *pcn)
{
struct puffs_node *pn = opc, *pn_res;
struct stat sb;
int rv;
assert(pn->pn_va.va_type == VDIR);
/*
* Note to whoever is copypasting this: you must first check
* if the node is there and only then do nodewalk. Alternatively
* you could make sure that you don't return unlinked/rmdir'd
* nodes in some other fashion
*/
rv = lstat(PCNPATH(pcn), &sb);
if (rv)
return errno;
/* XXX2: nodewalk is a bit too slow here */
pn_res = puffs_pn_nodewalk(pu, inodecmp, &sb.st_ino);
if (pn_res == NULL) {
pn_res = puffs_pn_new(pu, NULL);
if (pn_res == NULL)
return ENOMEM;
puffs_stat2vattr(&pn_res->pn_va, &sb);
}
/*
* XXX: need to do trickery here, telldir/seekdir would be nice, but
* then we'd need to keep state, which I'm too lazy to keep
*/
while (i--) {
rv = readdir_r(dp, &entry, &result);
if (rv != 0)
goto out;
if (!result) {
*eofflag = 1;
goto out;
}
}
for (;;) {
rv = readdir_r(dp, &entry, &result);
if (rv != 0)
goto out;
if (!result) {
*eofflag = 1;
goto out;
}
if (_DIRENT_SIZE(result) > *reslen)
goto out;
*de = *result;
*reslen -= _DIRENT_SIZE(result);
de = _DIRENT_NEXT(de);