예제 #1
0
파일: ioctl.go 프로젝트: plar/btrfs
func findUpdatedFiles(dir *C.DIR, rootId, oldestGen uint64) (uint64, error) {
	var maxFound uint64 = 0

	var args C.struct_btrfs_ioctl_search_args
	var sk *C.struct_btrfs_ioctl_search_key = &args.key
	var sh C.struct_btrfs_ioctl_search_header
	var item *BtrfsFileExtentItem
	var backup BtrfsFileExtentItem

	var foundGen uint64 = 0

	sk.tree_id = C.__u64(rootId)
	sk.max_objectid = math.MaxUint64
	sk.max_offset = math.MaxUint64
	sk.max_transid = math.MaxUint64
	sk.max_type = C.BTRFS_EXTENT_DATA_KEY
	sk.min_transid = C.__u64(oldestGen)
	sk.nr_items = 4096

	fd := getDirFd(dir)

	maxFound, err := findRootGen(dir)
	if err != nil {
		return 0, err
	}

	for {
		_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BTRFS_IOC_TREE_SEARCH, uintptr(unsafe.Pointer(&args)))
		if errno != 0 {
			return 0, fmt.Errorf("Failed to perform the search %v", errno.Error())
		}

		if sk.nr_items == 0 {
			break
		}

		var off uintptr = 0

		for i := uint32(0); i < uint32(sk.nr_items); i++ {
			C.memcpy(unsafe.Pointer(&sh), addptr(unsafe.Pointer(&args.buf), off), C.sizeof_struct_btrfs_ioctl_search_header)
			off += C.sizeof_struct_btrfs_ioctl_search_header

			if sh.len == 0 {
				item = &backup
			} else {
				rawItem := (*C.struct_btrfs_file_extent_item)(addptr(unsafe.Pointer(&args.buf), off))
				item, err = NewBtrfsFileExtentItem(rawItem)
				if err != nil {
					return 0, err
				}
			}

			foundGen = item.Generation
			if sh._type == C.BTRFS_EXTENT_DATA_KEY && foundGen >= uint64(oldestGen) {
				// print...
			}

			off += uintptr(sh.len)

			sk.min_objectid = sh.objectid
			sk.min_offset = sh.offset
			sk.min_type = sh._type
		}

		sk.nr_items = 4096
		if sk.min_offset < math.MaxUint64 {
			sk.min_offset++
		} else if sk.min_objectid < math.MaxUint64 {
			sk.min_objectid++
			sk.min_offset = 0
			sk.min_type = 0

		} else {
			break
		}
	}

	return maxFound, nil
}