static struct dhcp_lease *add_lease(GDHCPServer *dhcp_server, uint32_t expire, const uint8_t *chaddr, uint32_t yiaddr) { struct dhcp_lease *lease = NULL; int ret; ret = get_lease(dhcp_server, yiaddr, chaddr, &lease); if (ret != 0) return NULL; memset(lease, 0, sizeof(*lease)); memcpy(lease->lease_mac, chaddr, ETH_ALEN); lease->lease_nip = ntohl(yiaddr); if (expire == 0) lease->expire = time(NULL) + dhcp_server->lease_seconds; else lease->expire = expire; dhcp_server->lease_list = g_list_insert_sorted(dhcp_server->lease_list, lease, compare_expire); g_hash_table_insert(dhcp_server->nip_lease_hash, GINT_TO_POINTER((int) lease->lease_nip), lease); return lease; }
static inline long do_sys_truncate(const char * path, loff_t length) { struct nameidata nd; struct inode * inode; int error; error = -EINVAL; if (length < 0) /* sorry, but loff_t says... */ goto out; error = user_path_walk(path, &nd); if (error) goto out; inode = nd.dentry->d_inode; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ error = -EISDIR; if (S_ISDIR(inode->i_mode)) goto dput_and_out; error = -EINVAL; if (!S_ISREG(inode->i_mode)) goto dput_and_out; error = permission(inode,MAY_WRITE); if (error) goto dput_and_out; error = -EROFS; if (IS_RDONLY(inode)) goto dput_and_out; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; /* * Make sure that there are no leases. */ error = get_lease(inode, FMODE_WRITE); if (error) goto dput_and_out; error = get_write_access(inode); if (error) goto dput_and_out; error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); error = do_truncate(nd.dentry, length); } put_write_access(inode); dput_and_out: path_release(&nd); out: return error; }
/* * Set various file attributes. * N.B. After this call fhp needs an fh_put */ int nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, int check_guard, time_t guardtime) { struct dentry *dentry; struct inode *inode; int accmode = MAY_SATTR; int ftype = 0; int imode; int err; int size_change = 0; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) accmode |= MAY_WRITE|MAY_OWNER_OVERRIDE; if (iap->ia_valid & ATTR_SIZE) ftype = S_IFREG; /* Get inode */ err = fh_verify(rqstp, fhp, ftype, accmode); if (err || !iap->ia_valid) goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; /* NFSv2 does not differentiate between "set-[ac]time-to-now" * which only requires access, and "set-[ac]time-to-X" which * requires ownership. * So if it looks like it might be "set both to the same time which * is close to now", and if inode_change_ok fails, then we * convert to "set to now" instead of "set to explicit time" * * We only call inode_change_ok as the last test as technically * it is not an interface that we should be using. It is only * valid if the filesystem does not define it's own i_op->setattr. */ #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) #define MAX_TOUCH_TIME_ERROR (30*60) if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && iap->ia_mtime == iap->ia_atime ) { /* Looks probable. Now just make sure time is in the right ballpark. * Solaris, at least, doesn't seem to care what the time request is. * We require it be within 30 minutes of now. */ time_t delta = iap->ia_atime - CURRENT_TIME; if (delta<0) delta = -delta; if (delta < MAX_TOUCH_TIME_ERROR && inode_change_ok(inode, iap) != 0) { /* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME * this will cause notify_change to set these times to "now" */ iap->ia_valid &= ~BOTH_TIME_SET; } } /* The size case is special. It changes the file as well as the attributes. */ if (iap->ia_valid & ATTR_SIZE) { if (iap->ia_size < inode->i_size) { err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); if (err) goto out; } /* * If we are changing the size of the file, then * we need to break all leases. */ err = get_lease(inode, FMODE_WRITE); if (err) goto out_nfserr; err = get_write_access(inode); if (err) goto out_nfserr; err = locks_verify_truncate(inode, NULL, iap->ia_size); if (err) { put_write_access(inode); goto out_nfserr; } DQUOT_INIT(inode); } imode = inode->i_mode; if (iap->ia_valid & ATTR_MODE) { iap->ia_mode &= S_IALLUGO; imode = iap->ia_mode |= (imode & ~S_IALLUGO); } /* Revoke setuid/setgid bit on chown/chgrp */ if ((iap->ia_valid & ATTR_UID) && (imode & S_ISUID) && iap->ia_uid != inode->i_uid) { iap->ia_valid |= ATTR_MODE; iap->ia_mode = imode &= ~S_ISUID; } if ((iap->ia_valid & ATTR_GID) && (imode & S_ISGID) && iap->ia_gid != inode->i_gid) { iap->ia_valid |= ATTR_MODE; iap->ia_mode = imode &= ~S_ISGID; } /* Change the attributes. */ iap->ia_valid |= ATTR_CTIME; if (iap->ia_valid & ATTR_SIZE) { fh_lock(fhp); size_change = 1; } err = nfserr_notsync; if (!check_guard || guardtime == inode->i_ctime) { err = notify_change(dentry, iap); err = nfserrno(err); } if (size_change) { fh_unlock(fhp); put_write_access(inode); } if (!err) if (EX_ISSYNC(fhp->fh_export)) write_inode_now(inode, 1); out: return err; out_nfserr: err = nfserrno(err); goto out; }