Ejemplo n.º 1
0
/**
 * ntfs_get_dentry - find a dentry for the inode from a file handle sub-fragment
 * @sb:		super block identifying the mounted ntfs volume
 * @fh:		the file handle sub-fragment
 *
 * Find a dentry for the inode given a file handle sub-fragment.  This function
 * is called from fs/exportfs/expfs.c::find_exported_dentry() which in turn is
 * called from the default ->decode_fh() which is export_decode_fh() in the
 * same file.  The code is closely based on the default ->get_dentry() helper
 * fs/exportfs/expfs.c::get_object().
 *
 * The @fh contains two 32-bit unsigned values, the first one is the inode
 * number and the second one is the inode generation.
 *
 * Return the dentry on success or the error code on error (IS_ERR() is true).
 */
static struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
{
	struct inode *vi;
	struct dentry *dent;
	unsigned long ino = ((u32 *)fh)[0];
	u32 gen = ((u32 *)fh)[1];

	ntfs_debug("Entering for inode 0x%lx, generation 0x%x.", ino, gen);
	vi = ntfs_iget(sb, ino);
	if (IS_ERR(vi)) {
		ntfs_error(sb, "Failed to get inode 0x%lx.", ino);
		return (struct dentry *)vi;
	}
	if (unlikely(is_bad_inode(vi) || vi->i_generation != gen)) {
		/* We didn't find the right inode. */
		ntfs_error(sb, "Inode 0x%lx, bad count: %d %d or version 0x%x "
				"0x%x.", vi->i_ino, vi->i_nlink,
				atomic_read(&vi->i_count), vi->i_generation,
				gen);
		iput(vi);
		return ERR_PTR(-ESTALE);
	}
	/* Now find a dentry.  If possible, get a well-connected one. */
	dent = d_alloc_anon(vi);
	if (unlikely(!dent)) {
		iput(vi);
		return ERR_PTR(-ENOMEM);
	}
	ntfs_debug("Done for inode 0x%lx, generation 0x%x.", ino, gen);
	return dent;
}
Ejemplo n.º 2
0
/**
 * ntfs_usnjrnl_stamp - stamp the transaction log ($UsnJrnl) on an ntfs volume
 * @vol:	ntfs volume on which to stamp the transaction log
 *
 * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return 0
 * on success and errno on error.
 *
 * This function assumes that the transaction log has already been loaded and
 * consistency checked by a call to ntfs_vfsops.c::ntfs_usnjrnl_load().
 */
errno_t ntfs_usnjrnl_stamp(ntfs_volume *vol)
{
	ntfs_debug("Entering.");
	if (!NVolUsnJrnlStamped(vol)) {
		sle64 j_size, stamp;
		upl_t upl;
		upl_page_info_array_t pl;
		USN_HEADER *uh;
		ntfs_inode *max_ni;
		errno_t err;

		mtx_lock_spin(&vol->usnjrnl_j_ni->size_lock);
		j_size = vol->usnjrnl_j_ni->data_size;
		mtx_unlock_spin(&vol->usnjrnl_j_ni->size_lock);
		max_ni = vol->usnjrnl_max_ni;
		/*
		 * FIXME: Next If statement always false because of
		 * replacing vnode_get() with vhold()
		 */
		vhold(max_ni->vn);
		if (0) {
			ntfs_error(vol->mp, "Failed to get vnode for "
					"$UsnJrnl/$DATA/$Max.");
			return err;
		}
		sx_slock(&max_ni->lock);
		err = ntfs_page_map(max_ni, 0, &upl, &pl, (u8**)&uh, TRUE);
		if (err) {
			ntfs_error(vol->mp, "Failed to read from "
					"$UsnJrnl/$DATA/$Max attribute.");
			vdrop(max_ni->vn);
			return err;
		}
		stamp = ntfs_current_time();
		ntfs_debug("Stamping transaction log ($UsnJrnl): old "
				"journal_id 0x%llx, old lowest_valid_usn "
				"0x%llx, new journal_id 0x%llx, new "
				"lowest_valid_usn 0x%llx.",
				(unsigned long long)
				sle64_to_cpu(uh->journal_id),
				(unsigned long long)
				sle64_to_cpu(uh->lowest_valid_usn),
				(unsigned long long)sle64_to_cpu(stamp),
				(unsigned long long)j_size);
		uh->lowest_valid_usn = cpu_to_sle64(j_size);
		uh->journal_id = stamp;
		ntfs_page_unmap(max_ni, upl, pl, TRUE);
		sx_sunlock(&max_ni->lock);
		vdrop(max_ni->vn);
		/* Set the flag so we do not have to do it again on remount. */
		NVolSetUsnJrnlStamped(vol);
		// TODO: Should we mark any times on the base inode $UsnJrnl
		// for update here?
	}
	ntfs_debug("Done.");
	return 0;
}
Ejemplo n.º 3
0
Archivo: unistr.c Proyecto: 274914765/C
/**
 * ntfs_nlstoucs - convert NLS string to little endian Unicode string
 * @vol:    ntfs volume which we are working with
 * @ins:    input NLS string buffer
 * @ins_len:    length of input string in bytes
 * @outs:    on return contains the allocated output Unicode string buffer
 *
 * Convert the input string @ins, which is in whatever format the loaded NLS
 * map dictates, into a little endian, 2-byte Unicode string.
 *
 * This function allocates the string and the caller is responsible for
 * calling kmem_cache_free(ntfs_name_cache, *@outs); when finished with it.
 *
 * On success the function returns the number of Unicode characters written to
 * the output string *@outs (>= 0), not counting the terminating Unicode NULL
 * character. *@outs is set to the allocated output string buffer.
 *
 * On error, a negative number corresponding to the error code is returned. In
 * that case the output string is not allocated. Both *@outs and *@outs_len
 * are then undefined.
 *
 * This might look a bit odd due to fast path optimization...
 */
int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
        const int ins_len, ntfschar **outs)
{
    struct nls_table *nls = vol->nls_map;
    ntfschar *ucs;
    wchar_t wc;
    int i, o, wc_len;

    /* We do not trust outside sources. */
    if (likely(ins)) {
        ucs = kmem_cache_alloc(ntfs_name_cache, GFP_NOFS);
        if (likely(ucs)) {
            for (i = o = 0; i < ins_len; i += wc_len) {
                wc_len = nls->char2uni(ins + i, ins_len - i,
                        &wc);
                if (likely(wc_len >= 0 &&
                        o < NTFS_MAX_NAME_LEN)) {
                    if (likely(wc)) {
                        ucs[o++] = cpu_to_le16(wc);
                        continue;
                    } /* else if (!wc) */
                    break;
                } /* else if (wc_len < 0 ||
                        o >= NTFS_MAX_NAME_LEN) */
                goto name_err;
            }
            ucs[o] = 0;
            *outs = ucs;
            return o;
        } /* else if (!ucs) */
        ntfs_error(vol->sb, "Failed to allocate buffer for converted "
                "name from ntfs_name_cache.");
        return -ENOMEM;
    } /* else if (!ins) */
    ntfs_error(vol->sb, "Received NULL pointer.");
    return -EINVAL;
name_err:
    kmem_cache_free(ntfs_name_cache, ucs);
    if (wc_len < 0) {
        ntfs_error(vol->sb, "Name using character set %s contains "
                "characters that cannot be converted to "
                "Unicode.", nls->charset);
        i = -EILSEQ;
    } else /* if (o >= NTFS_MAX_NAME_LEN) */ {
        ntfs_error(vol->sb, "Name is too long (maximum length for a "
                "name on NTFS is %d Unicode characters.",
                NTFS_MAX_NAME_LEN);
        i = -ENAMETOOLONG;
    }
    return i;
}
Ejemplo n.º 4
0
Archivo: fs.c Proyecto: hugh712/Jollen
static void _ntfs_clear_inode(struct inode *inode)
{
	ntfs_inode *ino;
	ntfs_volume *vol;
	
	lock_kernel();
	ntfs_debug(DEBUG_OTHER, "_ntfs_clear_inode 0x%x\n", inode->i_ino);
	vol = NTFS_INO2VOL(inode);
	if (!vol)
		ntfs_error("_ntfs_clear_inode: vol = NTFS_INO2VOL(inode) is "
				"NULL.\n");
	switch (inode->i_ino) {
	case FILE_Mft:
		if (vol->mft_ino && ((vol->ino_flags & 1) == 0)) {
			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
			vol->mft_ino = ino;
			vol->ino_flags |= 1;
			goto unl_out;
		}
		break;
	case FILE_MftMirr:
		if (vol->mftmirr && ((vol->ino_flags & 2) == 0)) {
			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
			vol->mftmirr = ino;
			vol->ino_flags |= 2;
			goto unl_out;
		}
		break;
	case FILE_BitMap:
		if (vol->bitmap && ((vol->ino_flags & 4) == 0)) {
			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
			vol->bitmap = ino;
			vol->ino_flags |= 4;
			goto unl_out;
		}
		break;
	default:
		/* Nothing. Just clear the inode and exit. */
	}
	ntfs_clear_inode(&inode->u.ntfs_i);
unl_out:
	unlock_kernel();
	return;
}

/* Called when umounting a filesystem by do_umount() in fs/super.c. */
static void ntfs_put_super(struct super_block *sb)
{
	ntfs_volume *vol;

	ntfs_debug(DEBUG_OTHER, "ntfs_put_super\n");
	vol = NTFS_SB2VOL(sb);
	ntfs_release_volume(vol);
	if (vol->nls_map)
		unload_nls(vol->nls_map);
	ntfs_debug(DEBUG_OTHER, "ntfs_put_super: done\n");
}
Ejemplo n.º 5
0
Archivo: fs.c Proyecto: hugh712/Jollen
static int ntfs_create(struct inode* dir, struct dentry *d, int mode)
{
	struct inode *r = 0;
	ntfs_inode *ino = 0;
	ntfs_volume *vol;
	int error = 0;
	ntfs_attribute *si;

	r = new_inode(dir->i_sb);
	if (!r) {
		error = -ENOMEM;
		goto fail;
	}
	ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n", d->d_name.name);
	vol = NTFS_INO2VOL(dir);
	ino = NTFS_LINO2NINO(r);
	error = ntfs_alloc_file(NTFS_LINO2NINO(dir), ino, (char*)d->d_name.name,
				d->d_name.len);
	if (error) {
		ntfs_error("ntfs_alloc_file FAILED: error = %i", error);
		goto fail;
	}
	/* Not doing this one was causing a huge amount of corruption! Now the
	 * bugger bytes the dust! (-8 (AIA) */
	r->i_ino = ino->i_number;
	error = ntfs_update_inode(ino);
	if (error)
		goto fail;
	error = ntfs_update_inode(NTFS_LINO2NINO(dir));
	if (error)
		goto fail;
	r->i_uid = vol->uid;
	r->i_gid = vol->gid;
	/* FIXME: dirty? dev? */
	/* Get the file modification times from the standard information. */
	si = ntfs_find_attr(ino, vol->at_standard_information, NULL);
	if (si) {
		char *attr = si->d.data;
		r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18));
		r->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr));
		r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8));
	}
	/* It's not a directory */
	r->i_op = &ntfs_inode_operations;
	r->i_fop = &ntfs_file_operations;
	r->i_mode = S_IFREG | S_IRUGO;
#ifdef CONFIG_NTFS_RW
	r->i_mode |= S_IWUGO;
#endif
	r->i_mode &= ~vol->umask;
	insert_inode_hash(r);
	d_instantiate(d, r);
	return 0;
 fail:
	if (r)
		iput(r);
	return error;
}
Ejemplo n.º 6
0
/**
 * sync_mft_mirror_umount - synchronise an mft record to the mft mirror
 * @ni:		ntfs inode whose mft record to synchronize
 * @m:		mapped, mst protected (extent) mft record to synchronize
 *
 * Write the mapped, mst protected (extent) mft record @m described by the
 * (regular or extent) ntfs inode @ni to the mft mirror ($MFTMirr) bypassing
 * the page cache and the $MFTMirr inode itself.
 *
 * This function is only for use at umount time when the mft mirror inode has
 * already been disposed off.  We BUG() if we are called while the mft mirror
 * inode is still attached to the volume.
 *
 * On success return 0.  On error return -errno.
 *
 * NOTE:  This function is not implemented yet as I am not convinced it can
 * actually be triggered considering the sequence of commits we do in super.c::
 * ntfs_put_super().  But just in case we provide this place holder as the
 * alternative would be either to BUG() or to get a NULL pointer dereference
 * and Oops.
 */
static int sync_mft_mirror_umount(ntfs_inode *ni, MFT_RECORD *m)
{
	ntfs_volume *vol = ni->vol;

	BUG_ON(vol->mftmirr_ino);
	ntfs_error(vol->sb, "Umount time mft mirror syncing is not "
			"implemented yet.  %s", ntfs_please_email);
	return -EOPNOTSUPP;
}
Ejemplo n.º 7
0
int ntfs_stop_cycles(struct super_block *s, int key, int *c1, int *c2,
                char *msg)
{
        if (*c2 && *c1 == key) {
                ntfs_error(s, "cycle detected on key %08x in %s", key, msg);
                return 1;
        }
        (*c2)++;
        if (!((*c2 - 1) & *c2)) *c1 = key;
        return 0;
}
Ejemplo n.º 8
0
static int ntfs_rmdir(struct inode *dir, struct dentry *dentry)
{
        const unsigned char *name = dentry->d_name.name;
        unsigned len = dentry->d_name.len;
        struct quad_buffer_head qbh;
        struct ntfs_dirent *de;
        struct inode *inode = dentry->d_inode;
        dnode_secno dno;
        int n_items = 0;
        int err;
        int r;

        ntfs_adjust_length(name, &len);
        ntfs_lock(dir->i_sb);
        err = -ENOENT;
        de = map_dirent(dir, ntfs_i(dir)->i_dno, name, len, &dno, &qbh);
        if (!de)
                goto out;

        err = -EPERM;
        if (de->first)
                goto out1;

        err = -ENOTDIR;
        if (!de->directory)
                goto out1;

        ntfs_count_dnodes(dir->i_sb, ntfs_i(inode)->i_dno, NULL, NULL, &n_items);
        err = -ENOTEMPTY;
        if (n_items)
                goto out1;

        r = ntfs_remove_dirent(dir, dno, de, &qbh, 1);
        switch (r) {
        case 1:
                ntfs_error(dir->i_sb, "there was error when removing dirent");
                err = -EFSERROR;
                break;
        case 2:
                err = -ENOSPC;
                break;
        default:
                drop_nlink(dir);
                clear_nlink(inode);
                err = 0;
        }
        goto out;
out1:
        ntfs_brelse4(&qbh);
out:
        ntfs_unlock(dir->i_sb);
        return err;
}
Ejemplo n.º 9
0
/**
 * ntfs_inode_hash_init - initialize the ntfs inode hash
 *
 * Initialize the ntfs inode hash.
 */
