err = get_user(attr, user_attr); if (err) goto out;
err = mnt_want_write_file(file); if (err) goto out;
inode_lock(inode);
/* * ATTR_VOLUME and ATTR_DIR cannot be changed; this also * prevents the user from turning us into a VFAT * longname entry. Also, we obviously can't set * any of the NTFS attributes in the high 24 bits.
*/
attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); /* Merge in ATTR_VOLUME and ATTR_DIR */
attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |
(is_dir ? ATTR_DIR : 0);
oldattr = fat_make_attrs(inode);
/* * The security check is questionable... We single * out the RO attribute for checking by the security * module, just because it maps to a file mode.
*/
err = security_inode_setattr(file_mnt_idmap(file),
file->f_path.dentry, &ia); if (err) goto out_unlock_inode;
/* This MUST be done before doing anything irreversible... */
err = fat_setattr(file_mnt_idmap(file), file->f_path.dentry, &ia); if (err) goto out_unlock_inode;
fsnotify_change(file->f_path.dentry, ia.ia_valid); if (sbi->options.sys_immutable) { if (attr & ATTR_SYS)
inode->i_flags |= S_IMMUTABLE; else
inode->i_flags &= ~S_IMMUTABLE;
}
err = generic_cont_expand_simple(inode, size); if (err) goto out;
fat_truncate_time(inode, NULL, S_CTIME|S_MTIME);
mark_inode_dirty(inode); if (IS_SYNC(inode)) { int err2;
/* * Opencode syncing since we don't have a file open to use * standard fsync path.
*/
err = filemap_fdatawrite_range(mapping, start,
start + count - 1);
err2 = sync_mapping_buffers(mapping); if (!err)
err = err2;
err2 = write_inode_now(inode, 1); if (!err)
err = err2; if (!err) {
err = filemap_fdatawait_range(mapping, start,
start + count - 1);
}
}
out: return err;
}
/* * Preallocate space for a file. This implements fat's fallocate file * operation, which gets called from sys_fallocate system call. User * space requests len bytes at offset. If FALLOC_FL_KEEP_SIZE is set * we just allocate clusters without zeroing them out. Otherwise we * allocate and zero out clusters via an expanding truncate.
*/ staticlong fat_fallocate(struct file *file, int mode,
loff_t offset, loff_t len)
{ int nr_cluster; /* Number of clusters to be allocated */
loff_t mm_bytes; /* Number of bytes to be allocated for file */
loff_t ondisksize; /* block aligned on-disk size in bytes*/ struct inode *inode = file->f_mapping->host; struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); int err = 0;
/* No support for hole punch or other fallocate flags. */ if (mode & ~FALLOC_FL_KEEP_SIZE) return -EOPNOTSUPP;
/* No support for dir */ if (!S_ISREG(inode->i_mode)) return -EOPNOTSUPP;
inode_lock(inode); if (mode & FALLOC_FL_KEEP_SIZE) {
ondisksize = inode->i_blocks << 9; if ((offset + len) <= ondisksize) goto error;
/* First compute the number of clusters to be allocated */
mm_bytes = offset + len - ondisksize;
nr_cluster = (mm_bytes + (sbi->cluster_size - 1)) >>
sbi->cluster_bits;
/* Start the allocation.We are not zeroing out the clusters */ while (nr_cluster-- > 0) {
err = fat_add_cluster(inode); if (err) goto error;
}
} else { if ((offset + len) <= i_size_read(inode)) goto error;
/* This is just an expanding truncate */
err = fat_cont_expand(inode, (offset + len));
}
error:
inode_unlock(inode); return err;
}
/* Free all clusters after the skip'th cluster. */ staticint fat_free(struct inode *inode, int skip)
{ struct super_block *sb = inode->i_sb; int err, wait, free_start, i_start, i_logstart;
/* * This protects against truncating a file bigger than it was then * trying to write into the hole.
*/ if (MSDOS_I(inode)->mmu_private > offset)
MSDOS_I(inode)->mmu_private = offset;
/* * Note, the basic check is already done by a caller of * (attr->ia_mode & ~FAT_VALID_MODE)
*/
if (S_ISREG(inode->i_mode))
mask = sbi->options.fs_fmask; else
mask = sbi->options.fs_dmask;
perm = *mode_ptr & ~(S_IFMT | mask);
/* * Of the r and x bits, all (subject to umask) must be present. Of the * w bits, either all (subject to umask) or none must be present. * * If fat_mode_can_hold_ro(inode) is false, can't change w bits.
*/ if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) return -EPERM; if (fat_mode_can_hold_ro(inode)) { if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) return -EPERM;
} else { if ((perm & S_IWUGO) != (S_IWUGO & ~mask)) return -EPERM;
}
/* Check for setting the inode time. */
ia_valid = attr->ia_valid; if (ia_valid & TIMES_SET_FLAGS) { if (fat_allow_set_time(idmap, sbi, inode))
attr->ia_valid &= ~TIMES_SET_FLAGS;
}
error = setattr_prepare(idmap, dentry, attr);
attr->ia_valid = ia_valid; if (error) { if (sbi->options.quiet)
error = 0; goto out;
}
/* * Expand the file. Since inode_setattr() updates ->i_size * before calling the ->truncate(), but FAT needs to fill the * hole before it. XXX: this is no longer true with new truncate * sequence.
*/ if (attr->ia_valid & ATTR_SIZE) {
inode_dio_wait(inode);
if (error) { if (sbi->options.quiet)
error = 0; goto out;
}
/* * We don't return -EPERM here. Yes, strange, but this is too * old behavior.
*/ if (attr->ia_valid & ATTR_MODE) { if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0)
attr->ia_valid &= ~ATTR_MODE;
}
if (attr->ia_valid & ATTR_SIZE) {
error = fat_block_truncate_page(inode, attr->ia_size); if (error) goto out;
down_write(&MSDOS_I(inode)->truncate_lock);
truncate_setsize(inode, attr->ia_size);
fat_truncate_blocks(inode, attr->ia_size);
up_write(&MSDOS_I(inode)->truncate_lock);
}
/* * setattr_copy can't truncate these appropriately, so we'll * copy them ourselves
*/ if (attr->ia_valid & ATTR_ATIME)
fat_truncate_time(inode, &attr->ia_atime, S_ATIME); if (attr->ia_valid & ATTR_CTIME)
fat_truncate_time(inode, &attr->ia_ctime, S_CTIME); if (attr->ia_valid & ATTR_MTIME)
fat_truncate_time(inode, &attr->ia_mtime, S_MTIME);
attr->ia_valid &= ~(ATTR_ATIME|ATTR_CTIME|ATTR_MTIME);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.