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"); }
/** * 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; }
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; }
/** * 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; }
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); }
/** * 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; }
/** * 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; }
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; }
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; }
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; }
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; }
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; }
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); }
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); }
/** * 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; }
/** * 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; }
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; }
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; }
/* * 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) {
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; }
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); }
/** * 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; }
/** * 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; }
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); }
/** * 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; }
/* 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; }
/** * 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; }
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; }
/* 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; }
/* 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; }