errno_t ntfs_inode_hash_init(void)
{
	/* Create the ntfs inode hash. */
	ntfs_inode_hash_table = hashinit(desiredvnodes, M_TEMP,
			&ntfs_inode_hash_mask);
	if (!ntfs_inode_hash_table) {
		ntfs_error(NULL, "Failed to allocate ntfs inode hash table.");
		return ENOMEM;
	}
	ntfs_debug("ntfs_inode_hash_mask 0x%lx.", ntfs_inode_hash_mask);
	/* Initialize the ntfs inode hash lock. */
	mtx_init(&ntfs_inode_hash_lock, "ntfs inode hash lock", NULL, MTX_DEF);
	return 0;
}
Ejemplo n.º 10
0
static struct dentry *ntfs_get_parent(struct dentry *child_dent)
{
	struct inode *vi = child_dent->d_inode;
	ntfs_inode *ni = NTFS_I(vi);
	MFT_RECORD *mrec;
	ntfs_attr_search_ctx *ctx;
	ATTR_RECORD *attr;
	FILE_NAME_ATTR *fn;
	unsigned long parent_ino;
	int err;

	ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
	
	mrec = map_mft_record(ni);
	if (IS_ERR(mrec))
		return (struct dentry *)mrec;
	
	ctx = ntfs_attr_get_search_ctx(ni, mrec);
	if (unlikely(!ctx)) {
		unmap_mft_record(ni);
		return ERR_PTR(-ENOMEM);
	}
try_next:
	err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL,
			0, ctx);
	if (unlikely(err)) {
		ntfs_attr_put_search_ctx(ctx);
		unmap_mft_record(ni);
		if (err == -ENOENT)
			ntfs_error(vi->i_sb, "Inode 0x%lx does not have a "
					"file name attribute.  Run chkdsk.",
					vi->i_ino);
		return ERR_PTR(err);
	}
	attr = ctx->attr;
	if (unlikely(attr->non_resident))
		goto try_next;
	fn = (FILE_NAME_ATTR *)((u8 *)attr +
			le16_to_cpu(attr->data.resident.value_offset));
	if (unlikely((u8 *)fn + le32_to_cpu(attr->data.resident.value_length) >
			(u8*)attr + le32_to_cpu(attr->length)))
		goto try_next;
	
	parent_ino = MREF_LE(fn->parent_directory);
	
	ntfs_attr_put_search_ctx(ctx);
	unmap_mft_record(ni);

	return d_obtain_alias(ntfs_iget(vi->i_sb, parent_ino));
}
Ejemplo n.º 11
0
static void _ntfs_clear_inode(struct inode *inode)
{
	ntfs_inode *ino;
	ntfs_volume *vol;
	
	lock_kernel();
	ntfs_debug(DEBUG_OTHER, "_ntfs_clear_inode 0x%x\n", inode->i_ino);
	vol = NTFS_INO2VOL(inode);
	if (!vol)
		ntfs_error("_ntfs_clear_inode: vol = NTFS_INO2VOL(inode) is "
				"NULL.\n");
	switch (inode->i_ino) {
	case FILE_Mft:
		if (vol->mft_ino && ((vol->ino_flags & 1) == 0)) {
			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
			vol->mft_ino = ino;
			vol->ino_flags |= 1;
			goto unl_out;
		}
		break;
	case FILE_MftMirr:
		if (vol->mftmirr && ((vol->ino_flags & 2) == 0)) {
			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
			vol->mftmirr = ino;
			vol->ino_flags |= 2;
			goto unl_out;
		}
		break;
	case FILE_BitMap:
		if (vol->bitmap && ((vol->ino_flags & 4) == 0)) {
			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
			vol->bitmap = ino;
			vol->ino_flags |= 4;
			goto unl_out;
		}
		break;
		/* Nothing. Just clear the inode and exit. */
	}
	ntfs_clear_inode(&inode->u.ntfs_i);
unl_out:
	unlock_kernel();
	return;
}
Ejemplo n.º 12
0
Archivo: mft.c Proyecto: killvxk/NT_OS
/**
 * map_mft_record_page - map the page in which a specific mft record resides
 * @ni:		ntfs inode whose mft record page to map
 *
 * This maps the page in which the mft record of the ntfs inode @ni is situated
 * and returns a pointer to the mft record within the mapped page.
 *
 * Return value needs to be checked with IS_ERR() and if that is true PTR_ERR()
 * contains the negative error code returned.
 */
static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
{
	ntfs_volume *vol = ni->vol;
	struct inode *mft_vi = vol->mft_ino;
	struct page *page;
	unsigned long index, ofs, end_index;

	BUG_ON(ni->page);
	/*
	 * The index into the page cache and the offset within the page cache
	 * page of the wanted mft record. FIXME: We need to check for
	 * overflowing the unsigned long, but I don't think we would ever get
	 * here if the volume was that big...
	 */
	index = ni->mft_no << vol->mft_record_size_bits >> PAGE_CACHE_SHIFT;
	ofs = (ni->mft_no << vol->mft_record_size_bits) & ~PAGE_CACHE_MASK;

	/* The maximum valid index into the page cache for $MFT's data. */
	end_index = mft_vi->i_size >> PAGE_CACHE_SHIFT;

	/* If the wanted index is out of bounds the mft record doesn't exist. */
	if (unlikely(index >= end_index)) {
		if (index > end_index || (mft_vi->i_size & ~PAGE_CACHE_MASK) <
				ofs + vol->mft_record_size) {
			page = ERR_PTR(-ENOENT);
			goto err_out;
		}
	}
	/* Read, map, and pin the page. */
	page = ntfs_map_page(mft_vi->i_mapping, index);
	if (likely(!IS_ERR(page))) {
		ni->page = page;
		ni->page_ofs = ofs;
		return page_address(page) + ofs;
	}
err_out:
	ni->page = NULL;
	ni->page_ofs = 0;
	ntfs_error(vol->sb, "Failed with error code %lu.", -PTR_ERR(page));
	return (void*)page;
}
Ejemplo n.º 13
0
Archivo: mft.c Proyecto: killvxk/NT_OS
/**
 * map_mft_record - map, pin and lock an mft record
 * @ni:		ntfs inode whose MFT record to map
 *
 * First, take the mrec_lock semaphore. We might now be sleeping, while waiting
 * for the semaphore if it was already locked by someone else.
 *
 * The page of the record is mapped using map_mft_record_page() before being
 * returned to the caller.
 *
 * This in turn uses ntfs_map_page() to get the page containing the wanted mft
 * record (it in turn calls read_cache_page() which reads it in from disk if
 * necessary, increments the use count on the page so that it cannot disappear
 * under us and returns a reference to the page cache page).
 *
 * If read_cache_page() invokes ntfs_readpage() to load the page from disk, it
 * sets PG_locked and clears PG_uptodate on the page. Once I/O has completed
 * and the post-read mst fixups on each mft record in the page have been
 * performed, the page gets PG_uptodate set and PG_locked cleared (this is done
 * in our asynchronous I/O completion handler end_buffer_read_mft_async()).
 * ntfs_map_page() waits for PG_locked to become clear and checks if
 * PG_uptodate is set and returns an error code if not. This provides
 * sufficient protection against races when reading/using the page.
 *
 * However there is the write mapping to think about. Doing the above described
 * checking here will be fine, because when initiating the write we will set
 * PG_locked and clear PG_uptodate making sure nobody is touching the page
 * contents. Doing the locking this way means that the commit to disk code in
 * the page cache code paths is automatically sufficiently locked with us as
 * we will not touch a page that has been locked or is not uptodate. The only
 * locking problem then is them locking the page while we are accessing it.
 *
 * So that code will end up having to own the mrec_lock of all mft
 * records/inodes present in the page before I/O can proceed. In that case we
 * wouldn't need to bother with PG_locked and PG_uptodate as nobody will be
 * accessing anything without owning the mrec_lock semaphore. But we do need
 * to use them because of the read_cache_page() invocation and the code becomes
 * so much simpler this way that it is well worth it.
 *
 * The mft record is now ours and we return a pointer to it. You need to check
 * the returned pointer with IS_ERR() and if that is true, PTR_ERR() will return
 * the error code.
 *
 * NOTE: Caller is responsible for setting the mft record dirty before calling
 * unmap_mft_record(). This is obviously only necessary if the caller really
 * modified the mft record...
 * Q: Do we want to recycle one of the VFS inode state bits instead?
 * A: No, the inode ones mean we want to change the mft record, not we want to
 * write it out.
 */
MFT_RECORD *map_mft_record(ntfs_inode *ni)
{
	MFT_RECORD *m;

	ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);

	/* Make sure the ntfs inode doesn't go away. */
	atomic_inc(&ni->count);

	/* Serialize access to this mft record. */
	down(&ni->mrec_lock);

	m = map_mft_record_page(ni);
	if (likely(!IS_ERR(m)))
		return m;

	up(&ni->mrec_lock);
	atomic_dec(&ni->count);
	ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
	return m;
}
Ejemplo n.º 14
0
/**
 * ntfs_stamp_usnjrnl - stamp the transaction log ($UsnJrnl) on an ntfs volume
 * @vol:	ntfs volume on which to stamp the transaction log
 *
 * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return
 * 'true' on success and 'false' on error.
 *
 * This function assumes that the transaction log has already been loaded and
 * consistency checked by a call to fs/ntfs/super.c::load_and_init_usnjrnl().
 */
bool ntfs_stamp_usnjrnl(ntfs_volume *vol)
{
	ntfs_debug("Entering.");
	if (likely(!NVolUsnJrnlStamped(vol))) {
		sle64 stamp;
		struct page *page;
		USN_HEADER *uh;

		page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0);
		if (IS_ERR(page)) {
			ntfs_error(vol->sb, "Failed to read from "
					"$UsnJrnl/$DATA/$Max attribute.");
			return false;
		}
		uh = (USN_HEADER*)page_address(page);
		stamp = get_current_ntfs_time();
		ntfs_debug("Stamping transaction log ($UsnJrnl): old "
				"journal_id 0x%llx, old lowest_valid_usn "
				"0x%llx, new journal_id 0x%llx, new "
				"lowest_valid_usn 0x%llx.",
				(long long)sle64_to_cpu(uh->journal_id),
				(long long)sle64_to_cpu(uh->lowest_valid_usn),
				(long long)sle64_to_cpu(stamp),
				i_size_read(vol->usnjrnl_j_ino));
		uh->lowest_valid_usn =
				cpu_to_sle64(i_size_read(vol->usnjrnl_j_ino));
		uh->journal_id = stamp;
		flush_dcache_page(page);
		set_page_dirty(page);
		ntfs_unmap_page(page);
		/* Set the flag so we do not have to do it again on remount. */
		NVolSetUsnJrnlStamped(vol);
	}
	ntfs_debug("Done.");
	return true;
}
Ejemplo n.º 15
0
Archivo: fs.c Proyecto: hugh712/Jollen
/* Called to mount a filesystem by read_super() in fs/super.c.
 * Return a super block, the main structure of a filesystem.
 *
 * NOTE : Don't store a pointer to an option, as the page containing the
 * options is freed after ntfs_read_super() returns.
 *
 * NOTE : A context switch can happen in kernel code only if the code blocks
 * (= calls schedule() in kernel/sched.c). */
struct super_block *ntfs_read_super(struct super_block *sb, void *options,
		int silent)
{
	ntfs_volume *vol;
	struct buffer_head *bh;
	int i, to_read, blocksize;

	ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n");
	vol = NTFS_SB2VOL(sb);
	init_ntfs_super_block(vol);
	if (!parse_options(vol, (char*)options))
		goto ntfs_read_super_vol;
	blocksize = get_hardsect_size(sb->s_dev);
	if (blocksize < 512)
		blocksize = 512;
	if (set_blocksize(sb->s_dev, blocksize) < 0) {
		ntfs_error("Unable to set blocksize %d.\n", blocksize);
		goto ntfs_read_super_vol;
	}
	sb->s_blocksize = blocksize;
	/* Read the super block (boot block). */
	if (!(bh = sb_bread(sb, 0))) {
		ntfs_error("Reading super block failed\n");
		goto ntfs_read_super_unl;
	}
	ntfs_debug(DEBUG_OTHER, "Done reading boot block\n");
	/* Check for valid 'NTFS' boot sector. */
	if (!is_boot_sector_ntfs(bh->b_data)) {
		ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n");
		bforget(bh);
		goto ntfs_read_super_unl;
	}
	ntfs_debug(DEBUG_OTHER, "Going to init volume\n");
	if (ntfs_init_volume(vol, bh->b_data) < 0) {
		ntfs_debug(DEBUG_OTHER, "Init volume failed.\n");
		bforget(bh);
		goto ntfs_read_super_unl;
	}
	ntfs_debug(DEBUG_OTHER, "$Mft at cluster 0x%lx\n", vol->mft_lcn);
	brelse(bh);
	NTFS_SB(vol) = sb;
	if (vol->cluster_size > PAGE_SIZE) {
		ntfs_error("Partition cluster size is not supported yet (it "
			   "is > max kernel blocksize).\n");
		goto ntfs_read_super_unl;
	}
	ntfs_debug(DEBUG_OTHER, "Done to init volume\n");
	/* Inform the kernel that a device block is a NTFS cluster. */
	sb->s_blocksize = vol->cluster_size;
	sb->s_blocksize_bits = vol->cluster_size_bits;
	if (blocksize != vol->cluster_size &&
			set_blocksize(sb->s_dev, sb->s_blocksize) < 0) {
		ntfs_error("Cluster size too small for device.\n");
		goto ntfs_read_super_unl;
	}
	ntfs_debug(DEBUG_OTHER, "set_blocksize\n");
	/* Allocate an MFT record (MFT record can be smaller than a cluster). */
	i = vol->cluster_size;
	if (i < vol->mft_record_size)
		i = vol->mft_record_size;
	if (!(vol->mft = ntfs_malloc(i)))
		goto ntfs_read_super_unl;

	/* Read at least the MFT record for $Mft. */
	to_read = vol->mft_clusters_per_record;
	if (to_read < 1)
		to_read = 1;
	for (i = 0; i < to_read; i++) {
		if (!(bh = sb_bread(sb, vol->mft_lcn + i))) {
			ntfs_error("Could not read $Mft record 0\n");
			goto ntfs_read_super_mft;
		}
		ntfs_memcpy(vol->mft + ((__s64)i << vol->cluster_size_bits),
						bh->b_data, vol->cluster_size);
		brelse(bh);
		ntfs_debug(DEBUG_OTHER, "Read cluster 0x%x\n",
							 vol->mft_lcn + i);
	}
	/* Check and fixup this MFT record */
	if (!ntfs_check_mft_record(vol, vol->mft)){
		ntfs_error("Invalid $Mft record 0\n");
		goto ntfs_read_super_mft;
	}
	/* Inform the kernel about which super operations are available. */
	sb->s_op = &ntfs_super_operations;
	sb->s_magic = NTFS_SUPER_MAGIC;
	sb->s_maxbytes = ~0ULL >> 1;
	ntfs_debug(DEBUG_OTHER, "Reading special files\n");
	if (ntfs_load_special_files(vol)) {
		ntfs_error("Error loading special files\n");
		goto ntfs_read_super_mft;
	}
	ntfs_debug(DEBUG_OTHER, "Getting RootDir\n");
	/* Get the root directory. */
	if (!(sb->s_root = d_alloc_root(iget(sb, FILE_root)))) {
		ntfs_error("Could not get root dir inode\n");
		goto ntfs_read_super_mft;
	}
ntfs_read_super_ret:
	ntfs_debug(DEBUG_OTHER, "read_super: done\n");
	return sb;
ntfs_read_super_mft:
	ntfs_free(vol->mft);
ntfs_read_super_unl:
ntfs_read_super_vol:
	sb = NULL;
	goto ntfs_read_super_ret;
}
Ejemplo n.º 16
0
/* Called to mount a filesystem by read_super() in fs/super.c
 * Return a super block, the main structure of a filesystem
 *
 * NOTE : Don't store a pointer to an option, as the page containing the
 * options is freed after ntfs_read_super() returns.
 *
 * NOTE : A context switch can happen in kernel code only if the code blocks
 * (= calls schedule() in kernel/sched.c).
 */
struct super_block * ntfs_read_super(struct super_block *sb, 
				     void *options, int silent)
{
	ntfs_volume *vol;
	struct buffer_head *bh;
	int i;

	ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n");

#ifdef NTFS_IN_LINUX_KERNEL
	vol = NTFS_SB2VOL(sb);
#else
	if(!(vol = ntfs_malloc(sizeof(ntfs_volume))))
		goto ntfs_read_super_dec;
	NTFS_SB2VOL(sb)=vol;
#endif
	
	if(!parse_options(vol,(char*)options))
		goto ntfs_read_super_vol;

#if 0
	/* Set to read only, user option might reset it */
	sb->s_flags |= MS_RDONLY;
#endif

	/* Assume a 512 bytes block device for now */
	set_blocksize(sb->s_dev, 512);
	/* Read the super block (boot block) */
	if(!(bh=bread(sb->s_dev,0,512))) {
		ntfs_error("Reading super block failed\n");
		goto ntfs_read_super_unl;
	}
	ntfs_debug(DEBUG_OTHER, "Done reading boot block\n");

	/* Check for 'NTFS' magic number */
	if(!IS_NTFS_VOLUME(bh->b_data)){
		ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n");
		brelse(bh);
		goto ntfs_read_super_unl;
	}

	ntfs_debug(DEBUG_OTHER, "Going to init volume\n");
	ntfs_init_volume(vol,bh->b_data);
	ntfs_debug(DEBUG_OTHER, "MFT record at cluster 0x%X\n",vol->mft_cluster);
	brelse(bh);
	NTFS_SB(vol)=sb;
	ntfs_debug(DEBUG_OTHER, "Done to init volume\n");

	/* Inform the kernel that a device block is a NTFS cluster */
	sb->s_blocksize=vol->clustersize;
	for(i=sb->s_blocksize,sb->s_blocksize_bits=0;i != 1;i>>=1)
		sb->s_blocksize_bits++;
	set_blocksize(sb->s_dev,sb->s_blocksize);
	ntfs_debug(DEBUG_OTHER, "set_blocksize\n");

	/* Allocate a MFT record (MFT record can be smaller than a cluster) */
	if(!(vol->mft=ntfs_malloc(max(vol->mft_recordsize,vol->clustersize))))
		goto ntfs_read_super_unl;

	/* Read at least the MFT record for $MFT */
	for(i=0;i<max(vol->mft_clusters_per_record,1);i++){
		if(!(bh=bread(sb->s_dev,vol->mft_cluster+i,vol->clustersize))) {
			ntfs_error("Could not read MFT record 0\n");
			goto ntfs_read_super_mft;
		}
		ntfs_memcpy(vol->mft+i*vol->clustersize,bh->b_data,vol->clustersize);
		brelse(bh);
		ntfs_debug(DEBUG_OTHER, "Read cluster %x\n",vol->mft_cluster+i);
	}

	/* Check and fixup this MFT record */
	if(!ntfs_check_mft_record(vol,vol->mft)){
		ntfs_error("Invalid MFT record 0\n");
		goto ntfs_read_super_mft;
	}

	/* Inform the kernel about which super operations are available */
	sb->s_op = &ntfs_super_operations;
	sb->s_magic = NTFS_SUPER_MAGIC;
	
	ntfs_debug(DEBUG_OTHER, "Reading special files\n");
	if(ntfs_load_special_files(vol)){
		ntfs_error("Error loading special files\n");
		goto ntfs_read_super_mft;
	}

	ntfs_debug(DEBUG_OTHER, "Getting RootDir\n");
	/* Get the root directory */
	if(!(sb->s_root=d_alloc_root(iget(sb,FILE_ROOT)))){
		ntfs_error("Could not get root dir inode\n");
		goto ntfs_read_super_mft;
	}
	ntfs_debug(DEBUG_OTHER, "read_super: done\n");
	return sb;

ntfs_read_super_mft:
	ntfs_free(vol->mft);
ntfs_read_super_unl:
ntfs_read_super_vol:
	#ifndef NTFS_IN_LINUX_KERNEL
	ntfs_free(vol);
ntfs_read_super_dec:
	#endif
	ntfs_debug(DEBUG_OTHER, "read_super: done\n");
	return NULL;
}
Ejemplo n.º 17
0
/* ntfs_read_inode is called by the Virtual File System (the kernel layer that
 * deals with filesystems) when iget is called requesting an inode not already
 * present in the inode table. Typically filesystems have separate
 * inode_operations for directories, files and symlinks.
 */
static void ntfs_read_inode(struct inode* inode)
{
	ntfs_volume *vol;
	int can_mmap=0;
	ntfs_inode *ino;
	ntfs_attribute *data;
	ntfs_attribute *si;

	vol=NTFS_INO2VOL(inode);
	inode->i_mode=0;
	ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n",(unsigned)inode->i_ino);

	switch(inode->i_ino)
	{
		/* those are loaded special files */
	case FILE_MFT:
		ntfs_error("Trying to open MFT\n");return;
	default:
		#ifdef NTFS_IN_LINUX_KERNEL
		ino=&inode->u.ntfs_i;
		#else
		/* FIXME: check for ntfs_malloc failure */
		ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
		inode->u.generic_ip=ino;
		#endif
		if(!ino || ntfs_init_inode(ino,
					   NTFS_INO2VOL(inode),inode->i_ino))
		{
			ntfs_debug(DEBUG_OTHER, "NTFS:Error loading inode %x\n",
			       (unsigned int)inode->i_ino);
			return;
		}
	}
	/* Set uid/gid from mount options */
	inode->i_uid=vol->uid;
	inode->i_gid=vol->gid;
	inode->i_nlink=1;
	/* Use the size of the data attribute as file size */
	data = ntfs_find_attr(ino,vol->at_data,NULL);
	if(!data)
	{
		inode->i_size=0;
		can_mmap=0;
	}
	else
	{
		inode->i_size=data->size;
		/* FIXME: once ntfs_get_block is implemented, uncomment the
		 * next line and remove the can_mmap = 0; */
		/* can_mmap=!data->resident && !data->compressed;*/
		can_mmap = 0;
	}
	/* get the file modification times from the standard information */
	si=ntfs_find_attr(ino,vol->at_standard_information,NULL);
	if(si){
		char *attr=si->d.data;
		inode->i_atime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18));
		inode->i_ctime=ntfs_ntutc2unixutc(NTFS_GETU64(attr));
		inode->i_mtime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+8));
	}
	/* if it has an index root, it's a directory */
	if(ntfs_find_attr(ino,vol->at_index_root,"$I30"))
	{
		ntfs_attribute *at;
		at = ntfs_find_attr (ino, vol->at_index_allocation, "$I30");
		inode->i_size = at ? at->size : 0;
	  
		inode->i_op=&ntfs_dir_inode_operations;
		inode->i_fop=&ntfs_dir_operations;
		inode->i_mode=S_IFDIR|S_IRUGO|S_IXUGO;
	}
	else
	{
		/* As long as ntfs_get_block() is just a call to BUG() do not
	 	 * define any [bm]map ops or we get the BUG() whenever someone
		 * runs mc or mpg123 on an ntfs partition!
		 * FIXME: Uncomment the below code when ntfs_get_block is
		 * implemented. */
		/* if (can_mmap) {
			inode->i_op = &ntfs_inode_operations;
			inode->i_fop = &ntfs_file_operations;
			inode->i_mapping->a_ops = &ntfs_aops;
			inode->u.ntfs_i.mmu_private = inode->i_size;
		} else */ {
			inode->i_op=&ntfs_inode_operations_nobmap;
			inode->i_fop=&ntfs_file_operations_nommap;
		}
		inode->i_mode=S_IFREG|S_IRUGO;
	}
#ifdef CONFIG_NTFS_RW
	if(!data || !data->compressed)
		inode->i_mode|=S_IWUGO;
#endif
	inode->i_mode &= ~vol->umask;
}
Ejemplo n.º 18
0
/**
 * ntfs_lookup - find the inode represented by a dentry in a directory inode
 * @dir_ino:	directory inode in which to look for the inode
 * @dent:	dentry representing the inode to look for
 * @nd:		lookup nameidata
 *
 * In short, ntfs_lookup() looks for the inode represented by the dentry @dent
 * in the directory inode @dir_ino and if found attaches the inode to the
 * dentry @dent.
 *
 * In more detail, the dentry @dent specifies which inode to look for by
 * supplying the name of the inode in @dent->d_name.name. ntfs_lookup()
 * converts the name to Unicode and walks the contents of the directory inode
 * @dir_ino looking for the converted Unicode name. If the name is found in the
 * directory, the corresponding inode is loaded by calling ntfs_iget() on its
 * inode number and the inode is associated with the dentry @dent via a call to
 * d_add().
 *
 * If the name is not found in the directory, a NULL inode is inserted into the
 * dentry @dent. The dentry is then termed a negative dentry.
 *
 * Only if an actual error occurs, do we return an error via ERR_PTR().
 *
 * In order to handle the case insensitivity issues of NTFS with regards to the
 * dcache and the dcache requiring only one dentry per directory, we deal with
 * dentry aliases that only differ in case in ->ntfs_lookup() while maintining
 * a case sensitive dcache. This means that we get the full benefit of dcache
 * speed when the file/directory is looked up with the same case as returned by
 * ->ntfs_readdir() but that a lookup for any other case (or for the short file
 * name) will not find anything in dcache and will enter ->ntfs_lookup()
 * instead, where we search the directory for a fully matching file name
 * (including case) and if that is not found, we search for a file name that
 * matches with different case and if that has non-POSIX semantics we return
 * that. We actually do only one search (case sensitive) and keep tabs on
 * whether we have found a case insensitive match in the process.
 *
 * To simplify matters for us, we do not treat the short vs long filenames as
 * two hard links but instead if the lookup matches a short filename, we
 * return the dentry for the corresponding long filename instead.
 *
 * There are three cases we need to distinguish here:
 *
 * 1) @dent perfectly matches (i.e. including case) a directory entry with a
 *    file name in the WIN32 or POSIX namespaces. In this case
 *    ntfs_lookup_inode_by_name() will return with name set to NULL and we
 *    just d_add() @dent.
 * 2) @dent matches (not including case) a directory entry with a file name in
 *    the WIN32 namespace. In this case ntfs_lookup_inode_by_name() will return
 *    with name set to point to a kmalloc()ed ntfs_name structure containing
 *    the properly cased little endian Unicode name. We convert the name to the
 *    current NLS code page, search if a dentry with this name already exists
 *    and if so return that instead of @dent. The VFS will then destroy the old
 *    @dent and use the one we returned. If a dentry is not found, we allocate
 *    a new one, d_add() it, and return it as above.
 * 3) @dent matches either perfectly or not (i.e. we don't care about case) a
 *    directory entry with a file name in the DOS namespace. In this case
 *    ntfs_lookup_inode_by_name() will return with name set to point to a
 *    kmalloc()ed ntfs_name structure containing the mft reference (cpu endian)
 *    of the inode. We use the mft reference to read the inode and to find the
 *    file name in the WIN32 namespace corresponding to the matched short file
 *    name. We then convert the name to the current NLS code page, and proceed
 *    searching for a dentry with this name, etc, as in case 2), above.
 */
static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, struct nameidata *nd)
{
	ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
	struct inode *dent_inode;
	uchar_t *uname;
	ntfs_name *name = NULL;
	MFT_REF mref;
	unsigned long dent_ino;
	int uname_len;

	ntfs_debug("Looking up %s in directory inode 0x%lx.",
			dent->d_name.name, dir_ino->i_ino);
	/* Convert the name of the dentry to Unicode. */
	uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len,
			&uname);
	if (uname_len < 0) {
		ntfs_error(vol->sb, "Failed to convert name to Unicode.");
		return ERR_PTR(uname_len);
	}
	mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len,
			&name);
	kmem_cache_free(ntfs_name_cache, uname);
	if (!IS_ERR_MREF(mref)) {
		dent_ino = MREF(mref);
		ntfs_debug("Found inode 0x%lx. Calling ntfs_iget.", dent_ino);
		dent_inode = ntfs_iget(vol->sb, dent_ino);
		if (likely(!IS_ERR(dent_inode))) {
			/* Consistency check. */
			if (MSEQNO(mref) == NTFS_I(dent_inode)->seq_no ||
					dent_ino == FILE_MFT) {
				/* Perfect WIN32/POSIX match. -- Case 1. */
				if (!name) {
					d_add(dent, dent_inode);
					ntfs_debug("Done.");
					return NULL;
				}
				/*
				 * We are too indented. Handle imperfect
				 * matches and short file names further below.
				 */
				goto handle_name;
			}
			ntfs_error(vol->sb, "Found stale reference to inode "
					"0x%lx (reference sequence number = "
					"0x%x, inode sequence number = 0x%x, "
					"returning -EIO. Run chkdsk.",
					dent_ino, MSEQNO(mref),
					NTFS_I(dent_inode)->seq_no);
			iput(dent_inode);
			dent_inode = ERR_PTR(-EIO);
		} else
			ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with "
					"error code %li.", dent_ino,
					PTR_ERR(dent_inode));
		if (name)
			kfree(name);
		/* Return the error code. */
		return (struct dentry *)dent_inode;
	}
	/* It is guaranteed that name is no longer allocated at this point. */
	if (MREF_ERR(mref) == -ENOENT) {
		ntfs_debug("Entry was not found, adding negative dentry.");
		/* The dcache will handle negative entries. */
		d_add(dent, NULL);
		ntfs_debug("Done.");
		return NULL;
	}
	ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error "
			"code %i.", -MREF_ERR(mref));
	return ERR_PTR(MREF_ERR(mref));

	// TODO: Consider moving this lot to a separate function! (AIA)
handle_name:
   {
	struct dentry *real_dent;
	MFT_RECORD *m;
	attr_search_context *ctx;
	ntfs_inode *ni = NTFS_I(dent_inode);
	int err;
	struct qstr nls_name;

	nls_name.name = NULL;
	if (name->type != FILE_NAME_DOS) {			/* Case 2. */
		nls_name.len = (unsigned)ntfs_ucstonls(vol,
				(uchar_t*)&name->name, name->len,
				(unsigned char**)&nls_name.name,
				name->len * 3 + 1);
		kfree(name);
	} else /* if (name->type == FILE_NAME_DOS) */ {		/* Case 3. */
		FILE_NAME_ATTR *fn;

		kfree(name);

		/* Find the WIN32 name corresponding to the matched DOS name. */
		ni = NTFS_I(dent_inode);
		m = map_mft_record(ni);
		if (IS_ERR(m)) {
			err = PTR_ERR(m);
			m = NULL;
			ctx = NULL;
			goto err_out;
		}
		ctx = get_attr_search_ctx(ni, m);
		if (!ctx) {
			err = -ENOMEM;
			goto err_out;
		}
		do {
			ATTR_RECORD *a;
			u32 val_len;

			if (!lookup_attr(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0,
					ctx)) {
				ntfs_error(vol->sb, "Inode corrupt: No WIN32 "
						"namespace counterpart to DOS "
						"file name. Run chkdsk.");
				err = -EIO;
				goto err_out;
			}
			/* Consistency checks. */
			a = ctx->attr;
			if (a->non_resident || a->flags)
				goto eio_err_out;
			val_len = le32_to_cpu(a->data.resident.value_length);
			if (le16_to_cpu(a->data.resident.value_offset) +
					val_len > le32_to_cpu(a->length))
				goto eio_err_out;
			fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
					ctx->attr->data.resident.value_offset));
			if ((u32)(fn->file_name_length * sizeof(uchar_t) +
					sizeof(FILE_NAME_ATTR)) > val_len)
				goto eio_err_out;
		} while (fn->file_name_type != FILE_NAME_WIN32);

		/* Convert the found WIN32 name to current NLS code page. */
		nls_name.len = (unsigned)ntfs_ucstonls(vol,
				(uchar_t*)&fn->file_name, fn->file_name_length,
				(unsigned char**)&nls_name.name,
				fn->file_name_length * 3 + 1);

		put_attr_search_ctx(ctx);
		unmap_mft_record(ni);
	}
	m = NULL;
	ctx = NULL;

	/* Check if a conversion error occurred. */
	if ((signed)nls_name.len < 0) {
		err = (signed)nls_name.len;
		goto err_out;
	}
	nls_name.hash = full_name_hash(nls_name.name, nls_name.len);

	/*
	 * Note: No need for dent->d_lock lock as i_sem is held on the
	 * parent inode.
	 */

	/* Does a dentry matching the nls_name exist already? */
	real_dent = d_lookup(dent->d_parent, &nls_name);
	/* If not, create it now. */
	if (!real_dent) {
		real_dent = d_alloc(dent->d_parent, &nls_name);
		kfree(nls_name.name);
		if (!real_dent) {
			err = -ENOMEM;
			goto err_out;
		}
		d_add(real_dent, dent_inode);
		return real_dent;
	}
	kfree(nls_name.name);
	/* Matching dentry exists, check if it is negative. */
	if (real_dent->d_inode) {
		BUG_ON(real_dent->d_inode != dent_inode);
		/*
		 * Already have the inode and the dentry attached, decrement
		 * the reference count to balance the ntfs_iget() we did
		 * earlier on.
		 */
		iput(dent_inode);
		return real_dent;
	}
	/* Negative dentry: instantiate it. */
	d_instantiate(real_dent, dent_inode);
	return real_dent;

eio_err_out:
	ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
	err = -EIO;
err_out:
	if (ctx)
		put_attr_search_ctx(ctx);
	if (m)
		unmap_mft_record(ni);
	iput(dent_inode);
	return ERR_PTR(err);
   }
}
Ejemplo n.º 19
0
/**
 * ntfs_page_map_ext - map a page of a vnode into memory
 * @ni:		ntfs inode of which to map a page
 * @ofs:	byte offset into @ni of which to map a page
 * @upl:	destination page list for the page
 * @pl:		destination array of pages containing the page itself
 * @kaddr:	destination pointer for the address of the mapped page contents
 * @uptodate:	if true return an uptodate page and if false return it as is
 * @rw:		if true we intend to modify the page and if false we do not
 *
 * Map the page corresponding to byte offset @ofs into the ntfs inode @ni into
 * memory and return the page list in @upl, the array of pages containing the
 * page in @pl and the address of the mapped page contents in @kaddr.
 *
 * If @uptodate is true the page is returned uptodate, i.e. if the page is
 * currently not valid, it will be brought uptodate via a call to ntfs_pagein()
 * before it is returned.  And if @uptodate is false, the page is just returned
 * ignoring its state.  This means the page may or may not be uptodate.
 *
 * The caller must set @rw to true if the page is going to be modified and to
 * false otherwise.
 *
 * Note: @ofs must be page aligned.
 *
 * Locking: - Caller must hold an iocount reference on the vnode of @ni.
 *	    - Caller must hold @ni->lock for reading or writing.
 *
 * Return 0 on success and errno on error in which case *@upl is set to NULL.
 */
errno_t ntfs_page_map_ext(ntfs_inode *ni, s64 ofs, upl_t *upl,
		upl_page_info_array_t *pl, u8 **kaddr, const BOOL uptodate,
		const BOOL rw)
{
	s64 size;
	kern_return_t kerr;
	int abort_flags;
	errno_t err;

	ntfs_debug("Entering for inode 0x%llx, offset 0x%llx, rw is %s.",
			(unsigned long long)ni->mft_no,
			(unsigned long long)ofs,
			rw ? "true" : "false");
	if (ofs & PAGE_MASK)
		panic("%s() called with non page aligned offset (0x%llx).",
				__FUNCTION__, (unsigned long long)ofs);
	lck_spin_lock(&ni->size_lock);
	size = ubc_getsize(ni->vn);
	if (size > ni->data_size)
		size = ni->data_size;
	lck_spin_unlock(&ni->size_lock);
	if (ofs > size) {
		ntfs_error(ni->vol->mp, "Offset 0x%llx is outside the end of "
				"the attribute (0x%llx).",
				(unsigned long long)ofs,
				(unsigned long long)size);
		err = EINVAL;
		goto err;
	}
	/* Create a page list for the wanted page. */
	kerr = ubc_create_upl(ni->vn, ofs, PAGE_SIZE, upl, pl, UPL_SET_LITE |
			(rw ? UPL_WILL_MODIFY : 0));
	if (kerr != KERN_SUCCESS)
		panic("%s(): Failed to get page (error %d).\n", __FUNCTION__,
				(int)kerr);
	/*
	 * If the page is not valid, need to read it in from the vnode now thus
	 * making it valid.
	 *
	 * We set UPL_NESTED_PAGEOUT to let ntfs_pagein() know that we already
	 * have the inode locked (@ni->lock is held by the caller).
	 */
	if (uptodate && !upl_valid_page(*pl, 0)) {
		ntfs_debug("Reading page as it was not valid.");
		err = ntfs_pagein(ni, ofs, PAGE_SIZE, *upl, 0, UPL_IOSYNC |
				UPL_NOCOMMIT | UPL_NESTED_PAGEOUT);
		if (err) {
			ntfs_error(ni->vol->mp, "Failed to read page (error "
					"%d).", err);
			goto pagein_err;
		}
	}
	/* Map the page into the kernel's address space. */
	kerr = ubc_upl_map(*upl, (vm_offset_t*)kaddr);
	if (kerr == KERN_SUCCESS) {
		ntfs_debug("Done.");
		return 0;
	}
	ntfs_error(ni->vol->mp, "Failed to map page (error %d).",
			(int)kerr);
	err = EIO;
pagein_err:
	abort_flags = UPL_ABORT_FREE_ON_EMPTY;
	if (!upl_valid_page(*pl, 0) ||
			(vnode_isnocache(ni->vn) && !upl_dirty_page(*pl, 0)))
		abort_flags |= UPL_ABORT_DUMP_PAGES;
	ubc_upl_abort_range(*upl, 0, PAGE_SIZE, abort_flags);
err:
	*upl = NULL;
	return err;
}
Ejemplo n.º 20
0
/**
 * ntfs_lookup - find the inode represented by a dentry in a directory inode
 * @dir_ino:	directory inode in which to look for the inode
 * @dent:	dentry representing the inode to look for
 * @flags:	lookup flags
 *
 * In short, ntfs_lookup() looks for the inode represented by the dentry @dent
 * in the directory inode @dir_ino and if found attaches the inode to the
 * dentry @dent.
 *
 * In more detail, the dentry @dent specifies which inode to look for by
 * supplying the name of the inode in @dent->d_name.name. ntfs_lookup()
 * converts the name to Unicode and walks the contents of the directory inode
 * @dir_ino looking for the converted Unicode name. If the name is found in the
 * directory, the corresponding inode is loaded by calling ntfs_iget() on its
 * inode number and the inode is associated with the dentry @dent via a call to
 * d_splice_alias().
 *
 * If the name is not found in the directory, a NULL inode is inserted into the
 * dentry @dent via a call to d_add(). The dentry is then termed a negative
 * dentry.
 *
 * Only if an actual error occurs, do we return an error via ERR_PTR().
 *
 * In order to handle the case insensitivity issues of NTFS with regards to the
 * dcache and the dcache requiring only one dentry per directory, we deal with
 * dentry aliases that only differ in case in ->ntfs_lookup() while maintaining
 * a case sensitive dcache. This means that we get the full benefit of dcache
 * speed when the file/directory is looked up with the same case as returned by
 * ->ntfs_readdir() but that a lookup for any other case (or for the short file
 * name) will not find anything in dcache and will enter ->ntfs_lookup()
 * instead, where we search the directory for a fully matching file name
 * (including case) and if that is not found, we search for a file name that
 * matches with different case and if that has non-POSIX semantics we return
 * that. We actually do only one search (case sensitive) and keep tabs on
 * whether we have found a case insensitive match in the process.
 *
 * To simplify matters for us, we do not treat the short vs long filenames as
 * two hard links but instead if the lookup matches a short filename, we
 * return the dentry for the corresponding long filename instead.
 *
 * There are three cases we need to distinguish here:
 *
 * 1) @dent perfectly matches (i.e. including case) a directory entry with a
 *    file name in the WIN32 or POSIX namespaces. In this case
 *    ntfs_lookup_inode_by_name() will return with name set to NULL and we
 *    just d_splice_alias() @dent.
 * 2) @dent matches (not including case) a directory entry with a file name in
 *    the WIN32 namespace. In this case ntfs_lookup_inode_by_name() will return
 *    with name set to point to a kmalloc()ed ntfs_name structure containing
 *    the properly cased little endian Unicode name. We convert the name to the
 *    current NLS code page, search if a dentry with this name already exists
 *    and if so return that instead of @dent.  At this point things are
 *    complicated by the possibility of 'disconnected' dentries due to NFS
 *    which we deal with appropriately (see the code comments).  The VFS will
 *    then destroy the old @dent and use the one we returned.  If a dentry is
 *    not found, we allocate a new one, d_splice_alias() it, and return it as
 *    above.
 * 3) @dent matches either perfectly or not (i.e. we don't care about case) a
 *    directory entry with a file name in the DOS namespace. In this case
 *    ntfs_lookup_inode_by_name() will return with name set to point to a
 *    kmalloc()ed ntfs_name structure containing the mft reference (cpu endian)
 *    of the inode. We use the mft reference to read the inode and to find the
 *    file name in the WIN32 namespace corresponding to the matched short file
 *    name. We then convert the name to the current NLS code page, and proceed
 *    searching for a dentry with this name, etc, as in case 2), above.
 *
 * Locking: Caller must hold i_mutex on the directory.
 */
static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
		unsigned int flags)
{
	ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
	struct inode *dent_inode;
	ntfschar *uname;
	ntfs_name *name = NULL;
	MFT_REF mref;
	unsigned long dent_ino;
	int uname_len;

	ntfs_debug("Looking up %pd in directory inode 0x%lx.",
			dent, dir_ino->i_ino);
	/* Convert the name of the dentry to Unicode. */
	uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len,
			&uname);
	if (uname_len < 0) {
		if (uname_len != -ENAMETOOLONG)
			ntfs_error(vol->sb, "Failed to convert name to "
					"Unicode.");
		return ERR_PTR(uname_len);
	}
	mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len,
			&name);
	kmem_cache_free(ntfs_name_cache, uname);
	if (!IS_ERR_MREF(mref)) {
		dent_ino = MREF(mref);
		ntfs_debug("Found inode 0x%lx. Calling ntfs_iget.", dent_ino);
		dent_inode = ntfs_iget(vol->sb, dent_ino);
		if (likely(!IS_ERR(dent_inode))) {
			/* Consistency check. */
			if (is_bad_inode(dent_inode) || MSEQNO(mref) ==
					NTFS_I(dent_inode)->seq_no ||
					dent_ino == FILE_MFT) {
				/* Perfect WIN32/POSIX match. -- Case 1. */
				if (!name) {
					ntfs_debug("Done.  (Case 1.)");
					return d_splice_alias(dent_inode, dent);
				}
				/*
				 * We are too indented.  Handle imperfect
				 * matches and short file names further below.
				 */
				goto handle_name;
			}
			ntfs_error(vol->sb, "Found stale reference to inode "
					"0x%lx (reference sequence number = "
					"0x%x, inode sequence number = 0x%x), "
					"returning -EIO. Run chkdsk.",
					dent_ino, MSEQNO(mref),
					NTFS_I(dent_inode)->seq_no);
			iput(dent_inode);
			dent_inode = ERR_PTR(-EIO);
		} else
			ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with "
					"error code %li.", dent_ino,
					PTR_ERR(dent_inode));
		kfree(name);
		/* Return the error code. */
		return ERR_CAST(dent_inode);
	}
	/* It is guaranteed that @name is no longer allocated at this point. */
	if (MREF_ERR(mref) == -ENOENT) {
		ntfs_debug("Entry was not found, adding negative dentry.");
		/* The dcache will handle negative entries. */
		d_add(dent, NULL);
		ntfs_debug("Done.");
		return NULL;
	}
	ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error "
			"code %i.", -MREF_ERR(mref));
	return ERR_PTR(MREF_ERR(mref));
	// TODO: Consider moving this lot to a separate function! (AIA)
handle_name:
   {
	MFT_RECORD *m;
	ntfs_attr_search_ctx *ctx;
	ntfs_inode *ni = NTFS_I(dent_inode);
	int err;
	struct qstr nls_name;

	nls_name.name = NULL;
	if (name->type != FILE_NAME_DOS) {			/* Case 2. */
		ntfs_debug("Case 2.");
		nls_name.len = (unsigned)ntfs_ucstonls(vol,
				(ntfschar*)&name->name, name->len,
				(unsigned char**)&nls_name.name, 0);
		kfree(name);
	} else /* if (name->type == FILE_NAME_DOS) */ {		/* Case 3. */
		FILE_NAME_ATTR *fn;

		ntfs_debug("Case 3.");
		kfree(name);

		/* Find the WIN32 name corresponding to the matched DOS name. */
		ni = NTFS_I(dent_inode);
		m = map_mft_record(ni);
		if (IS_ERR(m)) {
			err = PTR_ERR(m);
			m = NULL;
			ctx = NULL;
			goto err_out;
		}
		ctx = ntfs_attr_get_search_ctx(ni, m);
		if (unlikely(!ctx)) {
			err = -ENOMEM;
			goto err_out;
		}
		do {
			ATTR_RECORD *a;
			u32 val_len;

			err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0,
					NULL, 0, ctx);
			if (unlikely(err)) {
				ntfs_error(vol->sb, "Inode corrupt: No WIN32 "
						"namespace counterpart to DOS "
						"file name. Run chkdsk.");
				if (err == -ENOENT)
					err = -EIO;
				goto err_out;
			}
			/* Consistency checks. */
			a = ctx->attr;
			if (a->non_resident || a->flags)
				goto eio_err_out;
			val_len = le32_to_cpu(a->data.resident.value_length);
			if (le16_to_cpu(a->data.resident.value_offset) +
					val_len > le32_to_cpu(a->length))
				goto eio_err_out;
			fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
					ctx->attr->data.resident.value_offset));
			if ((u32)(fn->file_name_length * sizeof(ntfschar) +
					sizeof(FILE_NAME_ATTR)) > val_len)
				goto eio_err_out;
		} while (fn->file_name_type != FILE_NAME_WIN32);

		/* Convert the found WIN32 name to current NLS code page. */
		nls_name.len = (unsigned)ntfs_ucstonls(vol,
				(ntfschar*)&fn->file_name, fn->file_name_length,
				(unsigned char**)&nls_name.name, 0);

		ntfs_attr_put_search_ctx(ctx);
		unmap_mft_record(ni);
	}
	m = NULL;
	ctx = NULL;

	/* Check if a conversion error occurred. */
	if ((signed)nls_name.len < 0) {
		err = (signed)nls_name.len;
		goto err_out;
	}
	nls_name.hash = full_name_hash(dent, nls_name.name, nls_name.len);

	dent = d_add_ci(dent, dent_inode, &nls_name);
	kfree(nls_name.name);
	return dent;

eio_err_out:
	ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
	err = -EIO;
err_out:
	if (ctx)
		ntfs_attr_put_search_ctx(ctx);
	if (m)
		unmap_mft_record(ni);
	iput(dent_inode);
	ntfs_error(vol->sb, "Failed, returning error code %i.", err);
	return ERR_PTR(err);
   }
}
Ejemplo n.º 21
0
/**
 * ntfs_mark_quotas_out_of_date - mark the quotas out of date on an ntfs volume
 * @vol:	ntfs volume on which to mark the quotas out of date
 *
 * Mark the quotas out of date on the ntfs volume @vol and return TRUE on
 * success and FALSE on error.
 */
BOOL ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
{
	ntfs_index_context *ictx;
	QUOTA_CONTROL_ENTRY *qce;
	const le32 qid = QUOTA_DEFAULTS_ID;
	int err;

	ntfs_debug("Entering.");
	if (NVolQuotaOutOfDate(vol))
		goto done;
	if (!vol->quota_ino || !vol->quota_q_ino) {
		ntfs_error(vol->sb, "Quota inodes are not open.");
		return FALSE;
	}
	down(&vol->quota_q_ino->i_sem);
	ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino));
	if (!ictx) {
		ntfs_error(vol->sb, "Failed to get index context.");
		goto err_out;
	}
	err = ntfs_index_lookup(&qid, sizeof(qid), ictx);
	if (err) {
		if (err == -ENOENT)
			ntfs_error(vol->sb, "Quota defaults entry is not "
					"present.");
		else
			ntfs_error(vol->sb, "Lookup of quota defaults entry "
					"failed.");
		goto err_out;
	}
	if (ictx->data_len < offsetof(QUOTA_CONTROL_ENTRY, sid)) {
		ntfs_error(vol->sb, "Quota defaults entry size is invalid.  "
				"Run chkdsk.");
		goto err_out;
	}
	qce = (QUOTA_CONTROL_ENTRY*)ictx->data;
	if (le32_to_cpu(qce->version) != QUOTA_VERSION) {
		ntfs_error(vol->sb, "Quota defaults entry version 0x%x is not "
				"supported.", le32_to_cpu(qce->version));
		goto err_out;
	}
	ntfs_debug("Quota defaults flags = 0x%x.", le32_to_cpu(qce->flags));
	/* If quotas are already marked out of date, no need to do anything. */
	if (qce->flags & QUOTA_FLAG_OUT_OF_DATE)
		goto set_done;
	/*
	 * If quota tracking is neither requested, nor enabled and there are no
	 * pending deletes, no need to mark the quotas out of date.
	 */
	if (!(qce->flags & (QUOTA_FLAG_TRACKING_ENABLED |
			QUOTA_FLAG_TRACKING_REQUESTED |
			QUOTA_FLAG_PENDING_DELETES)))
		goto set_done;
	/*
	 * Set the QUOTA_FLAG_OUT_OF_DATE bit thus marking quotas out of date.
	 * This is verified on WinXP to be sufficient to cause windows to
	 * rescan the volume on boot and update all quota entries.
	 */
	qce->flags |= QUOTA_FLAG_OUT_OF_DATE;
	/* Ensure the modified flags are written to disk. */
	ntfs_index_entry_flush_dcache_page(ictx);
	ntfs_index_entry_mark_dirty(ictx);
set_done:
	ntfs_index_ctx_put(ictx);
	up(&vol->quota_q_ino->i_sem);
	/*
	 * We set the flag so we do not try to mark the quotas out of date
	 * again on remount.
	 */
	NVolSetQuotaOutOfDate(vol);
done:
	ntfs_debug("Done.");
	return TRUE;
err_out:
	if (ictx)
		ntfs_index_ctx_put(ictx);
	up(&vol->quota_q_ino->i_sem);
	return FALSE;
}
Ejemplo n.º 22
0
/* ntfs_read_inode is called by the Virtual File System (the kernel layer that
 * deals with filesystems) when iget is called requesting an inode not already
 * present in the inode table. Typically filesystems have separate
 * inode_operations for directories, files and symlinks.
 */
static void ntfs_read_inode(struct inode* inode)
{
	ntfs_volume *vol;
	int can_mmap=0;
	ntfs_inode *ino;
	ntfs_attribute *data;
	ntfs_attribute *si;

	vol=NTFS_INO2VOL(inode);
	inode->i_op=NULL;
	inode->i_mode=0;
	ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n",(unsigned)inode->i_ino);

	switch(inode->i_ino)
	{
		/* those are loaded special files */
	case FILE_MFT:
		ntfs_error("Trying to open MFT\n");return;
	default:
		#ifdef NTFS_IN_LINUX_KERNEL
		ino=&inode->u.ntfs_i;
		#else
		/* FIXME: check for ntfs_malloc failure */
		ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
		inode->u.generic_ip=ino;
		#endif
		if(!ino || ntfs_init_inode(ino,
					   NTFS_INO2VOL(inode),inode->i_ino))
		{
			ntfs_debug(DEBUG_OTHER, "NTFS:Error loading inode %x\n",
			       (unsigned int)inode->i_ino);
			return;
		}
	}
	/* Set uid/gid from mount options */
	inode->i_uid=vol->uid;
	inode->i_gid=vol->gid;
	inode->i_nlink=1;
	/* Use the size of the data attribute as file size */
	data = ntfs_find_attr(ino,vol->at_data,NULL);
	if(!data)
	{
		inode->i_size=0;
		can_mmap=0;
	}
	else
	{
		inode->i_size=data->size;
		can_mmap=!data->resident && !data->compressed;
	}
	/* get the file modification times from the standard information */
	si=ntfs_find_attr(ino,vol->at_standard_information,NULL);
	if(si){
		char *attr=si->d.data;
		inode->i_atime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18));
		inode->i_ctime=ntfs_ntutc2unixutc(NTFS_GETU64(attr));
		inode->i_mtime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+8));
	}
	/* if it has an index root, it's a directory */
	if(ntfs_find_attr(ino,vol->at_index_root,"$I30"))
	{
		ntfs_attribute *at;
		at = ntfs_find_attr (ino, vol->at_index_allocation, "$I30");
		inode->i_size = at ? at->size : 0;
	  
		inode->i_op=&ntfs_dir_inode_operations;
		inode->i_mode=S_IFDIR|S_IRUGO|S_IXUGO;
	}
	else
	{
		inode->i_op=can_mmap ? &ntfs_inode_operations : 
			&ntfs_inode_operations_nobmap;
		inode->i_mode=S_IFREG|S_IRUGO;
	}
#ifdef CONFIG_NTFS_RW
	if(!data || !data->compressed)
		inode->i_mode|=S_IWUGO;
#endif
	inode->i_mode &= ~vol->umask;
}
Ejemplo n.º 23
0
Archivo: fs.c Proyecto: hugh712/Jollen
/* ntfs_read_inode() is called by the Virtual File System (the kernel layer 
 * that deals with filesystems) when iget is called requesting an inode not
 * already present in the inode table. Typically filesystems have separate
 * inode_operations for directories, files and symlinks. */
static void ntfs_read_inode(struct inode* inode)
{
	ntfs_volume *vol;
	ntfs_inode *ino;
	ntfs_attribute *data;
	ntfs_attribute *si;

	vol = NTFS_INO2VOL(inode);
	inode->i_mode = 0;
	ntfs_debug(DEBUG_OTHER, "ntfs_read_inode 0x%lx\n", inode->i_ino);
	switch (inode->i_ino) {
		/* Those are loaded special files. */
	case FILE_Mft:
		if (!vol->mft_ino || ((vol->ino_flags & 1) == 0))
			goto sys_file_error;
		ntfs_memcpy(&inode->u.ntfs_i, vol->mft_ino, sizeof(ntfs_inode));
		ino = vol->mft_ino;
		vol->mft_ino = &inode->u.ntfs_i;
		vol->ino_flags &= ~1;
		ntfs_free(ino);
		ino = vol->mft_ino;
		ntfs_debug(DEBUG_OTHER, "Opening $MFT!\n");
		break;
	case FILE_MftMirr:
		if (!vol->mftmirr || ((vol->ino_flags & 2) == 0))
			goto sys_file_error;
		ntfs_memcpy(&inode->u.ntfs_i, vol->mftmirr, sizeof(ntfs_inode));
		ino = vol->mftmirr;
		vol->mftmirr = &inode->u.ntfs_i;
		vol->ino_flags &= ~2;
		ntfs_free(ino);
		ino = vol->mftmirr;
		ntfs_debug(DEBUG_OTHER, "Opening $MFTMirr!\n");
		break;
	case FILE_BitMap:
		if (!vol->bitmap || ((vol->ino_flags & 4) == 0))
			goto sys_file_error;
		ntfs_memcpy(&inode->u.ntfs_i, vol->bitmap, sizeof(ntfs_inode));
		ino = vol->bitmap;
		vol->bitmap = &inode->u.ntfs_i;
		vol->ino_flags &= ~4;
		ntfs_free(ino);
		ino = vol->bitmap;
		ntfs_debug(DEBUG_OTHER, "Opening $Bitmap!\n");
		break;
	case FILE_LogFile ... FILE_AttrDef:
	/* No need to log root directory accesses. */
	case FILE_Boot ... FILE_UpCase:
		ntfs_debug(DEBUG_OTHER, "Opening system file %i!\n",
				inode->i_ino);
	default:
		ino = &inode->u.ntfs_i;
		if (!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode),
								inode->i_ino))
		{
			ntfs_debug(DEBUG_OTHER, "NTFS: Error loading inode "
					"0x%x\n", (unsigned int)inode->i_ino);
			return;
		}
	}
	/* Set uid/gid from mount options */
	inode->i_uid = vol->uid;
	inode->i_gid = vol->gid;
	inode->i_nlink = 1;
	/* Use the size of the data attribute as file size */
	data = ntfs_find_attr(ino, vol->at_data, NULL);
	if (!data)
		inode->i_size = 0;
	else
		inode->i_size = data->size;
	/* Get the file modification times from the standard information. */
	si = ntfs_find_attr(ino, vol->at_standard_information, NULL);
	if (si) {
		char *attr = si->d.data;
		inode->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18));
		inode->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr));
		inode->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8));
	}
	/* If it has an index root, it's a directory. */
	if (ntfs_find_attr(ino, vol->at_index_root, "$I30")) {
		ntfs_attribute *at;
		at = ntfs_find_attr(ino, vol->at_index_allocation, "$I30");
		inode->i_size = at ? at->size : 0;
		inode->i_op = &ntfs_dir_inode_operations;
		inode->i_fop = &ntfs_dir_operations;
		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
	} else {
		inode->i_op = &ntfs_inode_operations;
		inode->i_fop = &ntfs_file_operations;
		inode->i_mode = S_IFREG | S_IRUGO;
	}
#ifdef CONFIG_NTFS_RW
	if (!data || !(data->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)))
		inode->i_mode |= S_IWUGO;
#endif
	inode->i_mode &= ~vol->umask;
	return;
sys_file_error:
	ntfs_error("Critical error. Tried to call ntfs_read_inode() before we "
		"have completed read_super() or VFS error.\n");
	// FIXME: Should we panic() at this stage?
}
Ejemplo n.º 24
0
/**
 * ntfs_lookup - find the inode represented by a dentry in a directory inode
 * @dir_ino:	directory inode in which to look for the inode
 * @dent:	dentry representing the inode to look for
 * @nd:		lookup nameidata
 *
 * In short, ntfs_lookup() looks for the inode represented by the dentry @dent
 * in the directory inode @dir_ino and if found attaches the inode to the
 * dentry @dent.
 *
 * In more detail, the dentry @dent specifies which inode to look for by
 * supplying the name of the inode in @dent->d_name.name. ntfs_lookup()
 * converts the name to Unicode and walks the contents of the directory inode
 * @dir_ino looking for the converted Unicode name. If the name is found in the
 * directory, the corresponding inode is loaded by calling ntfs_iget() on its
 * inode number and the inode is associated with the dentry @dent via a call to
 * d_splice_alias().
 *
 * If the name is not found in the directory, a NULL inode is inserted into the
 * dentry @dent via a call to d_add(). The dentry is then termed a negative
 * dentry.
 *
 * Only if an actual error occurs, do we return an error via ERR_PTR().
 *
 * In order to handle the case insensitivity issues of NTFS with regards to the
 * dcache and the dcache requiring only one dentry per directory, we deal with
 * dentry aliases that only differ in case in ->ntfs_lookup() while maintaining
 * a case sensitive dcache. This means that we get the full benefit of dcache
 * speed when the file/directory is looked up with the same case as returned by
 * ->ntfs_readdir() but that a lookup for any other case (or for the short file
 * name) will not find anything in dcache and will enter ->ntfs_lookup()
 * instead, where we search the directory for a fully matching file name
 * (including case) and if that is not found, we search for a file name that
 * matches with different case and if that has non-POSIX semantics we return
 * that. We actually do only one search (case sensitive) and keep tabs on
 * whether we have found a case insensitive match in the process.
 *
 * To simplify matters for us, we do not treat the short vs long filenames as
 * two hard links but instead if the lookup matches a short filename, we
 * return the dentry for the corresponding long filename instead.
 *
 * There are three cases we need to distinguish here:
 *
 * 1) @dent perfectly matches (i.e. including case) a directory entry with a
 *    file name in the WIN32 or POSIX namespaces. In this case
 *    ntfs_lookup_inode_by_name() will return with name set to NULL and we
 *    just d_splice_alias() @dent.
 * 2) @dent matches (not including case) a directory entry with a file name in
 *    the WIN32 namespace. In this case ntfs_lookup_inode_by_name() will return
 *    with name set to point to a kmalloc()ed ntfs_name structure containing
 *    the properly cased little endian Unicode name. We convert the name to the
 *    current NLS code page, search if a dentry with this name already exists
 *    and if so return that instead of @dent.  At this point things are
 *    complicated by the possibility of 'disconnected' dentries due to NFS
 *    which we deal with appropriately (see the code comments).  The VFS will
 *    then destroy the old @dent and use the one we returned.  If a dentry is
 *    not found, we allocate a new one, d_splice_alias() it, and return it as
 *    above.
 * 3) @dent matches either perfectly or not (i.e. we don't care about case) a
 *    directory entry with a file name in the DOS namespace. In this case
 *    ntfs_lookup_inode_by_name() will return with name set to point to a
 *    kmalloc()ed ntfs_name structure containing the mft reference (cpu endian)
 *    of the inode. We use the mft reference to read the inode and to find the
 *    file name in the WIN32 namespace corresponding to the matched short file
 *    name. We then convert the name to the current NLS code page, and proceed
 *    searching for a dentry with this name, etc, as in case 2), above.
 *
 * Locking: Caller must hold i_mutex on the directory.
 */
