Ejemplo n.º 1
0
/*
 * cap_info_write()
 *
 * This is the write() entry in the file_operations structure for CAP
 * metadata files.  The purpose is to transfer up to 'count' bytes
 * to the file corresponding to 'inode' beginning at offset
 * '*ppos' from user-space at the address 'buf'.
 * The return value is the number of bytes actually transferred.
 */
static hfs_rwret_t cap_info_write(struct file *filp, const char *buf, 
				  hfs_rwarg_t count, loff_t *ppos)
{
        struct inode *inode = filp->f_dentry->d_inode;
	hfs_u32 pos;

	if (!S_ISREG(inode->i_mode)) {
		hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode);
		return -EINVAL;
	}
	if (count <= 0) {
		return 0;
	}
	
	pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;

	if (pos > HFS_FORK_MAX) {
		return 0;
	}

	*ppos += count;
	if (*ppos > HFS_FORK_MAX) {
		*ppos = HFS_FORK_MAX;
		count = HFS_FORK_MAX - pos;
	}

	if (*ppos > inode->i_size)
	        inode->i_size = *ppos;

	/* Only deal with the part we store in memory */
	if (pos < sizeof(struct hfs_cap_info)) {
		int end, mem_count;
		struct hfs_cat_entry *entry = HFS_I(inode)->entry;
		struct hfs_cap_info meta;

		mem_count = sizeof(struct hfs_cap_info) - pos;
		if (mem_count > count) {
			mem_count = count;
		}
		end = pos + mem_count;

		cap_build_meta(&meta, entry);
		mem_count -= copy_from_user(((char *)&meta) + pos, buf, mem_count);

		/* Update finder attributes if changed */
		if (OVERLAPS(pos, end, struct hfs_cap_info, fi_fndr)) {
			memcpy(&entry->info, meta.fi_fndr, 32);
			hfs_cat_mark_dirty(entry);
		}
Ejemplo n.º 2
0
static int __hfs_notify_change(struct dentry *dentry, struct iattr * attr, int kind)
{
    struct inode *inode = dentry->d_inode;
    struct hfs_cat_entry *entry = HFS_I(inode)->entry;
    struct dentry **de = entry->sys_entry;
    struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
    int error=0, i;

    lock_kernel();

    error = inode_change_ok(inode, attr); /* basic permission checks */
    if (error) {
        /* Let netatalk's afpd think chmod() always succeeds */
        if (hsb->s_afpd &&
                (attr->ia_valid == (ATTR_MODE | ATTR_CTIME))) {
            error = 0;
        }
        goto out;
    }

    /* no uig/gid changes and limit which mode bits can be set */
    if (((attr->ia_valid & ATTR_UID) &&
            (attr->ia_uid != hsb->s_uid)) ||
            ((attr->ia_valid & ATTR_GID) &&
             (attr->ia_gid != hsb->s_gid)) ||
            ((attr->ia_valid & ATTR_MODE) &&
             (((entry->type == HFS_CDR_DIR) &&
               (attr->ia_mode != inode->i_mode))||
              (attr->ia_mode & ~HFS_VALID_MODE_BITS)))) {
        if( hsb->s_quiet ) {
            error = 0;
            goto out;
        }
    }

    if (entry->type == HFS_CDR_DIR) {
        attr->ia_valid &= ~ATTR_MODE;
    } else if (attr->ia_valid & ATTR_MODE) {
        /* Only the 'w' bits can ever change and only all together. */
        if (attr->ia_mode & S_IWUSR) {
            attr->ia_mode = inode->i_mode | S_IWUGO;
        } else {
            attr->ia_mode = inode->i_mode & ~S_IWUGO;
        }
        attr->ia_mode &= ~hsb->s_umask;
    }
    /*
     * Normal files handle size change in normal way.
     * Oddballs are served here.
     */
    if (attr->ia_valid & ATTR_SIZE) {
        if (kind == HFS_CAP) {
            inode->i_size = attr->ia_size;
            if (inode->i_size > HFS_FORK_MAX)
                inode->i_size = HFS_FORK_MAX;
            mark_inode_dirty(inode);
            attr->ia_valid &= ~ATTR_SIZE;
        } else if (kind == HFS_HDR) {
            hdr_truncate(inode, attr->ia_size);
            attr->ia_valid &= ~ATTR_SIZE;
        }
    }
    error = inode_setattr(inode, attr);
    if (error)
        goto out;

    /* We wouldn't want to mess with the sizes of the other fork */
    attr->ia_valid &= ~ATTR_SIZE;

    /* We must change all in-core inodes corresponding to this file. */
    for (i = 0; i < 4; ++i) {
        if (de[i] && (de[i] != dentry)) {
            inode_setattr(de[i]->d_inode, attr);
        }
    }

    /* Change the catalog entry if needed */
    if (attr->ia_valid & ATTR_MTIME) {
        entry->modify_date = hfs_u_to_mtime(inode->i_mtime.tv_sec);
        hfs_cat_mark_dirty(entry);
    }
    if (attr->ia_valid & ATTR_MODE) {
        hfs_u8 new_flags;

        if (inode->i_mode & S_IWUSR) {
            new_flags = entry->u.file.flags & ~HFS_FIL_LOCK;
        } else {
            new_flags = entry->u.file.flags | HFS_FIL_LOCK;
        }

        if (new_flags != entry->u.file.flags) {
            entry->u.file.flags = new_flags;
            hfs_cat_mark_dirty(entry);
        }
    }
    /* size changes handled in hfs_extent_adj() */

out:
    unlock_kernel();
    return error;
}