📄 super.c
字号:
* Example: version 3.1 will be returned as 0x0301. This has the obvious * limitation of not coping with version numbers above 0x80 but that shouldn't * be a problem... */int ntfs_get_version(ntfs_inode* volume){ ntfs_attribute *volinfo; volinfo = ntfs_find_attr(volume, volume->vol->at_volume_information, 0); if (!volinfo) return -EINVAL; if (!volinfo->resident) { ntfs_error("Volume information attribute is not resident!\n"); return -EINVAL; } return ((ntfs_u8*)volinfo->d.data)[8] << 8 | ((ntfs_u8*)volinfo->d.data)[9];}int ntfs_load_special_files(ntfs_volume *vol){ int error; ntfs_inode upcase, attrdef, volume; vol->mft_ino = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode)); vol->mftmirr = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode)); vol->bitmap = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode)); vol->ino_flags = 4 | 2 | 1; error = -ENOMEM; ntfs_debug(DEBUG_BSD, "Going to load MFT\n"); if (!vol->mft_ino || (error = ntfs_init_inode(vol->mft_ino, vol, FILE_Mft))) { ntfs_error("Problem loading MFT\n"); return error; } ntfs_debug(DEBUG_BSD, "Going to load MIRR\n"); if ((error = ntfs_init_inode(vol->mftmirr, vol, FILE_MftMirr))) { ntfs_error("Problem %d loading MFTMirr\n", error); return error; } ntfs_debug(DEBUG_BSD, "Going to load BITMAP\n"); if ((error = ntfs_init_inode(vol->bitmap, vol, FILE_BitMap))) { ntfs_error("Problem loading Bitmap\n"); return error; } ntfs_debug(DEBUG_BSD, "Going to load UPCASE\n"); error = ntfs_init_inode(&upcase, vol, FILE_UpCase); if (error) return error; ntfs_init_upcase(&upcase); ntfs_clear_inode(&upcase); ntfs_debug(DEBUG_BSD, "Going to load ATTRDEF\n"); error = ntfs_init_inode(&attrdef, vol, FILE_AttrDef); if (error) return error; error = ntfs_init_attrdef(&attrdef); ntfs_clear_inode(&attrdef); if (error) return error; /* Check for NTFS version and if Win2k version (ie. 3.0+) do not allow * write access since the driver write support is broken. */ ntfs_debug(DEBUG_BSD, "Going to load VOLUME\n"); error = ntfs_init_inode(&volume, vol, FILE_Volume); if (error) return error; if ((error = ntfs_get_version(&volume)) >= 0x0300 && !(NTFS_SB(vol)->s_flags & MS_RDONLY)) { NTFS_SB(vol)->s_flags |= MS_RDONLY; ntfs_error("Warning! NTFS volume version is Win2k+: Mounting " "read-only\n"); } ntfs_clear_inode(&volume); if (error < 0) return error; ntfs_debug(DEBUG_BSD, "NTFS volume is v%d.%d\n", error >> 8, error & 0xff); return 0;}int ntfs_release_volume(ntfs_volume *vol){ if (((vol->ino_flags & 1) == 1) && vol->mft_ino) { ntfs_clear_inode(vol->mft_ino); ntfs_free(vol->mft_ino); vol->mft_ino = 0; } if (((vol->ino_flags & 2) == 2) && vol->mftmirr) { ntfs_clear_inode(vol->mftmirr); ntfs_free(vol->mftmirr); vol->mftmirr = 0; } if (((vol->ino_flags & 4) == 4) && vol->bitmap) { ntfs_clear_inode(vol->bitmap); ntfs_free(vol->bitmap); vol->bitmap = 0; } ntfs_free(vol->mft); ntfs_free(vol->upcase); return 0;}/* * Writes the volume size (units of clusters) into vol_size. * Returns 0 if successful or error. */int ntfs_get_volumesize(ntfs_volume *vol, ntfs_s64 *vol_size){ ntfs_io io; char *cluster0; if (!vol_size) return -EFAULT; cluster0 = ntfs_malloc(vol->cluster_size); if (!cluster0) return -ENOMEM; io.fn_put = ntfs_put; io.fn_get = ntfs_get; io.param = cluster0; io.do_read = 1; io.size = vol->cluster_size; ntfs_getput_clusters(vol, 0, 0, &io); *vol_size = NTFS_GETU64(cluster0 + 0x28) >> (ffs(NTFS_GETU8(cluster0 + 0xD)) - 1); ntfs_free(cluster0); return 0;}static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0};int ntfs_get_free_cluster_count(ntfs_inode *bitmap){ ntfs_io io; int offset, error, clusters; unsigned char *bits = ntfs_malloc(2048); if (!bits) return -ENOMEM; offset = clusters = 0; io.fn_put = ntfs_put; io.fn_get = ntfs_get; while (1) { register int i; io.param = bits; io.size = 2048; error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, offset, &io); if (error || io.size == 0) break; /* I never thought I would do loop unrolling some day */ for (i = 0; i < io.size - 8; ) { clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF]; } while (i < io.size) { clusters += nc[bits[i] >> 4]; clusters += nc[bits[i++] & 0xF]; } offset += io.size; } ntfs_free(bits); return clusters;}/* * Insert the fixups for the record. The number and location of the fixes * is obtained from the record header but we double check with @rec_size and * use that as the upper boundary, if necessary overwriting the count value in * the record header. * * We return 0 on success or -1 if fixup header indicated the beginning of the * update sequence array to be beyond the valid limit. */int ntfs_insert_fixups(unsigned char *rec, int rec_size){ int first; int count; int offset = -2; ntfs_u16 fix; first = NTFS_GETU16(rec + 4); count = (rec_size >> NTFS_SECTOR_BITS) + 1; if (first + count * 2 > NTFS_SECTOR_SIZE - 2) { printk(KERN_CRIT "NTFS: ntfs_insert_fixups() detected corrupt " "NTFS record update sequence array position. - " "Cannot hotfix.\n"); return -1; } if (count != NTFS_GETU16(rec + 6)) { printk(KERN_ERR "NTFS: ntfs_insert_fixups() detected corrupt " "NTFS record update sequence array size. - " "Applying hotfix.\n"); NTFS_PUTU16(rec + 6, count); } fix = (NTFS_GETU16(rec + first) + 1) & 0xffff; if (fix == 0xffff || !fix) fix = 1; NTFS_PUTU16(rec + first, fix); count--; while (count--) { first += 2; offset += NTFS_SECTOR_SIZE; NTFS_PUTU16(rec + first, NTFS_GETU16(rec + offset)); NTFS_PUTU16(rec + offset, fix); } return 0;}/** * ntfs_allocate_clusters - allocate logical clusters on an ntfs volume * @vol: volume on which to allocate clusters * @location: preferred location for first allocated cluster * @count: number of clusters to allocate * @rl: address of pointer in which to return the allocated run list * @rl_len: the number of elements returned in @*rl * * Allocate @*count clusters (LCNs), preferably beginning at @*location in the * bitmap of the volume @vol. If @*location is -1, it does not matter where the * clusters are. @rl is the address of a ntfs_runlist pointer which this * function will allocate and fill with the runlist of the allocated clusters. * It is the callers responsibility to ntfs_vfree() @*rl after she is finished * with it. If the function was not successful, @*rl will be set to NULL. * @*rl_len will contain the number of ntfs_runlist elements in @*rl or 0 if * @*rl is NULL. * * Return 0 on success, or -errno on error. On success, @*location and @*count * say what was really allocated. On -ENOSPC, @*location and @*count say what * could have been allocated. If nothing could be allocated or a different * error occured, @*location = -1 and @*count = 0. * * There are two data zones. First is the area between the end of the mft zone * and the end of the volume, and second is the area between the start of the * volume and the start of the mft zone. On unmodified/standard volumes, the * second mft zone doesn't exist due to the mft zone being expanded to cover * the start of volume in order to reserve space for the mft bitmap attribute. * * This is not the prettiest function but the complexity stems from the need of * implementing the mft vs data zoned approach and from the fact that we have * access to the lcn bitmap in portions of PAGE_SIZE bytes at a time, so we * need to cope with crossing over boundaries of two pages. Further, the fact * that the allocator allows for caller supplied hints as to the location of * where allocation should begin and the fact that the allocator keeps track of * where in the data zones the next natural allocation should occur, contribute * to the complexity of the function. But it should all be worthwhile, because * this allocator should: 1) be a full implementation of the MFT zone approach * used by Windows, 2) cause reduction in fragmentation as much as possible, * and 3) be speedy in allocations (the code is not optimized for speed, but * the algorithm is, so further speed improvements are probably possible). * * FIXME: Really need finer-grained locking but this will do for the moment. I * just want to kill all races and have a working allocator. When that is done, * we can beautify... (AIA) * * FIXME: We should be monitoring cluster allocation and increment the MFT zone * size dynamically but this is something for the future. We will just cause * heavier fragmentation by not doing it and I am not even sure Windows would * grow the MFT zone dynamically, so might even be correct not doing this. The * overhead in doing dynamic MFT zone expansion would be very large and unlikely * worth the effort. (AIA) * * TODO: I have added in double the required zone position pointer wrap around * logic which can be optimized to having only one of the two logic sets. * However, having the double logic will work fine, but if we have only one of * the sets and we get it wrong somewhere, then we get into trouble, so * removing the duplicate logic requires _very_ careful consideration of _all_ * possible code paths. So at least for now, I am leaving the double logic - * better safe than sorry... (AIA) */int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location, ntfs_cluster_t *count, ntfs_runlist **rl, int *rl_len, const NTFS_CLUSTER_ALLOCATION_ZONES zone){ ntfs_runlist *rl2 = NULL, *rlt; ntfs_attribute *data; ntfs_cluster_t buf_pos, zone_start, zone_end, mft_zone_size; ntfs_cluster_t lcn, last_read_pos, prev_lcn = (ntfs_cluster_t)0; ntfs_cluster_t initial_location, prev_run_len = (ntfs_cluster_t)0; ntfs_cluster_t clusters = (ntfs_cluster_t)0; unsigned char *buf, *byte, bit, search_zone, done_zones; unsigned char pass, need_writeback; int rlpos = 0, rlsize, buf_size, err = 0; ntfs_io io; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Entering with *location = " "0x%x, *count = 0x%x, zone = %s_ZONE.\n", *location, *count, zone == DATA_ZONE ? "DATA" : "MFT"); buf = (char*)__get_free_page(GFP_NOFS); if (!buf) { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Returning " "-ENOMEM.\n"); return -ENOMEM; } io.fn_put = ntfs_put; io.fn_get = ntfs_get; lock_kernel(); /* Get the $DATA attribute of $Bitmap. */ data = ntfs_find_attr(vol->bitmap, vol->at_data, 0); if (!data) { err = -EINVAL; goto err_ret; } /* * If no specific location was requested, use the current data zone * position, otherwise use the requested location but make sure it lies * outside the mft zone. Also set done_zones to 0 (no zones done) and * pass depending on whether we are starting inside a zone (1) or * at the beginning of a zone (2). If requesting from the MFT_ZONE, then * we either start at the current position within the mft zone or at the * specified position and if the latter is out of bounds then we start * at the beginning of the MFT_ZONE. */ done_zones = 0; pass = 1; /* * zone_start and zone_end are the current search range. search_zone * is 1 for mft zone, 2 for data zone 1 (end of mft zone till end of * volume) and 4 for data zone 2 (start of volume till start of mft * zone). */ zone_start = *location; if (zone_start < 0) { if (zone == DATA_ZONE) zone_start = vol->data1_zone_pos; else zone_start = vol->mft_zone_pos; if (!zone_start) /* * Zone starts at beginning of volume which means a * single pass is sufficient. */ pass = 2; } else if (zone_start >= vol->mft_zone_start && zone_start < vol->mft_zone_end && zone == DATA_ZONE) { zone_start = vol->mft_zone_end; pass = 2; } else if ((zone_start < vol->mft_zone_start || zone_start >= vol->mft_zone_end) && zone == MFT_ZONE) { zone_start = vol->mft_lcn; if (!vol->mft_zone_end) zone_start = (ntfs_cluster_t)0; pass = 2; } if (zone == DATA_ZONE) { /* Skip searching the mft zone. */ done_zones |= 1; if (zone_start >= vol->mft_zone_end) { zone_end = vol->nr_clusters; search_zone = 2; } else { zone_end = vol->mft_zone_start;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -