📄 utils.c
字号:
len = snprintf(buffer + offset, bufsize - offset, "%c%s", PATH_SEP, names[i]); if (len >= (bufsize - offset)) { ntfs_log_error("Pathname was truncated.\n"); break; } offset += len; } /* Free all the allocated memory */ for (i = 0; i < max_path; i++) free(names[i]); ntfs_log_debug("Pathname: %s\n", buffer); return 1;}/** * utils_attr_get_name */int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int bufsize){ int len, namelen; char *name; ATTR_DEF *attrdef; // flags: attr, name, or both if (!attr || !buffer) { errno = EINVAL; return 0; } attrdef = ntfs_attr_find_in_attrdef(vol, attr->type); if (attrdef) { name = NULL; namelen = ntfs_ucsnlen(attrdef->name, sizeof(attrdef->name)); if (ntfs_ucstombs(attrdef->name, namelen, &name, 0) < 0) { ntfs_log_error("Couldn't translate attribute type to current locale.\n"); // <UNKNOWN>? return 0; } len = snprintf(buffer, bufsize, "%s", name); } else { ntfs_log_error("Unknown attribute type 0x%02x\n", attr->type); len = snprintf(buffer, bufsize, "<UNKNOWN>"); } if (len >= bufsize) { ntfs_log_error("Attribute type was truncated.\n"); return 0; } if (!attr->name_length) { return 0; } buffer += len; bufsize -= len; name = NULL; namelen = attr->name_length; if (ntfs_ucstombs((ntfschar *)((char *)attr + attr->name_offset), namelen, &name, 0) < 0) { ntfs_log_error("Couldn't translate attribute name to current locale.\n"); // <UNKNOWN>? len = snprintf(buffer, bufsize, "<UNKNOWN>"); return 0; } len = snprintf(buffer, bufsize, "(%s)", name); free(name); if (len >= bufsize) { ntfs_log_error("Attribute name was truncated.\n"); return 0; } return 0;}/** * utils_cluster_in_use - Determine if a cluster is in use * @vol: An ntfs volume obtained from ntfs_mount * @lcn: The Logical Cluster Number to test * * The metadata file $Bitmap has one binary bit representing each cluster on * disk. The bit will be set for each cluster that is in use. The function * reads the relevant part of $Bitmap into a buffer and tests the bit. * * This function has a static buffer in which it caches a section of $Bitmap. * If the lcn, being tested, lies outside the range, the buffer will be * refreshed. * * Return: 1 Cluster is in use * 0 Cluster is free space * -1 Error occurred */int utils_cluster_in_use(ntfs_volume *vol, long long lcn){ static unsigned char buffer[512]; static long long bmplcn = -sizeof(buffer) - 1; /* Which bit of $Bitmap is in the buffer */ int byte, bit; ntfs_attr *attr; if (!vol) { errno = EINVAL; return -1; } /* Does lcn lie in the section of $Bitmap we already have cached? */ if ((lcn < bmplcn) || (lcn >= (bmplcn + (sizeof(buffer) << 3)))) { ntfs_log_debug("Bit lies outside cache.\n"); attr = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0); if (!attr) { ntfs_log_perror("Couldn't open $Bitmap"); return -1; } /* Mark the buffer as in use, in case the read is shorter. */ memset(buffer, 0xFF, sizeof(buffer)); bmplcn = lcn & (~((sizeof(buffer) << 3) - 1)); if (ntfs_attr_pread(attr, (bmplcn>>3), sizeof(buffer), buffer) < 0) { ntfs_log_perror("Couldn't read $Bitmap"); ntfs_attr_close(attr); return -1; } ntfs_log_debug("Reloaded bitmap buffer.\n"); ntfs_attr_close(attr); } bit = 1 << (lcn & 7); byte = (lcn >> 3) & (sizeof(buffer) - 1); ntfs_log_debug("cluster = %lld, bmplcn = %lld, byte = %d, bit = %d, in use %d\n", lcn, bmplcn, byte, bit, buffer[byte] & bit); return (buffer[byte] & bit);}/** * utils_mftrec_in_use - Determine if a MFT Record is in use * @vol: An ntfs volume obtained from ntfs_mount * @mref: MFT Reference (inode number) * * The metadata file $BITMAP has one binary bit representing each record in the * MFT. The bit will be set for each record that is in use. The function * reads the relevant part of $BITMAP into a buffer and tests the bit. * * This function has a static buffer in which it caches a section of $BITMAP. * If the mref, being tested, lies outside the range, the buffer will be * refreshed. * * Return: 1 MFT Record is in use * 0 MFT Record is unused * -1 Error occurred */int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref){ static u8 buffer[512]; static s64 bmpmref = -sizeof(buffer) - 1; /* Which bit of $BITMAP is in the buffer */ int byte, bit; if (!vol) { errno = EINVAL; return -1; } ntfs_log_trace("entering\n"); /* Does mref lie in the section of $Bitmap we already have cached? */ if (((s64)MREF(mref) < bmpmref) || ((s64)MREF(mref) >= (bmpmref + (sizeof(buffer) << 3)))) { ntfs_log_debug("Bit lies outside cache.\n"); /* Mark the buffer as not in use, in case the read is shorter. */ memset(buffer, 0, sizeof(buffer)); bmpmref = mref & (~((sizeof(buffer) << 3) - 1)); if (ntfs_attr_pread(vol->mftbmp_na, (bmpmref>>3), sizeof(buffer), buffer) < 0) { ntfs_log_perror("Couldn't read $MFT/$BITMAP"); return -1; } ntfs_log_debug("Reloaded bitmap buffer.\n"); } bit = 1 << (mref & 7); byte = (mref >> 3) & (sizeof(buffer) - 1); ntfs_log_debug("cluster = %lld, bmpmref = %lld, byte = %d, bit = %d, in use %d\n", mref, bmpmref, byte, bit, buffer[byte] & bit); return (buffer[byte] & bit);}/** * __metadata */static int __metadata(ntfs_volume *vol, u64 num){ if (num <= FILE_UpCase) return 1; if (!vol) return -1; if ((vol->major_ver == 3) && (num == FILE_Extend)) return 1; return 0;}/** * utils_is_metadata - Determine if an inode represents a metadata file * @inode: An ntfs inode to be tested * * A handful of files in the volume contain filesystem data - metadata. * They can be identified by their inode number (offset in MFT/$DATA) or by * their parent. * * Return: 1 inode is a metadata file * 0 inode is not a metadata file * -1 Error occurred */int utils_is_metadata(ntfs_inode *inode){ ntfs_volume *vol; ATTR_RECORD *rec; FILE_NAME_ATTR *attr; MFT_RECORD *file; u64 num; if (!inode) { errno = EINVAL; return -1; } vol = inode->vol; if (!vol) return -1; num = inode->mft_no; if (__metadata(vol, num) == 1) return 1; file = inode->mrec; if (file && (file->base_mft_record != 0)) { num = MREF(file->base_mft_record); if (__metadata(vol, num) == 1) return 1; } file = inode->mrec; rec = find_first_attribute(AT_FILE_NAME, inode->mrec); if (!rec) return -1; /* We know this will always be resident. */ attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->value_offset)); num = MREF(attr->parent_directory); if ((num != FILE_root) && (__metadata(vol, num) == 1)) return 1; return 0;}/** * utils_dump_mem - Display a block of memory in hex and ascii * @buf: Buffer to be displayed * @start: Offset into @buf to start from * @length: Number of bytes to display * @flags: Options to change the style of the output * * Display a block of memory in a tradition hex-dump manner. * Optionally the ascii part can be turned off. * * The flags, described fully in utils.h, default to 0 (DM_DEFAULTS). * Examples are: DM_INDENT (indent the output by one tab); DM_RED (colour the * output); DM_NO_ASCII (only print the hex values). */void utils_dump_mem(void *buf, int start, int length, int flags){ int off, i, s, e, col; u8 *mem = buf; s = start & ~15; // round down e = (start + length + 15) & ~15; // round up for (off = s; off < e; off += 16) { col = 30; if (flags & DM_RED) col += 1; if (flags & DM_GREEN) col += 2; if (flags & DM_BLUE) col += 4; if (flags & DM_INDENT) ntfs_log_debug("\t"); if (flags & DM_BOLD) ntfs_log_debug("\e[01m"); if (flags & (DM_RED | DM_BLUE | DM_GREEN | DM_BOLD)) ntfs_log_debug("\e[%dm", col); if (off == s) ntfs_log_debug("%6.6x ", start); else ntfs_log_debug("%6.6x ", off); for (i = 0; i < 16; i++) { if ((i == 8) && (!(flags & DM_NO_DIVIDER))) ntfs_log_debug(" -"); if (((off+i) >= start) && ((off+i) < (start+length))) ntfs_log_debug(" %02X", mem[off+i]); else ntfs_log_debug(" "); } if (!(flags & DM_NO_ASCII)) { ntfs_log_debug(" "); for (i = 0; i < 16; i++) { if (((off+i) < start) || ((off+i) >= (start+length))) ntfs_log_debug(" "); else if (isprint(mem[off + i])) ntfs_log_debug("%c", mem[off + i]); else ntfs_log_debug("."); } } if (flags & (DM_RED | DM_BLUE | DM_GREEN | DM_BOLD)) ntfs_log_debug("\e[0m"); ntfs_log_debug("\n"); }}/** * mft_get_search_ctx */struct mft_search_ctx * mft_get_search_ctx(ntfs_volume *vol){ struct mft_search_ctx *ctx; if (!vol) { errno = EINVAL; return NULL; } ctx = calloc(1, sizeof *ctx); ctx->mft_num = -1; ctx->vol = vol; return ctx;}/** * mft_put_search_ctx */void mft_put_search_ctx(struct mft_search_ctx *ctx){ if (!ctx) return; if (ctx->inode) ntfs_inode_close(ctx->inode); free(ctx);}/** * mft_next_record */int mft_next_record(struct mft_search_ctx *ctx){ s64 nr_mft_records; ATTR_RECORD *attr10 = NULL; ATTR_RECORD *attr20 = NULL; ATTR_RECORD *attr80 = NULL; ntfs_attr_search_ctx *attr_ctx; if (!ctx) { errno = EINVAL; return -1; } if (ctx->inode) { ntfs_inode_close(ctx->inode); ctx->inode = NULL; } nr_mft_records = ctx->vol->mft_na->initialized_size >> ctx->vol->mft_record_size_bits; for (ctx->mft_num++; (s64)ctx->mft_num < nr_mft_records; ctx->mft_num++) { int in_use; ctx->flags_match = 0; in_use = utils_mftrec_in_use(ctx->vol, (MFT_REF) ctx->mft_num); if (in_use == -1) { ntfs_log_error("Error reading inode %llu. Aborting.\n", (unsigned long long)ctx->mft_num); return -1; } if (in_use) { ctx->flags_match |= FEMR_IN_USE; ctx->inode = ntfs_inode_open(ctx->vol, (MFT_REF) ctx->mft_num); if (ctx->inode == NULL) { ntfs_log_error("Error reading inode %llu.\n", (unsigned long long) ctx->mft_num); continue; } attr10 = find_first_attribute(AT_STANDARD_INFORMATION, ctx->inode->mrec); attr20 = find_first_attribute(AT_ATTRIBUTE_LIST, ctx->inode->mrec); attr80 = find_first_attribute(AT_DATA, ctx->inode->mrec); if (attr10) ctx->flags_match |= FEMR_BASE_RECORD; else ctx->flags_match |= FEMR_NOT_BASE_RECORD; if (attr20) ctx->flags_match |= FEMR_BASE_RECORD; if (attr80) ctx->flags_match |= FEMR_FILE; if (ctx->flags_search & FEMR_DIR) { attr_ctx = ntfs_attr_get_search_ctx(ctx->inode, NULL); if (attr_ctx) { if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, 0, 0, NULL, 0, attr_ctx) == 0) ctx->flags_match |= FEMR_DIR; ntfs_attr_put_search_ctx(attr_ctx); } else { ntfs_log_error("Couldn't create a search context.\n"); return -1; } } switch (utils_is_metadata(ctx->inode)) { case 1: ctx->flags_match |= FEMR_METADATA; break; case 0: ctx->flags_match |= FEMR_NOT_METADATA; break; default: ctx->flags_match |= FEMR_NOT_METADATA; break; //ntfs_log_error("Error reading inode %lld.\n", ctx->mft_num); //return -1; } } else { // !in_use ntfs_attr *mft; ctx->flags_match |= FEMR_NOT_IN_USE; ctx->inode = calloc(1, sizeof(*ctx->inode)); if (!ctx->inode) { ntfs_log_error("Out of memory. Aborting.\n"); return -1; } ctx->inode->mft_no = ctx->mft_num; ctx->inode->vol = ctx->vol; ctx->inode->mrec = ntfs_malloc(ctx->vol->mft_record_size); if (!ctx->inode->mrec) { free(ctx->inode); // == ntfs_inode_close return -1; } mft = ntfs_attr_open(ctx->vol->mft_ni, AT_DATA, AT_UNNAMED, 0); if (!mft) { ntfs_log_perror("Couldn't open $MFT/$DATA"); // free / close return -1; } if (ntfs_attr_pread(mft, ctx->vol->mft_record_size * ctx->mft_num, ctx->vol->mft_record_size, ctx->inode->mrec) < ctx->vol->mft_record_size) { ntfs_log_perror("Couldn't read MFT Record %llu", (unsigned long long) ctx->mft_num); // free / close ntfs_attr_close(mft); return -1; } ntfs_attr_close(mft); } if (ctx->flags_match & ctx->flags_search) { break; } if (ntfs_inode_close(ctx->inode)) { ntfs_log_error("Error closing inode %llu.\n", (unsigned long long)ctx->mft_num); return -errno; } ctx->inode = NULL; } return (ctx->inode == NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -