📄 dir.c
字号:
* @pathname: Pathname to be located * * Take an ASCII pathname and find the inode that represents it. The function * splits the path and then descends the directory tree. If @parent is NULL, * then the root directory '.' will be used as the base for the search. * * Return: inode Success, the pathname was valid * NULL Error, the pathname was invalid, or some other error occurred */ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, const char *pathname){ u64 inum; int len, err = 0; char *p, *q; ntfs_inode *ni; ntfs_inode *result = NULL; ntfschar *unicode = NULL; char *ascii = NULL; if (!vol || !pathname) { errno = EINVAL; return NULL; } ntfs_log_trace("path: '%s'\n", pathname); if (parent) { ni = parent; } else { ni = ntfs_inode_open(vol, FILE_root); if (!ni) { ntfs_log_debug("Couldn't open the inode of the root " "directory.\n"); err = EIO; goto close; } } ascii = strdup(pathname); if (!ascii) { ntfs_log_debug("Out of memory.\n"); err = ENOMEM; goto close; } p = ascii; /* Remove leading /'s. */ while (p && *p && *p == PATH_SEP) p++; while (p && *p) { /* Find the end of the first token. */ q = strchr(p, PATH_SEP); if (q != NULL) { *q = '\0'; q++; } len = ntfs_mbstoucs(p, &unicode); if (len < 0) { ntfs_log_debug("Couldn't convert name to Unicode: %s.\n", p); err = errno; goto close; } else if (len > NTFS_MAX_NAME_LEN) { err = ENAMETOOLONG; goto close; } inum = ntfs_inode_lookup_by_name(ni, unicode, len); if (inum == (u64) -1) { ntfs_log_debug("Couldn't find name '%s' in pathname " "'%s'.\n", p, pathname); err = ENOENT; goto close; } if (ni != parent) if (ntfs_inode_close(ni)) { err = errno; goto out; } inum = MREF(inum); ni = ntfs_inode_open(vol, inum); if (!ni) { ntfs_log_debug("Cannot open inode %llu: %s.\n", (unsigned long long)inum, p); err = EIO; goto close; } free(unicode); unicode = NULL; p = q; while (p && *p && *p == PATH_SEP) p++; } result = ni; ni = NULL;close: if (ni && (ni != parent)) if (ntfs_inode_close(ni) && !err) err = errno;out: free(ascii); free(unicode); if (err) errno = err; return result;}/* * The little endian Unicode string ".." for ntfs_readdir(). */static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), const_cpu_to_le16('.'), const_cpu_to_le16('\0') };/* * union index_union - * More helpers for ntfs_readdir(). */typedef union { INDEX_ROOT *ir; INDEX_ALLOCATION *ia;} index_union __attribute__((__transparent_union__));/** * enum INDEX_TYPE - * More helpers for ntfs_readdir(). */typedef enum { INDEX_TYPE_ROOT, /* index root */ INDEX_TYPE_ALLOCATION, /* index allocation */} INDEX_TYPE;/** * ntfs_filldir - ntfs specific filldir method * @dir_ni: ntfs inode of current directory * @pos: current position in directory * @ivcn_bits: log(2) of index vcn size * @index_type: specifies whether @iu is an index root or an index allocation * @iu: index root or index block to which @ie belongs * @ie: current index entry * @dirent: context for filldir callback supplied by the caller * @filldir: filldir callback supplied by the caller * * Pass information specifying the current directory entry @ie to the @filldir * callback. */static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits, const INDEX_TYPE index_type, index_union iu, INDEX_ENTRY *ie, void *dirent, ntfs_filldir_t filldir){ FILE_NAME_ATTR *fn = &ie->key.file_name; unsigned dt_type; ntfs_log_trace("Entering.\n"); /* Advance the position even if going to skip the entry. */ if (index_type == INDEX_TYPE_ALLOCATION) *pos = (u8*)ie - (u8*)iu.ia + (sle64_to_cpu( iu.ia->index_block_vcn) << ivcn_bits) + dir_ni->vol->mft_record_size; else /* if (index_type == INDEX_TYPE_ROOT) */ *pos = (u8*)ie - (u8*)iu.ir; /* Skip root directory self reference entry. */ if (MREF_LE(ie->indexed_file) == FILE_root) return 0; if (ie->key.file_name.file_attributes & FILE_ATTR_I30_INDEX_PRESENT) dt_type = NTFS_DT_DIR; else if (fn->file_attributes & FILE_ATTR_SYSTEM) dt_type = NTFS_DT_UNKNOWN; else dt_type = NTFS_DT_REG; return filldir(dirent, fn->file_name, fn->file_name_length, fn->file_name_type, *pos, le64_to_cpu(ie->indexed_file), dt_type);}/** * ntfs_mft_get_parent_ref - find mft reference of parent directory of an inode * @ni: ntfs inode whose parent directory to find * * Find the parent directory of the ntfs inode @ni. To do this, find the first * file name attribute in the mft record of @ni and return the parent mft * reference from that. * * Note this only makes sense for directories, since files can be hard linked * from multiple directories and there is no way for us to tell which one is * being looked for. * * Technically directories can have hard links, too, but we consider that as * illegal as Linux/UNIX do not support directory hard links. * * Return the mft reference of the parent directory on success or -1 on error * with errno set to the error code. */static MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni){ MFT_REF mref; ntfs_attr_search_ctx *ctx; FILE_NAME_ATTR *fn; int eo; ntfs_log_trace("Entering.\n"); if (!ni) { errno = EINVAL; return ERR_MREF(-1); } ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) return ERR_MREF(-1); if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { ntfs_log_debug("No file name found in inode 0x%llx. Corrupt " "inode.\n", (unsigned long long)ni->mft_no); goto err_out; } if (ctx->attr->non_resident) { ntfs_log_debug("File name attribute must be resident. Corrupt inode " "0x%llx.\n", (unsigned long long)ni->mft_no); goto io_err_out; } fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); if ((u8*)fn + le32_to_cpu(ctx->attr->value_length) > (u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) { ntfs_log_debug("Corrupt file name attribute in inode 0x%llx.\n", (unsigned long long)ni->mft_no); goto io_err_out; } mref = le64_to_cpu(fn->parent_directory); ntfs_attr_put_search_ctx(ctx); return mref;io_err_out: errno = EIO;err_out: eo = errno; ntfs_attr_put_search_ctx(ctx); errno = eo; return ERR_MREF(-1);}/** * ntfs_readdir - read the contents of an ntfs directory * @dir_ni: ntfs inode of current directory * @pos: current position in directory * @dirent: context for filldir callback supplied by the caller * @filldir: filldir callback supplied by the caller * * Parse the index root and the index blocks that are marked in use in the * index bitmap and hand each found directory entry to the @filldir callback * supplied by the caller. * * Return 0 on success or -1 on error with errno set to the error code. * * Note: Index blocks are parsed in ascending vcn order, from which follows * that the directory entries are not returned sorted. */int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, void *dirent, ntfs_filldir_t filldir){ s64 i_size, br, ia_pos, bmp_pos, ia_start; ntfs_volume *vol; ntfs_attr *ia_na, *bmp_na = NULL; ntfs_attr_search_ctx *ctx = NULL; u8 *index_end, *bmp = NULL; INDEX_ROOT *ir; INDEX_ENTRY *ie; INDEX_ALLOCATION *ia = NULL; int rc, ir_pos, bmp_buf_size, bmp_buf_pos, eo; u32 index_block_size, index_vcn_size; u8 index_block_size_bits, index_vcn_size_bits; ntfs_log_trace("Entering.\n"); if (!dir_ni || !pos || !filldir) { errno = EINVAL; return -1; } if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { errno = ENOTDIR; return -1; } vol = dir_ni->vol; ntfs_log_trace("Entering for inode 0x%llx, *pos 0x%llx.\n", (unsigned long long)dir_ni->mft_no, (long long)*pos); /* Open the index allocation attribute. */ ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); if (!ia_na) { if (errno != ENOENT) { ntfs_log_perror("Failed to open index allocation attribute. " "Directory inode 0x%llx is corrupt or bug", (unsigned long long)dir_ni->mft_no); return -1; } i_size = 0; } else i_size = ia_na->data_size; rc = 0; /* Are we at end of dir yet? */ if (*pos >= i_size + vol->mft_record_size) goto done; /* Emulate . and .. for all directories. */ if (!*pos) { rc = filldir(dirent, dotdot, 1, FILE_NAME_POSIX, *pos, MK_MREF(dir_ni->mft_no, le16_to_cpu(dir_ni->mrec->sequence_number)), NTFS_DT_DIR); if (rc) goto err_out; ++*pos; } if (*pos == 1) { MFT_REF parent_mref; parent_mref = ntfs_mft_get_parent_ref(dir_ni); if (parent_mref == ERR_MREF(-1)) { ntfs_log_perror("Parent directory not found"); goto dir_err_out; } rc = filldir(dirent, dotdot, 2, FILE_NAME_POSIX, *pos, parent_mref, NTFS_DT_DIR); if (rc) goto err_out; ++*pos; } ctx = ntfs_attr_get_search_ctx(dir_ni, NULL); if (!ctx) goto err_out; /* Get the offset into the index root attribute. */ ir_pos = (int)*pos; /* Find the index root attribute in the mft record. */ if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL, 0, ctx)) { ntfs_log_perror("Index root attribute missing in directory inode " "0x%llx", (unsigned long long)dir_ni->mft_no); goto dir_err_out; } /* Get to the index root value. */ ir = (INDEX_ROOT*)((u8*)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); /* Determine the size of a vcn in the directory index. */ index_block_size = le32_to_cpu(ir->index_block_size); if (index_block_size < NTFS_BLOCK_SIZE || index_block_size & (index_block_size - 1)) { ntfs_log_error("Index block size %u is invalid.\n", (unsigned)index_block_size); goto dir_err_out; } index_block_size_bits = ffs(index_block_size) - 1; if (vol->cluster_size <= index_block_size) { index_vcn_size = vol->cluster_size; index_vcn_size_bits = vol->cluster_size_bits; } else { index_vcn_size = vol->sector_size; index_vcn_size_bits = vol->sector_size_bits; } /* Are we jumping straight into the index allocation attribute? */ if (*pos >= vol->mft_record_size) { ntfs_attr_put_search_ctx(ctx); ctx = NULL; goto skip_index_root; } index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); /* The first index entry. */ ie = (INDEX_ENTRY*)((u8*)&ir->index + le32_to_cpu(ir->index.entries_offset)); /* * Loop until we exceed valid memory (corruption case) or until we * reach the last entry or until filldir tells us it has had enough * or signals an error (both covered by the rc test). */ for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { ntfs_log_debug("In index root, offset 0x%x.\n", (u8*)ie - (u8*)ir); /* Bounds checks. */ if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + sizeof(INDEX_ENTRY_HEADER) > index_end || (u8*)ie + le16_to_cpu(ie->key_length) > index_end) goto dir_err_out; /* The last entry cannot contain a name. */ if (ie->ie_flags & INDEX_ENTRY_END) break; /* Skip index root entry if continuing previous readdir. */ if (ir_pos > (u8*)ie - (u8*)ir) continue; /* * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. */ rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -