Пример #1
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;
	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");
}
Пример #2
0
/**
 * ntfs_device_alloc - allocate an ntfs device structure and pre-initialize it
 * @name:	name of the device (must be present)
 * @state:	initial device state (usually zero)
 * @dops:	ntfs device operations to use with the device (must be present)
 * @priv_data:	pointer to private data (optional)
 *
 * Allocate an ntfs device structure and pre-initialize it with the user-
 * specified device operations @dops, device state @state, device name @name,
 * and optional private data @priv_data.
 *
 * Note, @name is copied and can hence be freed after this functions returns.
 *
 * On success return a pointer to the allocated ntfs device structure and on
 * error return NULL with errno set to the error code returned by ntfs_malloc().
 */
struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
		struct ntfs_device_operations *dops, void *priv_data)
{
	struct ntfs_device *dev;

	if (!name) {
		errno = EINVAL;
		return NULL;
	}

	dev = ntfs_malloc(sizeof(struct ntfs_device));
	if (dev) {
		if (!(dev->d_name = strdup(name))) {
			int eo = errno;
			free(dev);
			errno = eo;
			return NULL;
		}
		dev->d_ops = dops;
		dev->d_state = state;
		dev->d_private = priv_data;
		dev->d_heads = -1;
		dev->d_sectors_per_track = -1;
	}
	return dev;
}
Пример #3
0
static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d)
{
	struct inode *res=0;
	char *item=0;
	ntfs_iterate_s walk;
	int error;
	ntfs_debug(DEBUG_NAME1, "Looking up %s in %x\n",d->d_name.name,
		   (unsigned)dir->i_ino);
	/* convert to wide string */
	error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)d->d_name.name,
			     d->d_name.len,&walk.name,&walk.namelen);
	if(error)
		return ERR_PTR(-error);
	item=ntfs_malloc(ITEM_SIZE);
	if( !item )
		return ERR_PTR(-ENOMEM);
	/* ntfs_getdir will place the directory entry into item,
	   and the first long long is the MFT record number */
	walk.type=BY_NAME;
	walk.dir=NTFS_LINO2NINO(dir);
	walk.result=item;
	if(ntfs_getdir_byname(&walk))
	{
		res=iget(dir->i_sb,NTFS_GETU32(item));
	}
	d_add(d,res);
	ntfs_free(item);
	ntfs_free(walk.name);
	/* Always return success, the dcache will handle negative entries. */
	return NULL;
}
Пример #4
0
/**
 * Assumes mft_bitmap_rl is initialized.
 * return: 0 ok.
 *	   RETURN_OPERATIONAL_ERROR on error.
 */
static int mft_bitmap_load(ntfs_volume *rawvol)
{
	VCN vcn;
	u32 mft_bitmap_length;

	vcn = get_last_vcn(mft_bitmap_rl);
	if (vcn<=LCN_EINVAL) {
		mft_bitmap_buf = NULL;
		/* This case should not happen, not even with on-disk errors */
		goto error;
	}

	mft_bitmap_length = vcn * rawvol->cluster_size;
	mft_bitmap_records = 8 * mft_bitmap_length * rawvol->cluster_size /
		rawvol->mft_record_size;

	//printf("sizes: %d, %d.\n", mft_bitmap_length, mft_bitmap_records);

	mft_bitmap_buf = (u8*)ntfs_malloc(mft_bitmap_length);
	if (!mft_bitmap_buf)
		goto error;
	if (ntfs_rl_pread(rawvol, mft_bitmap_rl, 0, mft_bitmap_length,
			mft_bitmap_buf)!=mft_bitmap_length)
		goto error;
	return 0;
error:
	mft_bitmap_records = 0;
	ntfs_log_error("Could not load $MFT/Bitmap.\n");
	return RETURN_OPERATIONAL_ERROR;
}
Пример #5
0
static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie,
			ntfs_index_context *ictx)
{
	INDEX_ENTRY *entry;
	s64 vcn;

	entry = ie;
	do {
		vcn = ntfs_ie_get_vcn(entry);
		if (ictx->is_in_root) {

			/* down from level zero */

			ictx->ir = (INDEX_ROOT*)NULL;
			ictx->ib = (INDEX_BLOCK*)ntfs_malloc(ictx->block_size);
			ictx->pindex = 1;
			ictx->is_in_root = FALSE;
		} else {

			/* down from non-zero level */
			
			ictx->pindex++;
		}
		ictx->parent_pos[ictx->pindex] = 0;
		ictx->parent_vcn[ictx->pindex] = vcn;
		if (!ntfs_ib_read(ictx,vcn,ictx->ib)) {
			ictx->entry = ntfs_ie_get_first(&ictx->ib->index);
			entry = ictx->entry;
		} else
			entry = (INDEX_ENTRY*)NULL;
	} while (entry && (entry->ie_flags & INDEX_ENTRY_NODE));
	return (entry);
}
Пример #6
0
/**
 * ntfs_guid_to_mbs - convert a GUID to a multi byte string
 * @guid:	[IN]  guid to convert
 * @guid_str:	[OUT] string in which to return the GUID (optional)
 *
 * Convert the GUID pointed to by @guid to a multi byte string of the form
 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".  Therefore, @guid_str (if not NULL)
 * needs to be able to store at least 37 bytes.
 *
 * If @guid_str is not NULL it will contain the converted GUID on return.  If
 * it is NULL a string will be allocated and this will be returned.  The caller
 * is responsible for free()ing the string in that case.
 *
 * On success return the converted string and on failure return NULL with errno
 * set to the error code.
 */
char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
{
	char *_guid_str;
	int res;

	if (!guid) {
		errno = EINVAL;
		return NULL;
	}
	_guid_str = guid_str;
	if (!_guid_str) {
		_guid_str = ntfs_malloc(37);
		if (!_guid_str)
			return _guid_str;
	}
	res = snprintf(_guid_str, 37,
			"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
			(unsigned int)le32_to_cpu(guid->data1),
			le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
			guid->data4[0], guid->data4[1],
			guid->data4[2], guid->data4[3], guid->data4[4],
			guid->data4[5], guid->data4[6], guid->data4[7]);
	if (res == 36)
		return _guid_str;
	if (!guid_str)
		free(_guid_str);
	errno = EINVAL;
	return NULL;
}
Пример #7
0
/**
 * ntfs_device_unix_io_open - Open a device and lock it exclusively
 * @dev:
 * @flags:
 *
 * Description...
 *
 * Returns:
 */
static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
{
	struct flock flk;
	struct stat sbuf;
	int err;

	if (NDevOpen(dev)) {
		errno = EBUSY;
		return -1;
	}
	if (stat(dev->d_name, &sbuf)) {
		ntfs_log_perror("Failed to access '%s'", dev->d_name);
		return -1;
	}
	if (S_ISBLK(sbuf.st_mode))
		NDevSetBlock(dev);
	
	dev->d_private = ntfs_malloc(sizeof(int));
	if (!dev->d_private)
		return -1;
	/*
	 * Open file for exclusive access if mounting r/w.
	 * Fuseblk takes care about block devices.
	 */ 
	if (!NDevBlock(dev) && (flags & O_RDWR) == O_RDWR)
		flags |= O_EXCL;
	*(int*)dev->d_private = open(dev->d_name, flags);
	if (*(int*)dev->d_private == -1) {
		err = errno;
		goto err_out;
	}
	
	if ((flags & O_RDWR) != O_RDWR)
		NDevSetReadOnly(dev);
	
	memset(&flk, 0, sizeof(flk));
	if (NDevReadOnly(dev))
		flk.l_type = F_RDLCK;
	else
		flk.l_type = F_WRLCK;
	flk.l_whence = SEEK_SET;
	flk.l_start = flk.l_len = 0LL;
	if (fcntl(DEV_FD(dev), F_SETLK, &flk)) {
		err = errno;
		ntfs_log_perror("Failed to %s lock '%s'", NDevReadOnly(dev) ? 
				"read" : "write", dev->d_name);
		if (close(DEV_FD(dev)))
			ntfs_log_perror("Failed to close '%s'", dev->d_name);
		goto err_out;
	}
	
	NDevSetOpen(dev);
	return 0;
err_out:
	free(dev->d_private);
	dev->d_private = NULL;
	errno = err;
	return -1;
}
Пример #8
0
static int parse_options(int argc, char *argv[])
{
	int c;

	static const char *sopt = "-hrw";
	static const struct option lopt[] = {
		{ "readonly",	no_argument,	NULL, 'r' },
		{ "readwrite",	no_argument,	NULL, 'w' },
		{ "help",	no_argument,	NULL, 'h' },
		{ NULL,		0,		NULL,  0  }
	};

	opterr = 0; /* We handle errors. */
	opts.probetype = PROBE_UNSET;

	while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
		switch (c) {
		case 1:	/* A non-option argument */
			if (!opts.device) {
				opts.device = ntfs_malloc(PATH_MAX + 1);
				if (!opts.device)
					return -1;
				
				strncpy(opts.device, optarg, PATH_MAX);
				opts.device[PATH_MAX] = 0;
			} else {
				ntfs_log_error("%s: You must specify exactly "
					       "one device\n", EXEC_NAME);
				return -1;
			}
			break;
		case 'h':
			usage();
			exit(0);
		case 'r':
			opts.probetype = PROBE_READONLY;
			break;
		case 'w':
			opts.probetype = PROBE_READWRITE;
			break;
		default:
			ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
				       argv[optind - 1]);
			return -1;
		}
	}

	if (!opts.device) {
		ntfs_log_error("ERROR: %s: Device is missing\n", EXEC_NAME);
		return -1;
	}

	if (opts.probetype == PROBE_UNSET) {
		ntfs_log_error("ERROR: %s: Probe type is missing\n", EXEC_NAME);
		return -1;
	}

	return 0;
}
Пример #9
0
static int
_linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
{
	int error;
	struct inode *r = 0;
	ntfs_volume *vol;
	ntfs_inode *ino;
	ntfs_attribute *si;

	ntfs_debug (DEBUG_DIR1, "mkdir %s in %x\n",d->d_name.name, dir->i_ino);
	error = ENAMETOOLONG;
	if (d->d_name.len > /* FIXME */255)
		goto out;

	error = EIO;
	r = get_empty_inode();
	if (!r)
		goto out;
	
	vol = NTFS_INO2VOL(dir);
#ifdef NTFS_IN_LINUX_KERNEL
	ino = NTFS_LINO2NINO(r);
#else
	ino = ntfs_malloc(sizeof(ntfs_inode));
	error = ENOMEM;
	if(!ino)
		goto out;
	r->u.generic_ip = ino;
#endif
	error = ntfs_mkdir(NTFS_LINO2NINO(dir), 
			   d->d_name.name, d->d_name.len, ino);
	if(error)
		goto out;
	r->i_uid = vol->uid;
	r->i_gid = vol->gid;
	r->i_nlink = 1;
	r->i_sb = dir->i_sb;
	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 a directory */
	r->i_op = &ntfs_dir_inode_operations;
	r->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
#ifdef CONFIG_NTFS_RW
	r->i_mode|=S_IWUGO;
#endif
	r->i_mode &= ~vol->umask;	
	
	insert_inode_hash(r);
	d_instantiate(d, r);
	error = 0;
 out:
 	ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", -error);
	return -error;
}
Пример #10
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;
}
Пример #11
0
static INDEX_ENTRY *ntfs_ie_dup(INDEX_ENTRY *ie)
{
	INDEX_ENTRY *dup;
	
	ntfs_log_trace("Entering\n");
	
	dup = ntfs_malloc(le16_to_cpu(ie->length));
	if (dup)
		memcpy(dup, ie, le16_to_cpu(ie->length));
	
	return dup;
}
Пример #12
0
static int ntfs_index_rm_leaf(ntfs_index_context *icx)
{
	INDEX_BLOCK *ib = NULL;
	INDEX_HEADER *parent_ih;
	INDEX_ENTRY *ie;
	int ret = STATUS_ERROR;
	
	ntfs_log_trace("pindex: %d\n", icx->pindex);
	
	if (ntfs_icx_parent_dec(icx))
		return STATUS_ERROR;

	if (ntfs_ibm_clear(icx, icx->parent_vcn[icx->pindex + 1]))
		return STATUS_ERROR;
	
	if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT)
		parent_ih = &icx->ir->index;
	else {
		ib = ntfs_malloc(icx->block_size);
		if (!ib)
			return STATUS_ERROR;
		
		if (ntfs_ib_read(icx, ntfs_icx_parent_vcn(icx), ib))
			goto out;
	
		parent_ih = &ib->index;
	}
	
	ie = ntfs_ie_get_by_pos(parent_ih, ntfs_icx_parent_pos(icx));
	if (!ntfs_ie_end(ie)) {
		ret = ntfs_ih_takeout(icx, parent_ih, ie, ib);
		goto out;
	}
		
	if (ntfs_ih_zero_entry(parent_ih)) {
		
		if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) {
			ntfs_ir_leafify(icx, parent_ih);
			goto ok;
		}
		
		ret = ntfs_index_rm_leaf(icx);
		goto out;
	}
		
	if (ntfs_ih_reparent_end(icx, parent_ih, ib))
		goto out;
ok:	
	ret = STATUS_OK;
out:
	free(ib);
	return ret;
}
Пример #13
0
struct XATTRMAPPING *ntfs_xattr_build_mapping(ntfs_volume *vol,
			const char *xattrmap_path)
{
	struct XATTRMAPPING *firstmapping;
	struct XATTRMAPPING *mapping;
	BOOL user_efs;
	BOOL notfound;
	ntfs_inode *ni;
	int fd;

	firstmapping = (struct XATTRMAPPING*)NULL;
	notfound = FALSE;
	if (!xattrmap_path)
		xattrmap_path = XATTRMAPPINGFILE;
	if (xattrmap_path[0] == '/') {
		fd = open(xattrmap_path,O_RDONLY);
		if (fd > 0) {
			firstmapping = ntfs_read_xattr_mapping(basicread, (void*)&fd);
			close(fd);
		} else
			notfound = TRUE;
	} else {
		ni = ntfs_pathname_to_inode(vol, NULL, xattrmap_path);
		if (ni) {
			firstmapping = ntfs_read_xattr_mapping(localread, ni);
			ntfs_inode_close(ni);
		} else
			notfound = TRUE;
	}
	if (notfound && strcmp(xattrmap_path, XATTRMAPPINGFILE)) {
		ntfs_log_early_error("Could not open \"%s\"\n",xattrmap_path);
	}
	if (vol->efs_raw) {
		user_efs = TRUE;
		for (mapping=firstmapping; mapping; mapping=mapping->next)
			if (mapping->xattr == XATTR_NTFS_EFSINFO)
				user_efs = FALSE;
	} else
		user_efs = FALSE;
	if (user_efs) {
		mapping = (struct XATTRMAPPING*)ntfs_malloc(
				sizeof(struct XATTRMAPPING)
				+ strlen(nf_ns_alt_xattr_efsinfo));
		if (mapping) {
			mapping->next = firstmapping;
			mapping->xattr = XATTR_NTFS_EFSINFO;
			strcpy(mapping->name,nf_ns_alt_xattr_efsinfo);
			firstmapping = mapping;
		}
	}
	return (firstmapping);
}
Пример #14
0
static int set_new_serial(ntfs_volume *vol)
{
	NTFS_BOOT_SECTOR *bs; /* full boot sectors */
	NTFS_BOOT_SECTOR *oldbs; /* full original boot sector */
	le64 serial_number;
	u64 number_of_sectors;
	u64 sn;
	int res;

	res = -1;
	bs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size);
	oldbs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size);
	if (bs && oldbs) {
		if (opts.serial)
			serial_number = cpu_to_le64(opts.serial);
		else {
			/* different values for parallel processes */
			srandom(time((time_t*)NULL) ^ (getpid() << 16));
			sn = ((u64)random() << 32)
					| ((u64)random() & 0xffffffff);
			serial_number = cpu_to_le64(sn);
		}
		if (!change_serial(vol, 0, serial_number, bs, oldbs)) {
			number_of_sectors = le64_to_cpu(bs->number_of_sectors);
			if (!change_serial(vol, number_of_sectors,
						serial_number, bs, oldbs)) {
				ntfs_log_info("New serial number : %016llx\n",
					(long long)le64_to_cpu(
						bs->volume_serial_number));
				res = 0;
				}
		}
		free(bs);
		free(oldbs);
	}
	if (res)
		ntfs_log_info("Error setting a new serial number\n");
	return (res);
}
Пример #15
0
/**
 * ntfs_ucsndup - duplicate little endian Unicode string
 * @s:		pointer to Unicode string
 * @maxlen:	maximum length of string @s
 *
 * Return a pointer to a new little endian Unicode string which is a duplicate
 * of the string s.  Memory for the new string is obtained with ntfs_malloc(3),
 * and can be freed with free(3).
 *
 * A maximum of @maxlen Unicode characters are copied and a terminating
 * (ntfschar)'\0' little endian Unicode character is added.
 *
 * This function never looks beyond @s + @maxlen.
 *
 * Return a pointer to the new little endian Unicode string on success and NULL
 * on failure with errno set to the error code.
 */
ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen)
{
	ntfschar *dst;
	u32 len;

	len = ntfs_ucsnlen(s, maxlen);
	dst = ntfs_malloc((len + 1) * sizeof(ntfschar));
	if (dst) {
		memcpy(dst, s, len * sizeof(ntfschar));
		dst[len] = cpu_to_le16(L'\0');
	}
	return dst;
}
Пример #16
0
/**
 * ntfs_device_unix_io_open - Open a device and lock it exclusively
 * @dev:
 * @flags:
 *
 * Description...
 *
 * Returns:
 */
static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
{
	struct flock flk;
	struct stat sbuf;
	int err;

	if (NDevOpen(dev)) {
		errno = EBUSY;
		return -1;
	}
	if (!(dev->d_private = ntfs_malloc(sizeof(int))))
		return -1;
	*(int*)dev->d_private = open(dev->d_name, flags);
	if (*(int*)dev->d_private == -1) {
		err = errno;
		goto err_out;
	}
	/* Setup our read-only flag. */
	if ((flags & O_RDWR) != O_RDWR)
		NDevSetReadOnly(dev);
	/* Acquire exclusive (mandatory) lock on the whole device. */
	memset(&flk, 0, sizeof(flk));
	if (NDevReadOnly(dev))
		flk.l_type = F_RDLCK;
	else
		flk.l_type = F_WRLCK;
	flk.l_whence = SEEK_SET;
	flk.l_start = flk.l_len = 0LL;
	if (fcntl(DEV_FD(dev), F_SETLK, &flk)) {
		err = errno;
		ntfs_log_debug("ntfs_device_unix_io_open: Could not lock %s "
				"for %s\n", dev->d_name, NDevReadOnly(dev) ?
				"reading" : "writing");
		if (close(DEV_FD(dev)))
			ntfs_log_perror("ntfs_device_unix_io_open: Warning: "
					"Could not close %s", dev->d_name);
		goto err_out;
	}
	/* Determine if device is a block device or not, ignoring errors. */
	if (!fstat(DEV_FD(dev), &sbuf) && S_ISBLK(sbuf.st_mode))
		NDevSetBlock(dev);
	/* Set our open flag. */
	NDevSetOpen(dev);
	return 0;
err_out:
	free(dev->d_private);
	dev->d_private = NULL;
	errno = err;
	return -1;
}
Пример #17
0
int ntfs_calc_free_space(nspace *_ns)
{
	nspace		*ns = (nspace*)_ns;
	ntfs_volume *vol = ns->ntvol;	
	ntfs_attr 	*data = vol->lcnbmp_na;
	s64 		free_clusters = 0;
	off_t 	 	pos = 0;
	size_t 	 	readed;
	unsigned 	char *buf = NULL;
			
	if (ns == NULL || vol == NULL || data == NULL)
		return -1;
		
	if (vol->lcnbmp_na == NULL)
		return -1;

	if (!(ns->state & NF_FreeClustersOutdate))
		return -1;	

	buf = (unsigned char*)ntfs_malloc(vol->cluster_size);
	if (buf == NULL)
		goto exit;
	
	while (pos < data->data_size) {
		if (pos % vol->cluster_size == 0) {
			readed = ntfs_attr_pread(vol->lcnbmp_na, pos,
				min(data->data_size - pos, vol->cluster_size), buf);
			if (readed < B_NO_ERROR)
				goto error;
			if (readed != min(data->data_size - pos, vol->cluster_size))
				goto error;
		}

		free_clusters += ntfs_count_bits( buf[pos%vol->cluster_size],
			min((vol->nr_clusters) - (pos * 8), 8));
		pos++;
	}
error:
	free(buf);
exit:	
	ns->free_clusters = free_clusters;
	ns->state &= ~(NF_FreeClustersOutdate);
	
	return B_NO_ERROR;
}
Пример #18
0
static status_t
get_node_type(ntfs_inode* ni, int* _type)
{
	ntfs_attr* na;

	if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
		// Directory
		*_type = S_IFDIR;
		return B_OK;
	} else {
		// Regular or Interix (INTX) file
		*_type = S_IFREG;

		if (ni->flags & FILE_ATTR_SYSTEM) {
			na = ntfs_attr_open(ni, AT_DATA, NULL,0);
			if (!na) {
				return ENOENT;
			}
			// Check whether it's Interix symbolic link
			if (na->data_size <= sizeof(INTX_FILE_TYPES) +
			    sizeof(ntfschar) * PATH_MAX &&
			    na->data_size > sizeof(INTX_FILE_TYPES)) {
				INTX_FILE *intx_file;

				intx_file = ntfs_malloc(na->data_size);
				if (!intx_file) {
					ntfs_attr_close(na);
					return EINVAL;
				}
				if (ntfs_attr_pread(na, 0, na->data_size,
						intx_file) != na->data_size) {
					free(intx_file);
					ntfs_attr_close(na);
					return EINVAL;
				}
				if (intx_file->magic == INTX_SYMBOLIC_LINK)
					*_type = FS_SLNK_MODE;
				free(intx_file);
			}
			ntfs_attr_close(na);
		}
	}

	return B_OK;
}
Пример #19
0
/*
 * ntfs_utf16_to_utf8 - convert a little endian UTF16LE string to an UTF-8 string
 * @ins:	input utf16 string buffer
 * @ins_len:	length of input string in utf16 characters
 * @outs:	on return contains the (allocated) output multibyte string
 * @outs_len:	length of output buffer in bytes
 *
 * Return -1 with errno set if string has invalid byte sequence or too long.
 */
static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
			      char **outs, int outs_len)
{
#if defined(__APPLE__) || defined(__DARWIN__)
#ifdef ENABLE_NFCONV
	char *original_outs_value = *outs;
	int original_outs_len = outs_len;
#endif /* ENABLE_NFCONV */
#endif /* defined(__APPLE__) || defined(__DARWIN__) */

	char *t;
	int i, size, ret = -1;
	int halfpair;

	halfpair = 0;
	if (!*outs)
		outs_len = PATH_MAX;

	size = utf16_to_utf8_size(ins, ins_len, outs_len);

	if (size < 0)
		goto out;

	if (!*outs) {
		outs_len = size + 1;
		*outs = ntfs_malloc(outs_len);
		if (!*outs)
			goto out;
	}

	t = *outs;

	for (i = 0; i < ins_len && ins[i]; i++) {
	    unsigned short c = le16_to_cpu(ins[i]);
			/* size not double-checked */
		if (halfpair) {
			if ((c >= 0xdc00) && (c < 0xe000)) {
				*t++ = 0xf0 + (((halfpair + 64) >> 8) & 7);
				*t++ = 0x80 + (((halfpair + 64) >> 2) & 63);
				*t++ = 0x80 + ((c >> 6) & 15) + ((halfpair & 3) << 4);
				*t++ = 0x80 + (c & 63);
				halfpair = 0;
			} else 
				goto fail;
		} else if (c < 0x80) {
Пример #20
0
static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie)
{
	INDEX_ENTRY *dup;
	int size = le16_to_cpu(ie->length);
	
	ntfs_log_trace("Entering\n");
	
	if (ie->ie_flags & INDEX_ENTRY_NODE)
		size -= sizeof(VCN);
	
	dup = ntfs_malloc(size);
	if (dup) {
		memcpy(dup, ie, size);
		dup->ie_flags &= ~INDEX_ENTRY_NODE;
		dup->length = cpu_to_le16(size);
	}
	return dup;
}
Пример #21
0
static int print_serial(ntfs_volume *vol)
{
	NTFS_BOOT_SECTOR *bs; /* full boot sectors */
	int res;

	res = -1;
	bs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size);
	if (bs
	    && (ntfs_pread(vol->dev, 0,
			vol->sector_size, bs) == vol->sector_size)) {
		ntfs_log_info("Serial number : %016llx\n",
			(long long)le64_to_cpu(bs->volume_serial_number));
		res = 0;
		free(bs);
	}
	if (res)
		ntfs_log_info("Error getting the serial number\n");
	return (res);
}
Пример #22
0
/**
 * ntfs_index_root_get - read the index root of an attribute
 * @ni:		open ntfs inode in which the ntfs attribute resides
 * @attr:	attribute for which we want its index root 
 *
 * This function will read the related index root an ntfs attribute.
 *
 * On success a buffer is allocated with the content of the index root
 * and which needs to be freed when it's not needed anymore.
 *
 * On error NULL is returned with errno set to the error code.
 */
INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr)
{
	ntfs_attr_search_ctx *ctx;
	ntfschar *name;
	INDEX_ROOT *root = NULL;

	name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset));

	if (!ntfs_ir_lookup(ni, name, attr->name_length, &ctx))
		return NULL;
	
	root = ntfs_malloc(sizeof(INDEX_ROOT));
	if (!root)
		goto out;
	
	*root = *((INDEX_ROOT *)((u8 *)ctx->attr +
				le16_to_cpu(ctx->attr->value_offset)));
out:	
	ntfs_attr_put_search_ctx(ctx);
	return root;
}
Пример #23
0
/**
 * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
 * On error return STATUS_ERROR.
 */
static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn)
{			  
	INDEX_BLOCK *ib;
	u32 idx_size, allocated_size;
	int err = STATUS_ERROR;
	VCN old_vcn;

	ntfs_log_trace("Entering\n");
	
	ib = ntfs_malloc(icx->block_size);
	if (!ib)
		return -1;
	
	old_vcn = ntfs_icx_parent_vcn(icx);
	
	if (ntfs_ib_read(icx, old_vcn, ib))
		goto err_out;

	idx_size       = le32_to_cpu(ib->index.index_length);
	allocated_size = le32_to_cpu(ib->index.allocated_size);
	/* FIXME: sizeof(VCN) should be included only if ie has no VCN */
	if (idx_size + le16_to_cpu(ie->length) + sizeof(VCN) > allocated_size) {
		err = ntfs_ib_split(icx, ib);
		if (err == STATUS_OK)
			err = STATUS_KEEP_SEARCHING;
		goto err_out;
	}
	
	if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx)))
		goto err_out;
	
	if (ntfs_ib_write(icx, ib))
		goto err_out;
	
	err = STATUS_OK;
err_out:	
	free(ib);
	return err;
}
Пример #24
0
static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d)
{
	struct inode *res = 0;
	char *item = 0;
	ntfs_iterate_s walk;
	int err;
	
	ntfs_debug(DEBUG_NAME1, __FUNCTION__ "(): Looking up %s in directory "
			"ino 0x%x.\n", d->d_name.name, (unsigned)dir->i_ino);
	walk.name = NULL;
	walk.namelen = 0;
	/* Convert to wide string. */
	err = ntfs_decodeuni(NTFS_INO2VOL(dir), (char*)d->d_name.name,
			       d->d_name.len, &walk.name, &walk.namelen);
	if (err)
		goto err_ret;
	item = ntfs_malloc(ITEM_SIZE);
	if (!item) {
		err = -ENOMEM;
		goto err_ret;
	}
	/* ntfs_getdir will place the directory entry into item, and the first
	 * long long is the MFT record number. */
	walk.type = BY_NAME;
	walk.dir = NTFS_LINO2NINO(dir);
	walk.result = item;
	if (ntfs_getdir_byname(&walk))
		res = iget(dir->i_sb, NTFS_GETU32(item));
	d_add(d, res);
	ntfs_free(item);
	ntfs_free(walk.name);
	/* Always return success, the dcache will handle negative entries. */
	return NULL;
err_ret:
	ntfs_free(walk.name);
	return ERR_PTR(err);
}
Пример #25
0
/**
 * parse_options - Read and validate the programs command line
 * Read the command line, verify the syntax and parse the options.
 *
 * Return:   0 success, -1 error.
 */
int ntfs_parse_options(struct ntfs_options *popts, void (*usage)(void),
			int argc, char *argv[])
{
	int c;

	static const char *sopt = "-o:hnvV";
	static const struct option lopt[] = {
		{ "options",	 required_argument,	NULL, 'o' },
		{ "help",	 no_argument,		NULL, 'h' },
		{ "no-mtab",	 no_argument,		NULL, 'n' },
		{ "verbose",	 no_argument,		NULL, 'v' },
		{ "version",	 no_argument,		NULL, 'V' },
		{ NULL,		 0,			NULL,  0  }
	};

	opterr = 0; /* We'll handle the errors, thank you. */

	while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
		switch (c) {
		case 1:	/* A non-option argument */
			if (!popts->device) {
				popts->device = ntfs_malloc(PATH_MAX + 1);
				if (!popts->device)
					return -1;
				
				/* Canonicalize device name (mtab, etc) */
				popts->arg_device = optarg;
				if (!ntfs_realpath_canonicalize(optarg,
						popts->device)) {
					ntfs_log_perror("%s: Failed to access "
					     "volume '%s'", EXEC_NAME, optarg);
					free(popts->device);
					popts->device = NULL;
					return -1;
				}
			} else if (!popts->mnt_point) {
				popts->mnt_point = optarg;
			} else {
				ntfs_log_error("%s: You must specify exactly one "
						"device and exactly one mount "
						"point.\n", EXEC_NAME);
				return -1;
			}
			break;
		case 'o':
			if (popts->options)
				if (ntfs_strappend(&popts->options, ","))
					return -1;
			if (ntfs_strappend(&popts->options, optarg))
				return -1;
			break;
		case 'h':
			usage();
			exit(9);
		case 'n':
			/*
			 * no effect - automount passes it, meaning 'no-mtab'
			 */
			break;
		case 'v':
			/*
			 * We must handle the 'verbose' option even if
			 * we don't use it because mount(8) passes it.
			 */
			break;
		case 'V':
			ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION, 
				      FUSE_TYPE, fuse_version());
			exit(0);
		default:
			ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
				       argv[optind - 1]);
			return -1;
		}
	}

	if (!popts->device) {
		ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
		return -1;
	}
	if (!popts->mnt_point) {
		ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
		return -1;
	}

	return 0;
}
Пример #26
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, 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;
}
Пример #27
0
/**
 * ntfs_index_lookup - find a key in an index and return its index entry
 * @key:	[IN] key for which to search in the index
 * @key_len:	[IN] length of @key in bytes
 * @icx:	[IN/OUT] context describing the index and the returned entry
 *
 * Before calling ntfs_index_lookup(), @icx must have been obtained from a
 * call to ntfs_index_ctx_get().
 *
 * Look for the @key in the index specified by the index lookup context @icx.
 * ntfs_index_lookup() walks the contents of the index looking for the @key.
 *
 * If the @key is found in the index, 0 is returned and @icx is setup to
 * describe the index entry containing the matching @key.  @icx->entry is the
 * index entry and @icx->data and @icx->data_len are the index entry data and
 * its length in bytes, respectively.
 *
 * If the @key is not found in the index, -1 is returned, errno = ENOENT and
 * @icx is setup to describe the index entry whose key collates immediately
 * after the search @key, i.e. this is the position in the index at which
 * an index entry with a key of @key would need to be inserted.
 *
 * If an error occurs return -1, set errno to error code and @icx is left
 * untouched.
 *
 * When finished with the entry and its data, call ntfs_index_ctx_put() to free
 * the context and other associated resources.
 *
 * If the index entry was modified, call ntfs_index_entry_mark_dirty() before
 * the call to ntfs_index_ctx_put() to ensure that the changes are written
 * to disk.
 */
int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *icx)
{
	VCN old_vcn, vcn;
	ntfs_inode *ni = icx->ni;
	INDEX_ROOT *ir;
	INDEX_ENTRY *ie;
	INDEX_BLOCK *ib = NULL;
	int ret, err = 0;

	ntfs_log_trace("Entering\n");
	
	if (!key || key_len <= 0) {
		errno = EINVAL;
		ntfs_log_perror("key: %p  key_len: %d", key, key_len);
		return -1;
	}

	ir = ntfs_ir_lookup(ni, icx->name, icx->name_len, &icx->actx);
	if (!ir) {
		if (errno == ENOENT)
			errno = EIO;
		return -1;
	}
	
	icx->block_size = le32_to_cpu(ir->index_block_size);
	if (icx->block_size < NTFS_BLOCK_SIZE) {
		errno = EINVAL;
		ntfs_log_perror("Index block size (%d) is smaller than the "
				"sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE);
		goto err_out;
	}

	if (ni->vol->cluster_size <= icx->block_size)
		icx->vcn_size_bits = ni->vol->cluster_size_bits;
	else
		icx->vcn_size_bits = NTFS_BLOCK_SIZE_BITS;
			/* get the appropriate collation function */
	icx->collate = ntfs_get_collate_function(ir->collation_rule);
	if (!icx->collate) {
		err = errno = EOPNOTSUPP;
		ntfs_log_perror("Unknown collation rule 0x%x", 
				(unsigned)le32_to_cpu(ir->collation_rule));
		goto err_out;
	}
	
	old_vcn = VCN_INDEX_ROOT_PARENT;
	/* 
	 * FIXME: check for both ir and ib that the first index entry is
	 * within the index block.
	 */
	ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie);
	if (ret == STATUS_ERROR) {
		err = errno;
		goto err_out;
	}
	
	icx->ir = ir;
	
	if (ret != STATUS_KEEP_SEARCHING) {
		/* STATUS_OK or STATUS_NOT_FOUND */
		err = errno;
		icx->is_in_root = TRUE;
		icx->parent_vcn[icx->pindex] = old_vcn;
		goto done;
	}
	
	/* Child node present, descend into it. */
	
	icx->ia_na = ntfs_ia_open(icx, ni);
	if (!icx->ia_na)
		goto err_out;
	
	ib = ntfs_malloc(icx->block_size);
	if (!ib) {
		err = errno;
		goto err_out;
	}
	
descend_into_child_node:

	icx->parent_vcn[icx->pindex] = old_vcn;
	if (ntfs_icx_parent_inc(icx)) {
		err = errno;
		goto err_out;
	}
	old_vcn = vcn;

	ntfs_log_debug("Descend into node with VCN %lld\n", (long long)vcn);
	
	if (ntfs_ib_read(icx, vcn, ib))
		goto err_out;
	
	ret = ntfs_ie_lookup(key, key_len, icx, &ib->index, &vcn, &ie);
	if (ret != STATUS_KEEP_SEARCHING) {
		err = errno;
		if (ret == STATUS_ERROR)
			goto err_out;
		
		/* STATUS_OK or STATUS_NOT_FOUND */
		icx->is_in_root = FALSE;
		icx->ib = ib;
		icx->parent_vcn[icx->pindex] = vcn;
		goto done;
	}

	if ((ib->index.ih_flags & NODE_MASK) == LEAF_NODE) {
		ntfs_log_error("Index entry with child node found in a leaf "
			       "node in inode 0x%llx.\n",
			       (unsigned long long)ni->mft_no);
		goto err_out;
	}
	
	goto descend_into_child_node;
err_out:
	free(ib);
	if (!err)
		err = EIO;
	errno = err;
	return -1;
done:
	icx->entry = ie;
	icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key);
	icx->data_len = le16_to_cpu(ie->key_length);
	ntfs_log_trace("Done.\n");
	if (err) {
		errno = err;
		return -1;
	}
	return 0;

}
Пример #28
0
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);
#ifdef NTFS_IN_LINUX_KERNEL
	ino=NTFS_LINO2NINO(r);
#else
	ino=ntfs_malloc(sizeof(ntfs_inode));
	if(!ino){
		error=ENOMEM;
		goto fail;
	}
	r->u.generic_ip=ino;
#endif
	error=ntfs_alloc_file(NTFS_LINO2NINO(dir),ino,(char*)d->d_name.name,
			       d->d_name.len);
	if(error)goto fail;
	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_nobmap;
	r->i_fop=&ntfs_file_operations_nommap,
	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:
	#ifndef NTFS_IN_LINUX_KERNEL
	if(ino)ntfs_free(ino);
	#endif
	if(r)iput(r);
	return -error;
}
Пример #29
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;
}
Пример #30
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;
}