static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
		struct nameidata *nd)
{
	ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
	struct inode *dent_inode;
	ntfschar *uname;
	ntfs_name *name = NULL;
	MFT_REF mref;
	unsigned long dent_ino;
	int uname_len;

	ntfs_debug("Looking up %s in directory inode 0x%lx.",
			dent->d_name.name, dir_ino->i_ino);
	/* Convert the name of the dentry to Unicode. */
	uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len,
			&uname);
	if (uname_len < 0) {
		if (uname_len != -ENAMETOOLONG)
			ntfs_error(vol->sb, "Failed to convert name to "
					"Unicode.");
		return ERR_PTR(uname_len);
	}
	mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len,
			&name);
	kmem_cache_free(ntfs_name_cache, uname);
	if (!IS_ERR_MREF(mref)) {
		dent_ino = MREF(mref);
		ntfs_debug("Found inode 0x%lx. Calling ntfs_iget.", dent_ino);
		dent_inode = ntfs_iget(vol->sb, dent_ino);
		if (likely(!IS_ERR(dent_inode))) {
			/* Consistency check. */
			if (is_bad_inode(dent_inode) || MSEQNO(mref) ==
					NTFS_I(dent_inode)->seq_no ||
					dent_ino == FILE_MFT) {
				/* Perfect WIN32/POSIX match. -- Case 1. */
				if (!name) {
					ntfs_debug("Done.  (Case 1.)");
					return d_splice_alias(dent_inode, dent);
				}
				/*
				 * We are too indented.  Handle imperfect
				 * matches and short file names further below.
				 */
				goto handle_name;
			}
			ntfs_error(vol->sb, "Found stale reference to inode "
					"0x%lx (reference sequence number = "
					"0x%x, inode sequence number = 0x%x), "
					"returning -EIO. Run chkdsk.",
					dent_ino, MSEQNO(mref),
					NTFS_I(dent_inode)->seq_no);
			iput(dent_inode);
			dent_inode = ERR_PTR(-EIO);
		} else
			ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with "
					"error code %li.", dent_ino,
					PTR_ERR(dent_inode));
		kfree(name);
		/* Return the error code. */
		return (struct dentry *)dent_inode;
	}
	/* It is guaranteed that @name is no longer allocated at this point. */
	if (MREF_ERR(mref) == -ENOENT) {
		ntfs_debug("Entry was not found, adding negative dentry.");
		/* The dcache will handle negative entries. */
		d_add(dent, NULL);
		ntfs_debug("Done.");
		return NULL;
	}
	ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error "
			"code %i.", -MREF_ERR(mref));
	return ERR_PTR(MREF_ERR(mref));
	// TODO: Consider moving this lot to a separate function! (AIA)
handle_name:
   {
	struct dentry *real_dent, *new_dent;
	MFT_RECORD *m;
	ntfs_attr_search_ctx *ctx;
	ntfs_inode *ni = NTFS_I(dent_inode);
	int err;
	struct qstr nls_name;

	nls_name.name = NULL;
	if (name->type != FILE_NAME_DOS) {			/* Case 2. */
		ntfs_debug("Case 2.");
		nls_name.len = (unsigned)ntfs_ucstonls(vol,
				(ntfschar*)&name->name, name->len,
				(unsigned char**)&nls_name.name, 0);
		kfree(name);
	} else /* if (name->type == FILE_NAME_DOS) */ {		/* Case 3. */
		FILE_NAME_ATTR *fn;

		ntfs_debug("Case 3.");
		kfree(name);

		/* Find the WIN32 name corresponding to the matched DOS name. */
		ni = NTFS_I(dent_inode);
		m = map_mft_record(ni);
		if (IS_ERR(m)) {
			err = PTR_ERR(m);
			m = NULL;
			ctx = NULL;
			goto err_out;
		}
		ctx = ntfs_attr_get_search_ctx(ni, m);
		if (unlikely(!ctx)) {
			err = -ENOMEM;
			goto err_out;
		}
		do {
			ATTR_RECORD *a;
			u32 val_len;

			err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0,
					NULL, 0, ctx);
			if (unlikely(err)) {
				ntfs_error(vol->sb, "Inode corrupt: No WIN32 "
						"namespace counterpart to DOS "
						"file name. Run chkdsk.");
				if (err == -ENOENT)
					err = -EIO;
				goto err_out;
			}
			/* Consistency checks. */
			a = ctx->attr;
			if (a->non_resident || a->flags)
				goto eio_err_out;
			val_len = le32_to_cpu(a->data.resident.value_length);
			if (le16_to_cpu(a->data.resident.value_offset) +
					val_len > le32_to_cpu(a->length))
				goto eio_err_out;
			fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
					ctx->attr->data.resident.value_offset));
			if ((u32)(fn->file_name_length * sizeof(ntfschar) +
					sizeof(FILE_NAME_ATTR)) > val_len)
				goto eio_err_out;
		} while (fn->file_name_type != FILE_NAME_WIN32);

		/* Convert the found WIN32 name to current NLS code page. */
		nls_name.len = (unsigned)ntfs_ucstonls(vol,
				(ntfschar*)&fn->file_name, fn->file_name_length,
				(unsigned char**)&nls_name.name, 0);

		ntfs_attr_put_search_ctx(ctx);
		unmap_mft_record(ni);
	}
	m = NULL;
	ctx = NULL;

	/* Check if a conversion error occurred. */
	if ((signed)nls_name.len < 0) {
		err = (signed)nls_name.len;
		goto err_out;
	}
	nls_name.hash = full_name_hash(nls_name.name, nls_name.len);

	/*
	 * Note: No need for dent->d_lock lock as i_mutex is held on the
	 * parent inode.
	 */

	/* Does a dentry matching the nls_name exist already? */
	real_dent = d_lookup(dent->d_parent, &nls_name);
	/* If not, create it now. */
	if (!real_dent) {
		real_dent = d_alloc(dent->d_parent, &nls_name);
		kfree(nls_name.name);
		if (!real_dent) {
			err = -ENOMEM;
			goto err_out;
		}
		new_dent = d_splice_alias(dent_inode, real_dent);
		if (new_dent)
			dput(real_dent);
		else
			new_dent = real_dent;
		ntfs_debug("Done.  (Created new dentry.)");
		return new_dent;
	}
	kfree(nls_name.name);
	/* Matching dentry exists, check if it is negative. */
	if (real_dent->d_inode) {
		if (unlikely(real_dent->d_inode != dent_inode)) {
			/* This can happen because bad inodes are unhashed. */
			BUG_ON(!is_bad_inode(dent_inode));
			BUG_ON(!is_bad_inode(real_dent->d_inode));
		}
		/*
		 * Already have the inode and the dentry attached, decrement
		 * the reference count to balance the ntfs_iget() we did
		 * earlier on.  We found the dentry using d_lookup() so it
		 * cannot be disconnected and thus we do not need to worry
		 * about any NFS/disconnectedness issues here.
		 */
		iput(dent_inode);
		ntfs_debug("Done.  (Already had inode and dentry.)");
		return real_dent;
	}
	/*
	 * Negative dentry: instantiate it unless the inode is a directory and
	 * has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED),
	 * in which case d_move() that in place of the found dentry.
	 */
	if (!S_ISDIR(dent_inode->i_mode)) {
		/* Not a directory; everything is easy. */
		d_instantiate(real_dent, dent_inode);
		ntfs_debug("Done.  (Already had negative file dentry.)");
		return real_dent;
	}
	spin_lock(&dcache_lock);
	if (list_empty(&dent_inode->i_dentry)) {
		/*
		 * Directory without a 'disconnected' dentry; we need to do
		 * d_instantiate() by hand because it takes dcache_lock which
		 * we already hold.
		 */
		list_add(&real_dent->d_alias, &dent_inode->i_dentry);
		real_dent->d_inode = dent_inode;
		spin_unlock(&dcache_lock);
		security_d_instantiate(real_dent, dent_inode);
		ntfs_debug("Done.  (Already had negative directory dentry.)");
		return real_dent;
	}
	/*
	 * Directory with a 'disconnected' dentry; get a reference to the
	 * 'disconnected' dentry.
	 */
	new_dent = list_entry(dent_inode->i_dentry.next, struct dentry,
			d_alias);
	dget_locked(new_dent);
	spin_unlock(&dcache_lock);
	/* Do security vodoo. */
	security_d_instantiate(real_dent, dent_inode);
	/* Move new_dent in place of real_dent. */
	d_move(new_dent, real_dent);
	/* Balance the ntfs_iget() we did above. */
	iput(dent_inode);
	/* Throw away real_dent. */
	dput(real_dent);
	/* Use new_dent as the actual dentry. */
	ntfs_debug("Done.  (Already had negative, disconnected directory "
			"dentry.)");
	return new_dent;

eio_err_out:
	ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
	err = -EIO;
err_out:
	if (ctx)
		ntfs_attr_put_search_ctx(ctx);
	if (m)
		unmap_mft_record(ni);
	iput(dent_inode);
	ntfs_error(vol->sb, "Failed, returning error code %i.", err);
	return ERR_PTR(err);
   }
}
Ejemplo n.º 25
0
/**
 * ntfs_inode_hash_get - find or allocate, and return a loaded ntfs inode
 *
 * Search the ntfs inode hash for the ntfs inode matching @na and if present
 * return it.
 *
 * If the found ntfs inode has a vnode attached, then get an iocount reference
 * on the vnode.
 *
 * If not present, allocate the ntfs inode, add it to the hash, and initialize
 * it before returning it.  The inode will be marked NInoAlloc() and no vnode
 * will be attached yet.
 */
ntfs_inode *ntfs_inode_hash_get(ntfs_volume *vol, const ntfs_attr *na)
{
	ntfs_inode_list_head *list;
	ntfs_inode *ni, *nni;

	ntfs_debug("Entering for mft_no 0x%llx, type 0x%x, name_len 0x%x.",
			(unsigned long long)na->mft_no,
			(unsigned)le32_to_cpu(na->type), na->name_len);
	list = ntfs_inode_hash_list(vol, na->mft_no);
	ni = ntfs_inode_hash_list_find(vol, list, na);
	if (ni) {
		ntfs_debug("Done (ntfs_inode found in cache).");
		return ni;
	}
	/* Not found, allocate a new ntfs_inode and initialize it. */
	nni = malloc(sizeof(ntfs_inode), M_NTFS, M_WAITOK);
	if (!nni) {
		ntfs_error(vol->mp, "Failed to allocate new ntfs_inode.");
		return nni;
	}
	if (ntfs_inode_init(vol, nni, na)) {
		free(nni, M_NTFS);
		ntfs_error(vol->mp, "Failed to initialize new ntfs_inode.");
		return NULL;
	}
	/*
	 * Take the hash lock and ensure a racing process did not already
	 * allocate the inode by searching for it again in the cache.
	 */
retry:
	mtx_lock(&ntfs_inode_hash_lock);
	ni = ntfs_inode_hash_list_find_nolock(vol, list, na);
	if (ni) {
		/*
		 * Someone else already added the ntfs inode so return that and
		 * throw away ours.
		 */
		vnode_t vn;
		u32 vn_id = 0;

		vn = ni->vn;
		if (vn)
			vn_id = vnode_vid(vn);
		/* Drops the hash lock. */
		ntfs_inode_wait_locked(ni, &ntfs_inode_hash_lock);
		if (vn && vnode_getwithvid(vn, vn_id))
			goto retry;
		free(nni, M_NTFS);
		ntfs_debug("Done (ntfs_inode found in cache - lost race)).");
		return ni;
	}
	/*
	 * We have allocated a new ntfs inode, it is NInoLocked() and
	 * NInoAlloc() and we hold the hash lock so we can now add our inode to
	 * the hash list bucket and drop the hash lock.
	 */
	LIST_INSERT_HEAD(list, nni, hash);
	mtx_unlock(&ntfs_inode_hash_lock);
	/* Add the inode to the list of inodes in the volume. */
	mtx_lock(&vol->inodes_lock);
	LIST_INSERT_HEAD(&vol->inodes, nni, inodes);
	mtx_unlock(&vol->inodes_lock);
	ntfs_debug("Done (new ntfs_inode added to cache).");
	return nni;
}
Ejemplo n.º 26
0
/**
 * ntfs_get_parent - find the dentry of the parent of a given directory dentry
 * @child_dent:		dentry of the directory whose parent directory to find
 *
 * Find the dentry for the parent directory of the directory specified by the
 * dentry @child_dent.  This function is called from
 * fs/exportfs/expfs.c::find_exported_dentry() which in turn is called from the
 * default ->decode_fh() which is export_decode_fh() in the same file.
 *
 * The code is based on the ext3 ->get_parent() implementation found in
 * fs/ext3/namei.c::ext3_get_parent().
 *
 * Note: ntfs_get_parent() is called with @child_dent->d_inode->i_mutex down.
 *
 * Return the dentry of the parent directory on success or the error code on
 * error (IS_ERR() is true).
 */
static struct dentry *ntfs_get_parent(struct dentry *child_dent)
{
	struct inode *vi = child_dent->d_inode;
	ntfs_inode *ni = NTFS_I(vi);
	MFT_RECORD *mrec;
	ntfs_attr_search_ctx *ctx;
	ATTR_RECORD *attr;
	FILE_NAME_ATTR *fn;
	struct inode *parent_vi;
	struct dentry *parent_dent;
	unsigned long parent_ino;
	int err;

	ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
	/* Get the mft record of the inode belonging to the child dentry. */
	mrec = map_mft_record(ni);
	if (IS_ERR(mrec))
		return (struct dentry *)mrec;
	/* Find the first file name attribute in the mft record. */
	ctx = ntfs_attr_get_search_ctx(ni, mrec);
	if (unlikely(!ctx)) {
		unmap_mft_record(ni);
		return ERR_PTR(-ENOMEM);
	}
try_next:
	err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL,
			0, ctx);
	if (unlikely(err)) {
		ntfs_attr_put_search_ctx(ctx);
		unmap_mft_record(ni);
		if (err == -ENOENT)
			ntfs_error(vi->i_sb, "Inode 0x%lx does not have a "
					"file name attribute.  Run chkdsk.",
					vi->i_ino);
		return ERR_PTR(err);
	}
	attr = ctx->attr;
	if (unlikely(attr->non_resident))
		goto try_next;
	fn = (FILE_NAME_ATTR *)((u8 *)attr +
			le16_to_cpu(attr->data.resident.value_offset));
	if (unlikely((u8 *)fn + le32_to_cpu(attr->data.resident.value_length) >
			(u8*)attr + le32_to_cpu(attr->length)))
		goto try_next;
	/* Get the inode number of the parent directory. */
	parent_ino = MREF_LE(fn->parent_directory);
	/* Release the search context and the mft record of the child. */
	ntfs_attr_put_search_ctx(ctx);
	unmap_mft_record(ni);
	/* Get the inode of the parent directory. */
	parent_vi = ntfs_iget(vi->i_sb, parent_ino);
	if (IS_ERR(parent_vi) || unlikely(is_bad_inode(parent_vi))) {
		if (!IS_ERR(parent_vi))
			iput(parent_vi);
		ntfs_error(vi->i_sb, "Failed to get parent directory inode "
				"0x%lx of child inode 0x%lx.", parent_ino,
				vi->i_ino);
		return ERR_PTR(-EACCES);
	}
	/* Finally get a dentry for the parent directory and return it. */
	parent_dent = d_alloc_anon(parent_vi);
	if (unlikely(!parent_dent)) {
		iput(parent_vi);
		return ERR_PTR(-ENOMEM);
	}
	ntfs_debug("Done for inode 0x%lx.", vi->i_ino);
	return parent_dent;
}
Ejemplo n.º 27
0
/**
 * ntfs_ucstonls - convert little endian Unicode string to NLS string
 * @vol:	ntfs volume which we are working with
 * @ins:	input Unicode string buffer
 * @ins_len:	length of input string in Unicode characters
 * @outs:	on return contains the (allocated) output NLS string buffer
 * @outs_len:	length of output string buffer in bytes
 *
 * Convert the input little endian, 2-byte Unicode string @ins, of length
 * @ins_len into the string format dictated by the loaded NLS.
 *
 * If *@outs is NULL, this function allocates the string and the caller is
 * responsible for calling kfree(*@outs); when finished with it. In this case
 * @outs_len is ignored and can be 0.
 *
 * On success the function returns the number of bytes written to the output
 * string *@outs (>= 0), not counting the terminating NULL byte. If the output
 * string buffer was allocated, *@outs is set to it.
 *
 * On error, a negative number corresponding to the error code is returned. In
 * that case the output string is not allocated. The contents of *@outs are
 * then undefined.
 *
 * This might look a bit odd due to fast path optimization...
 */
int ntfs_ucstonls(const ntfs_volume *vol, const ntfschar *ins,
		const int ins_len, unsigned char **outs, int outs_len)
{
	struct nls_table *nls = vol->nls_map;
	unsigned char *ns;
	int i, o, ns_len, wc;

	
	if (ins) {
		ns = *outs;
		ns_len = outs_len;
		if (ns && !ns_len) {
			wc = -ENAMETOOLONG;
			goto conversion_err;
		}
		if (!ns) {
			ns_len = ins_len * NLS_MAX_CHARSET_SIZE;
			ns = kmalloc(ns_len + 1, GFP_NOFS);
			if (!ns)
				goto mem_err_out;
		}
		for (i = o = 0; i < ins_len; i++) {
retry:			wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o,
					ns_len - o);
			if (wc > 0) {
				o += wc;
				continue;
			} else if (!wc)
				break;
			else if (wc == -ENAMETOOLONG && ns != *outs) {
				unsigned char *tc;
				
				tc = kmalloc((ns_len + 64) &
						~63, GFP_NOFS);
				if (tc) {
					memcpy(tc, ns, ns_len);
					ns_len = ((ns_len + 64) & ~63) - 1;
					kfree(ns);
					ns = tc;
					goto retry;
				} 
			} 
			goto conversion_err;
		}
		ns[o] = 0;
		*outs = ns;
		return o;
	} 
	ntfs_error(vol->sb, "Received NULL pointer.");
	return -EINVAL;
conversion_err:
	ntfs_error(vol->sb, "Unicode name contains characters that cannot be "
			"converted to character set %s.  You might want to "
			"try to use the mount option nls=utf8.", nls->charset);
	if (ns != *outs)
		kfree(ns);
	if (wc != -ENAMETOOLONG)
		wc = -EILSEQ;
	return wc;
mem_err_out:
	ntfs_error(vol->sb, "Failed to allocate name!");
	return -ENOMEM;
}
Ejemplo n.º 28
0
/**
 * ntfs_pagein - read a range of pages into memory
 * @ni:		ntfs inode whose data to read into the page range
 * @attr_ofs:	byte offset in the inode at which to start
 * @size:	number of bytes to read from the inode
 * @upl:	page list describing destination page range
 * @upl_ofs:	byte offset into page list at which to start
 * @flags:	flags further describing the pagein request
 *
 * Read @size bytes from the ntfs inode @ni, starting at byte offset @attr_ofs
 * into the inode, into the range of pages specified by the page list @upl,
 * starting at byte offset @upl_ofs into the page list.
 *
 * The @flags further describe the pagein request.  The following pagein flags
 * are currently defined in OSX kernel:
 *	UPL_IOSYNC	- Perform synchronous i/o.
 *	UPL_NOCOMMIT	- Do not commit/abort the page range.
 *	UPL_NORDAHEAD	- Do not perform any speculative read-ahead.
 *	IO_PASSIVE	- This is background i/o so do not throttle other i/o.
 *
 * Inside the ntfs driver we have the need to perform pageins whilst the inode
 * is locked for writing (@ni->lock) thus we cheat and set UPL_NESTED_PAGEOUT
 * in @flags when this is the case.  We make sure to clear it in @flags before
 * calling into the cluster layer so we do not accidentally cause confusion.
 *
 * For encrypted attributes we abort for now as we do not support them yet.
 *
 * For non-resident, non-compressed attributes we use cluster_pagein_ext()
 * which deals with both normal and multi sector transfer protected attributes.
 *
 * For resident attributes and non-resident, compressed attributes we read the
 * data ourselves by mapping the page list, and in the resident case, mapping
 * the mft record, looking up the attribute in it, and copying the requested
 * data from the mapped attribute into the page list, then unmapping the mft
 * record, whilst for non-resident, compressed attributes, we get the raw inode
 * and use it with ntfs_read_compressed() to read and decompress the data into
 * our mapped page list.  We then unmap the page list and finally, if
 * UPL_NOCOMMIT is not specified, we commit (success) or abort (error) the page
 * range.
 *
 * Return 0 on success and errno on error.
 *
 * Note the pages in the page list are marked busy on entry and the busy bit is
 * cleared when we commit the page range.  Thus it is perfectly safe for us to
 * fill the pages with encrypted or mst protected data and to decrypt or mst
 * deprotect in place before committing the page range.
 *
 * Adapted from cluster_pagein_ext().
 *
 * Locking: - Caller must hold an iocount reference on the vnode of @ni.
 *	    - Caller must not hold @ni->lock or if it is held it must be for
 *	      reading unless UPL_NESTED_PAGEOUT is set in @flags in which case
 *	      the caller must hold @ni->lock for reading or writing.
 */
int ntfs_pagein(ntfs_inode *ni, s64 attr_ofs, unsigned size, upl_t upl,
		upl_offset_t upl_ofs, int flags)
{
	s64 attr_size;
	u8 *kaddr;
	kern_return_t kerr;
	unsigned to_read;
	int err;
	BOOL locked = FALSE;

	ntfs_debug("Entering for mft_no 0x%llx, offset 0x%llx, size 0x%x, "
			"pagein flags 0x%x, page list offset 0x%llx.",
			(unsigned long long)ni->mft_no,
			(unsigned long long)attr_ofs, size, flags,
			(unsigned long long)upl_ofs);
	/*
	 * If the caller did not specify any i/o, then we are done.  We cannot
	 * issue an abort because we do not have a upl or we do not know its
	 * size.
	 */
	if (!upl) {
		ntfs_error(ni->vol->mp, "NULL page list passed in (error "
				"EINVAL).");
		return EINVAL;
	}
	if (S_ISDIR(ni->mode)) {
		ntfs_error(ni->vol->mp, "Called for directory vnode.");
		err = EISDIR;
		goto err;
	}
	/*
	 * Protect against changes in initialized_size and thus against
	 * truncation also unless UPL_NESTED_PAGEOUT is set in which case the
	 * caller has already taken @ni->lock for exclusive access.  We simply
	 * leave @locked to be FALSE in this case so we do not try to drop the
	 * lock later on.
	 *
	 * If UPL_NESTED_PAGEOUT is set we clear it in @flags to ensure we do
	 * not cause confusion in the cluster layer or the VM.
	 */
	if (flags & UPL_NESTED_PAGEOUT)
		flags &= ~UPL_NESTED_PAGEOUT;
	else {
		locked = TRUE;
		lck_rw_lock_shared(&ni->lock);
	}
	/* Do not allow messing with the inode once it has been deleted. */
	if (NInoDeleted(ni)) {
		/* Remove the inode from the name cache. */
		cache_purge(ni->vn);
		err = ENOENT;
		goto err;
	}
retry_pagein:
	/*
	 * We guarantee that the size in the ubc will be smaller or equal to
	 * the size in the ntfs inode thus no need to check @ni->data_size.
	 */
	attr_size = ubc_getsize(ni->vn);
	/*
	 * Only $DATA attributes can be encrypted/compressed.  Index root can
	 * have the flags set but this means to create compressed/encrypted
	 * files, not that the attribute is compressed/encrypted.  Note we need
	 * to check for AT_INDEX_ALLOCATION since this is the type of directory
	 * index inodes.
	 */
	if (ni->type != AT_INDEX_ALLOCATION) {
		/* TODO: Deny access to encrypted attributes, just like NT4. */
		if (NInoEncrypted(ni)) {
			if (ni->type != AT_DATA)
				panic("%s(): Encrypted non-data attribute.\n",
						__FUNCTION__);
			ntfs_warning(ni->vol->mp, "Denying access to "
					"encrypted attribute (EACCES).");
			err = EACCES;
			goto err;
		}
		/* Compressed data streams need special handling. */
		if (NInoNonResident(ni) && NInoCompressed(ni) && !NInoRaw(ni)) {
			if (ni->type != AT_DATA)
				panic("%s(): Compressed non-data attribute.\n",
						__FUNCTION__);
			goto compressed;
		}
	}
	/* NInoNonResident() == NInoIndexAllocPresent() */
	if (NInoNonResident(ni)) {
		int (*callback)(buf_t, void *);

		callback = NULL;
		if (NInoMstProtected(ni) || NInoEncrypted(ni))
			callback = ntfs_cluster_iodone;
		/* Non-resident, possibly mst protected, attribute. */
		err = cluster_pagein_ext(ni->vn, upl, upl_ofs, attr_ofs, size,
				attr_size, flags, callback, NULL);
		if (!err)
			ntfs_debug("Done (cluster_pagein_ext()).");
		else
			ntfs_error(ni->vol->mp, "Failed (cluster_pagein_ext(), "
					"error %d).", err);
		if (locked)
			lck_rw_unlock_shared(&ni->lock);
		return err;
	}
compressed:
	/*
	 * The attribute is resident and/or compressed.
	 *
	 * Cannot pagein from a negative offset or if we are starting beyond
	 * the end of the attribute or if the attribute offset is not page
	 * aligned or the size requested is not a multiple of PAGE_SIZE.
	 */
	if (attr_ofs < 0 || attr_ofs >= attr_size || attr_ofs & PAGE_MASK_64 ||
			size & PAGE_MASK || upl_ofs & PAGE_MASK) {
		err = EINVAL;
		goto err;
	}
	to_read = size;
	attr_size -= attr_ofs;
	if (to_read > attr_size)
		to_read = attr_size;
	/*
	 * We do not need @attr_size any more so reuse it to hold the number of
	 * bytes available in the attribute starting at offset @attr_ofs up to
	 * a maximum of the requested number of bytes rounded up to a multiple
	 * of the system page size.
	 */
	attr_size = (to_read + PAGE_MASK) & ~PAGE_MASK;
	/* Abort any pages outside the end of the attribute. */
	if (size > attr_size && !(flags & UPL_NOCOMMIT)) {
		ubc_upl_abort_range(upl, upl_ofs + attr_size, size - attr_size,
				UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR);
		/* Update @size. */
		size = attr_size;
	}
	/* To access the page list contents, we need to map the page list. */
	kerr = ubc_upl_map(upl, (vm_offset_t*)&kaddr);
	if (kerr != KERN_SUCCESS) {
		ntfs_error(ni->vol->mp, "ubc_upl_map() failed (error %d).",
				(int)kerr);
		err = EIO;
		goto err;
	}
	if (!NInoNonResident(ni)) {
		/*
		 * Read the data from the resident attribute into the page
		 * list.
		 */
		err = ntfs_resident_attr_read(ni, attr_ofs, size,
				kaddr + upl_ofs);
		if (err && err != EAGAIN)
			ntfs_error(ni->vol->mp, "ntfs_resident_attr_read() "
					"failed (error %d).", err);
	} else {
		ntfs_inode *raw_ni;
		int ioflags;

		/*
		 * Get the raw inode.  We take the inode lock shared to protect
		 * against concurrent writers as the compressed data is invalid
		 * whilst a write is in progress.
		 */
		err = ntfs_raw_inode_get(ni, LCK_RW_TYPE_SHARED, &raw_ni);
		if (err)
			ntfs_error(ni->vol->mp, "Failed to get raw inode "
					"(error %d).", err);
		else {
			if (!NInoRaw(raw_ni))
				panic("%s(): Requested raw inode but got "
						"non-raw one.\n", __FUNCTION__);
			ioflags = 0;
			if (vnode_isnocache(ni->vn) ||
					vnode_isnocache(raw_ni->vn))
				ioflags |= IO_NOCACHE;
			if (vnode_isnoreadahead(ni->vn) ||
					vnode_isnoreadahead(raw_ni->vn))
				ioflags |= IO_RAOFF;
			err = ntfs_read_compressed(ni, raw_ni, attr_ofs, size,
					kaddr + upl_ofs, NULL, ioflags);
			if (err)
				ntfs_error(ni->vol->mp,
						"ntfs_read_compressed() "
						"failed (error %d).", err);
			lck_rw_unlock_shared(&raw_ni->lock);
			(void)vnode_put(raw_ni->vn);
		}
	}
	kerr = ubc_upl_unmap(upl);
	if (kerr != KERN_SUCCESS) {
		ntfs_error(ni->vol->mp, "ubc_upl_unmap() failed (error %d).",
				(int)kerr);
		if (!err)
			err = EIO;
	}
	if (!err) {
		if (!(flags & UPL_NOCOMMIT)) {
			/* Commit the page range we brought up to date. */
			ubc_upl_commit_range(upl, upl_ofs, size,
					UPL_COMMIT_FREE_ON_EMPTY);
		}
		ntfs_debug("Done (%s).", !NInoNonResident(ni) ?
				"ntfs_resident_attr_read()" :
				"ntfs_read_compressed()");
	} else /* if (err) */ {
		/*
		 * If the attribute was converted to non-resident under our
		 * nose, retry the pagein.
		 *
		 * TODO: This may no longer be possible to happen now that we
		 * lock against changes in initialized size and thus
		 * truncation...  Revisit this issue when the write code has
		 * been written and remove the check + goto if appropriate.
		 */
		if (err == EAGAIN)
			goto retry_pagein;
err:
		if (!(flags & UPL_NOCOMMIT)) {
			int upl_flags = UPL_ABORT_FREE_ON_EMPTY;
			if (err != ENOMEM)
				upl_flags |= UPL_ABORT_ERROR;
			ubc_upl_abort_range(upl, upl_ofs, size, upl_flags);
		}
		ntfs_error(ni->vol->mp, "Failed (error %d).", err);
	}
	if (locked)
		lck_rw_unlock_shared(&ni->lock);
	return err;
}
Ejemplo n.º 29
0
static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
		struct nameidata *nd)
{
	ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
	struct inode *dent_inode;
	ntfschar *uname;
	ntfs_name *name = NULL;
	MFT_REF mref;
	unsigned long dent_ino;
	int uname_len;

	ntfs_debug("Looking up %s in directory inode 0x%lx.",
			dent->d_name.name, dir_ino->i_ino);
	
	uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len,
			&uname);
	if (uname_len < 0) {
		if (uname_len != -ENAMETOOLONG)
			ntfs_error(vol->sb, "Failed to convert name to "
					"Unicode.");
		return ERR_PTR(uname_len);
	}
	mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len,
			&name);
	kmem_cache_free(ntfs_name_cache, uname);
	if (!IS_ERR_MREF(mref)) {
		dent_ino = MREF(mref);
		ntfs_debug("Found inode 0x%lx. Calling ntfs_iget.", dent_ino);
		dent_inode = ntfs_iget(vol->sb, dent_ino);
		if (likely(!IS_ERR(dent_inode))) {
			
			if (is_bad_inode(dent_inode) || MSEQNO(mref) ==
					NTFS_I(dent_inode)->seq_no ||
					dent_ino == FILE_MFT) {
				
				if (!name) {
					ntfs_debug("Done.  (Case 1.)");
					return d_splice_alias(dent_inode, dent);
				}
				goto handle_name;
			}
			ntfs_error(vol->sb, "Found stale reference to inode "
					"0x%lx (reference sequence number = "
					"0x%x, inode sequence number = 0x%x), "
					"returning -EIO. Run chkdsk.",
					dent_ino, MSEQNO(mref),
					NTFS_I(dent_inode)->seq_no);
			iput(dent_inode);
			dent_inode = ERR_PTR(-EIO);
		} else
			ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with "
					"error code %li.", dent_ino,
					PTR_ERR(dent_inode));
		kfree(name);
		
		return (struct dentry *)dent_inode;
	}
	
	if (MREF_ERR(mref) == -ENOENT) {
		ntfs_debug("Entry was not found, adding negative dentry.");
		
		d_add(dent, NULL);
		ntfs_debug("Done.");
		return NULL;
	}
	ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error "
			"code %i.", -MREF_ERR(mref));
	return ERR_PTR(MREF_ERR(mref));
	
handle_name:
   {
	MFT_RECORD *m;
	ntfs_attr_search_ctx *ctx;
	ntfs_inode *ni = NTFS_I(dent_inode);
	int err;
	struct qstr nls_name;

	nls_name.name = NULL;
	if (name->type != FILE_NAME_DOS) {			
		ntfs_debug("Case 2.");
		nls_name.len = (unsigned)ntfs_ucstonls(vol,
				(ntfschar*)&name->name, name->len,
				(unsigned char**)&nls_name.name, 0);
		kfree(name);
	} else  {		
		FILE_NAME_ATTR *fn;

		ntfs_debug("Case 3.");
		kfree(name);

		
		ni = NTFS_I(dent_inode);
		m = map_mft_record(ni);
		if (IS_ERR(m)) {
			err = PTR_ERR(m);
			m = NULL;
			ctx = NULL;
			goto err_out;
		}
		ctx = ntfs_attr_get_search_ctx(ni, m);
		if (unlikely(!ctx)) {
			err = -ENOMEM;
			goto err_out;
		}
		do {
			ATTR_RECORD *a;
			u32 val_len;

			err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0,
					NULL, 0, ctx);
			if (unlikely(err)) {
				ntfs_error(vol->sb, "Inode corrupt: No WIN32 "
						"namespace counterpart to DOS "
						"file name. Run chkdsk.");
				if (err == -ENOENT)
					err = -EIO;
				goto err_out;
			}
			
			a = ctx->attr;
			if (a->non_resident || a->flags)
				goto eio_err_out;
			val_len = le32_to_cpu(a->data.resident.value_length);
			if (le16_to_cpu(a->data.resident.value_offset) +
					val_len > le32_to_cpu(a->length))
				goto eio_err_out;
			fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
					ctx->attr->data.resident.value_offset));
			if ((u32)(fn->file_name_length * sizeof(ntfschar) +
					sizeof(FILE_NAME_ATTR)) > val_len)
				goto eio_err_out;
		} while (fn->file_name_type != FILE_NAME_WIN32);

		
		nls_name.len = (unsigned)ntfs_ucstonls(vol,
				(ntfschar*)&fn->file_name, fn->file_name_length,
				(unsigned char**)&nls_name.name, 0);

		ntfs_attr_put_search_ctx(ctx);
		unmap_mft_record(ni);
	}
	m = NULL;
	ctx = NULL;

	
	if ((signed)nls_name.len < 0) {
		err = (signed)nls_name.len;
		goto err_out;
	}
	nls_name.hash = full_name_hash(nls_name.name, nls_name.len);

	dent = d_add_ci(dent, dent_inode, &nls_name);
	kfree(nls_name.name);
	return dent;

eio_err_out:
	ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
	err = -EIO;
err_out:
	if (ctx)
		ntfs_attr_put_search_ctx(ctx);
	if (m)
		unmap_mft_record(ni);
	iput(dent_inode);
	ntfs_error(vol->sb, "Failed, returning error code %i.", err);
	return ERR_PTR(err);
   }
}
Ejemplo n.º 30
0
static int ntfs_fill_super(struct super_block *s, void *options, int silent)
{
        struct buffer_head *bh0, *bh1, *bh2;
        struct ntfs_boot_block *bootblock;
        struct ntfs_super_block *superblock;
        struct ntfs_spare_block *spareblock;
        struct ntfs_sb_info *sbi;
        struct inode *root;

        kuid_t uid;
        kgid_t gid;
        umode_t umask;
        int lowercase, eas, chk, errs, chkdsk, timeshift;

        dnode_secno root_dno;
        struct ntfs_dirent *de = NULL;
        struct quad_buffer_head qbh;

        int o;

        save_mount_options(s, options);

        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi) {
                return -ENOMEM;
        }
        s->s_fs_info = sbi;

        sbi->sb_bmp_dir = NULL;
        sbi->sb_cp_table = NULL;

        mutex_init(&sbi->ntfs_mutex);
        ntfs_lock(s);

        uid = current_uid();
        gid = current_gid();
        umask = current_umask();
        lowercase = 0;
        eas = 2;
        chk = 1;
        errs = 1;
        chkdsk = 1;
        timeshift = 0;

        if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase,
            &eas, &chk, &errs, &chkdsk, &timeshift))) {
                printk("NTFS: bad mount options.\n");
                goto bail0;
        }
        if (o==2) {
                ntfs_help();
                goto bail0;
        }

        /*sbi->sb_mounting = 1;*/
        sb_set_blocksize(s, 512);
        sbi->sb_fs_size = -1;
        if (!(bootblock = ntfs_map_sector(s, 0, &bh0, 0))) goto bail1;
        if (!(superblock = ntfs_map_sector(s, 16, &bh1, 1))) goto bail2;
        if (!(spareblock = ntfs_map_sector(s, 17, &bh2, 0))) goto bail3;

        /* Check magics */
        if (/*le16_to_cpu(bootblock->magic) != BB_MAGIC
            ||*/ le32_to_cpu(superblock->magic) != SB_MAGIC
            || le32_to_cpu(spareblock->magic) != SP_MAGIC) {
                if (!silent) printk("NTFS: Bad magic ... probably not NTFS\n");
                goto bail4;
        }

        /* Check version */
        if (!(s->s_flags & MS_RDONLY) &&
              superblock->funcversion != 2 && superblock->funcversion != 3) {
                printk("NTFS: Bad version %d,%d. Mount readonly to go around\n",
                        (int)superblock->version, (int)superblock->funcversion);
                printk("NTFS: please try recent version of NTFS driver at http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/ntfs/index-e.cgi and if it still can't understand this format, contact author - [email protected]\n");
                goto bail4;
        }

        s->s_flags |= MS_NOATIME;

        /* Fill superblock stuff */
        s->s_magic = NTFS_SUPER_MAGIC;
        s->s_op = &ntfs_sops;
        s->s_d_op = &ntfs_dentry_operations;

        sbi->sb_root = le32_to_cpu(superblock->root);
        sbi->sb_fs_size = le32_to_cpu(superblock->n_sectors);
        sbi->sb_bitmaps = le32_to_cpu(superblock->bitmaps);
        sbi->sb_dirband_start = le32_to_cpu(superblock->dir_band_start);
        sbi->sb_dirband_size = le32_to_cpu(superblock->n_dir_band);
        sbi->sb_dmap = le32_to_cpu(superblock->dir_band_bitmap);
        sbi->sb_uid = uid;
        sbi->sb_gid = gid;
        sbi->sb_mode = 0777 & ~umask;
        sbi->sb_n_free = -1;
        sbi->sb_n_free_dnodes = -1;
        sbi->sb_lowercase = lowercase;
        sbi->sb_eas = eas;
        sbi->sb_chk = chk;
        sbi->sb_chkdsk = chkdsk;
        sbi->sb_err = errs;
        sbi->sb_timeshift = timeshift;
        sbi->sb_was_error = 0;
        sbi->sb_cp_table = NULL;
        sbi->sb_c_bitmap = -1;
        sbi->sb_max_fwd_alloc = 0xffffff;

        if (sbi->sb_fs_size >= 0x80000000) {
                ntfs_error(s, "invalid size in superblock: %08x",
                        (unsigned)sbi->sb_fs_size);
                goto bail4;
        }

        /* Load bitmap directory */
        if (!(sbi->sb_bmp_dir = ntfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps))))
                goto bail4;

        /* Check for general fs errors*/
        if (spareblock->dirty && !spareblock->old_wrote) {
                if (errs == 2) {
                        printk("NTFS: Improperly stopped, not mounted\n");
                        goto bail4;
                }
                ntfs_error(s, "improperly stopped");
        }

        if (!(s->s_flags & MS_RDONLY)) {
                spareblock->dirty = 1;
                spareblock->old_wrote = 0;
                mark_buffer_dirty(bh2);
        }

        if (spareblock->hotfixes_used || spareblock->n_spares_used) {
                if (errs >= 2) {
                        printk("NTFS: Hotfixes not supported here, try chkdsk\n");
                        mark_dirty(s, 0);
                        goto bail4;
                }
                ntfs_error(s, "hotfixes not supported here, try chkdsk");
                if (errs == 0) printk("NTFS: Proceeding, but your filesystem will be probably corrupted by this driver...\n");
                else printk("NTFS: This driver may read bad files or crash when operating on disk with hotfixes.\n");
        }
        if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) {
                if (errs >= 2) {
                        printk("NTFS: Spare dnodes used, try chkdsk\n");
                        mark_dirty(s, 0);
                        goto bail4;
                }
                ntfs_error(s, "warning: spare dnodes used, try chkdsk");
                if (errs == 0) printk("NTFS: Proceeding, but your filesystem could be corrupted if you delete files or directories\n");
        }
        if (chk) {
                unsigned a;
                if (le32_to_cpu(superblock->dir_band_end) - le32_to_cpu(superblock->dir_band_start) + 1 != le32_to_cpu(superblock->n_dir_band) ||
                    le32_to_cpu(superblock->dir_band_end) < le32_to_cpu(superblock->dir_band_start) || le32_to_cpu(superblock->n_dir_band) > 0x4000) {
                        ntfs_error(s, "dir band size mismatch: dir_band_start==%08x, dir_band_end==%08x, n_dir_band==%08x",
                                le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->dir_band_end), le32_to_cpu(superblock->n_dir_band));
                        goto bail4;
                }
                a = sbi->sb_dirband_size;
                sbi->sb_dirband_size = 0;
                if (ntfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->n_dir_band), "dir_band") ||
                    ntfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_bitmap), 4, "dir_band_bitmap") ||
                    ntfs_chk_sectors(s, le32_to_cpu(superblock->bitmaps), 4, "bitmaps")) {
                        mark_dirty(s, 0);
                        goto bail4;
                }
                sbi->sb_dirband_size = a;
        } else printk("NTFS: You really don't want any checks? You are crazy...\n");

        /* Load code page table */
        if (le32_to_cpu(spareblock->n_code_pages))
                if (!(sbi->sb_cp_table = ntfs_load_code_page(s, le32_to_cpu(spareblock->code_page_dir))))
                        printk("NTFS: Warning: code page support is disabled\n");

        brelse(bh2);
        brelse(bh1);
        brelse(bh0);

        root = iget_locked(s, sbi->sb_root);
        if (!root)
                goto bail0;
        ntfs_init_inode(root);
        ntfs_read_inode(root);
        unlock_new_inode(root);
        s->s_root = d_make_root(root);
        if (!s->s_root)
                goto bail0;

        /*
         * find the root directory's . pointer & finish filling in the inode
         */

        root_dno = ntfs_fnode_dno(s, sbi->sb_root);
        if (root_dno)
                de = map_dirent(root, root_dno, "\001\001", 2, NULL, &qbh);
        if (!de)
                ntfs_error(s, "unable to find root dir");
        else {
                root->i_atime.tv_sec = local_to_gmt(s, le32_to_cpu(de->read_date));
                root->i_atime.tv_nsec = 0;
                root->i_mtime.tv_sec = local_to_gmt(s, le32_to_cpu(de->write_date));
                root->i_mtime.tv_nsec = 0;
                root->i_ctime.tv_sec = local_to_gmt(s, le32_to_cpu(de->creation_date));
                root->i_ctime.tv_nsec = 0;
                ntfs_i(root)->i_ea_size = le32_to_cpu(de->ea_size);
                ntfs_i(root)->i_parent_dir = root->i_ino;
                if (root->i_size == -1)
                        root->i_size = 2048;
                if (root->i_blocks == -1)
                        root->i_blocks = 5;
                ntfs_brelse4(&qbh);
        }
        ntfs_unlock(s);
        return 0;

bail4:  brelse(bh2);
bail3:  brelse(bh1);
bail2:  brelse(bh0);
bail1:
bail0:
        ntfs_unlock(s);
        kfree(sbi->sb_bmp_dir);
        kfree(sbi->sb_cp_table);
        s->s_fs_info = NULL;
        kfree(sbi);
        return -EINVAL;
}