static u32 send_delta_block(int fd,int connfd) { u32 d_len; u64 d_off; u32 size_to_send = DELTA_BLOCK_ENTRY_SZ; delta_block_entry * dblk; list_head * dlst = dblk_link_list_head; if(dlst == NULL){ printf("no delta block to send!\n"); return 0; } while(1){ dblk = containerof(dlst,delta_block_entry,dbe_list); d_len = dblk->len; d_off = dblk->offset; if(dblk->dup_flag == N_DUP_BLOCK){ size_to_send += d_len; } lseek(fd,d_off,SEEK_SET); if(Read(fd,ptr,d_len) != d_len){ fprintf(stderr,"send_delta_block : less bytes read from fd!\n"); return 1; } memcpy(buf,dblk,DELTA_BLOCK_ENTRY_SZ); if(Write(connfd,buf,size_to_send) != size_to_send){ fprintf(stderr,"send_delta_block : less bytes written to socket!\n"); return 2; } if(IS_LAST_ENTRY(dlst)){ break; } dlst = dlst->next; } return 0; }
static int get_max_inline_xattr_value_size(struct inode *inode, struct ext4_iloc *iloc) { struct ext4_xattr_ibody_header *header; struct ext4_xattr_entry *entry; struct ext4_inode *raw_inode; int free, min_offs; min_offs = EXT4_SB(inode->i_sb)->s_inode_size - EXT4_GOOD_OLD_INODE_SIZE - EXT4_I(inode)->i_extra_isize - sizeof(struct ext4_xattr_ibody_header); /* * We need to subtract another sizeof(__u32) since an in-inode xattr * needs an empty 4 bytes to indicate the gap between the xattr entry * and the name/value pair. */ if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) return EXT4_XATTR_SIZE(min_offs - EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)) - EXT4_XATTR_ROUND - sizeof(__u32)); raw_inode = ext4_raw_inode(iloc); header = IHDR(inode, raw_inode); entry = IFIRST(header); /* Compute min_offs. */ for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { if (!entry->e_value_block && entry->e_value_size) { size_t offs = le16_to_cpu(entry->e_value_offs); if (offs < min_offs) min_offs = offs; } } free = min_offs - ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32); if (EXT4_I(inode)->i_inline_off) { entry = (struct ext4_xattr_entry *) ((void *)raw_inode + EXT4_I(inode)->i_inline_off); free += EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)); goto out; } free -= EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)); if (free > EXT4_XATTR_ROUND) free = EXT4_XATTR_SIZE(free - EXT4_XATTR_ROUND); else free = 0; out: return free; }
static int get_max_inline_xattr_value_size(struct inode *inode, struct ext4_iloc *iloc) { struct ext4_xattr_ibody_header *header; struct ext4_xattr_entry *entry; struct ext4_inode *raw_inode; int free, min_offs; if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) return EXT4_XATTR_SIZE(EXT4_SB(inode->i_sb)->s_inode_size - EXT4_GOOD_OLD_INODE_SIZE - EXT4_I(inode)->i_extra_isize - sizeof(struct ext4_xattr_ibody_header) - EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA_NAME)) - EXT4_XATTR_ROUND - sizeof(__u32)); down_read(&EXT4_I(inode)->xattr_sem); raw_inode = ext4_raw_inode(iloc); header = IHDR(inode, raw_inode); entry = IFIRST(header); min_offs = EXT4_SB(inode->i_sb)->s_inode_size - EXT4_GOOD_OLD_INODE_SIZE - EXT4_I(inode)->i_extra_isize - sizeof(struct ext4_xattr_ibody_header); /* Compute min_offs. */ for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { if (!entry->e_value_block && entry->e_value_size) { size_t offs = le16_to_cpu(entry->e_value_offs); if (offs < min_offs) min_offs = offs; } } free = min_offs - ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32); if (EXT4_I(inode)->i_inline_off) { entry = (struct ext4_xattr_entry *) ((void *)raw_inode + EXT4_I(inode)->i_inline_off); free += le32_to_cpu(entry->e_value_size); goto out; } free -= EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA_NAME)); if (free > EXT4_XATTR_ROUND) free = EXT4_XATTR_SIZE(free - EXT4_XATTR_ROUND); else free = 0; out: up_read(&EXT4_I(inode)->xattr_sem); return free; }
static void free_dblk_list(void) { u8 last_dblk = 0; delta_block_entry * dblk; list_head * lst = dblk_link_list_head; if(lst == NULL) return; while(1){ dblk = containerof(lst,delta_block_entry,dbe_list); if(IS_LAST_ENTRY(lst)){ last_dblk = 1; } free(dblk); if(last_dblk == 1){ break; } lst = lst->next; } return; }
int main() { /* rsync variables */ u8 file_name[FILE_NAME_LEN] = {'\0'}; u32 block_sz; u32 i; list_head ** lst_hd; list_head * lh_pre,* lh_next; u32 cblk_hash_v; /* chunk block */ u64 chunk_block_nr; chunk_file_header cfh; reply_to_chunk_file_header rplh; chunk_block_entry * cblk; chunk_block_entry * cblk_array; chunk_block_entry * cblk_p; chunk_block_entry * cblk_current; u64 chunk_block_no; u32 chunk_block_rollin_chksm; u32 chunk_block_len; u8 * chunk_block_md5; u32 brk_v; u32 is_first_entry,is_last_entry; /* searching for dup blocks */ u64 remaining_bytes; u64 delta_region_off; u64 dup_blk_off; u32 dup_blk_len; u32 rolling_chksm; u8 md5[MD5_SZ]; u32 n; u8 * p; u32 akl,bkl,skl; u8 dup_found; u8 oc,nc; /* file to sync */ int fd; struct stat file_stat; u64 file_sz; /* socket variables */ int port; int listenfd,connfd,len; char ip_str[INET_ADDRSTRLEN]; struct sockaddr_in addr,cli_addr; listenfd = socket(AF_INET,SOCK_STREAM,0); bzero(&addr,sizeof(addr)); addr.sin_family = AF_INET; inet_pton(AF_INET,RSYNC_HOST_IP,(void*)&addr.sin_addr); addr.sin_port = htons(RSYNC_SRV_PORT); len = sizeof(addr); bind(listenfd,(struct sockaddr *)&addr,len); listen(listenfd,LISTENQ); len = sizeof(cli_addr); connfd = accept(listenfd,(struct sockaddr *)&cli_addr,&len); bzero(ip_str,INET_ADDRSTRLEN); inet_ntop(AF_INET,(void*)&cli_addr.sin_addr,ip_str,INET_ADDRSTRLEN); port = ntohs(cli_addr.sin_port); printf(" from %s,port %d\n",ip_str,port); if(Read(connfd,&cfh,CHUNK_FILE_HEAD_SZ) != CHUNK_FILE_HEAD_SZ){ perror("read chunk_file_header"); goto over1; } printf("--------- read chunk_blk_header ok -----------\n"); block_sz = cfh.block_sz; chunk_block_nr = cfh.block_nr; strncpy(file_name,cfh.fn,strlen(cfh.fn)); printf("--- block_sz -- # %d\n",block_sz); printf("--- block_nr -- # %d\n",chunk_block_nr); printf("--- file_to_sync -- # %s\n",file_name); rplh.err = E_OK; if((fd = open(file_name,O_RDONLY)) < 0){ perror("open src file"); if(errno == ENOENT){ /* when file not exist,goto send_delta_file_header * need special disposition */ /* tell dst to delete file */ rplh.err = E_SRC_FILE_NOT_EXIST; goto SEND_RPL_TO_CFH; } goto over1; } if(fstat(fd,&file_stat) != 0){ perror("fstat"); goto over2; } file_sz = file_stat.st_size; if(file_sz == 0){ rplh.err = E_SRC_FILE_NO_BLK; } SEND_RPL_TO_CFH: /* send reply to chunk file header */ if(Write(connfd,&rplh,RPL_TO_CHUNK_FILE_HEADER_SZ) != RPL_TO_CHUNK_FILE_HEADER_SZ){ perror("write rpl to chunk file header"); goto over2; } if(rplh.err != E_OK){ goto over2; } /* dst file has 0 block */ if(chunk_block_nr == 0){ /* need special disposition */ printf("dst file has no block!\n"); update_delta_block_list(0,file_sz,0,NULL,block_sz); goto send_delta_file_header; } cblk_array = (chunk_block_entry*)malloc(chunk_block_nr*CHUNK_BLOCK_ENTRY_SZ); if(cblk_array == NULL){ perror("malloc for chunk_block_entry_array"); goto over2; } /* receive chunk block entry */ for(i = 0;i < chunk_block_nr;i++){ cblk_p = cblk_array + i; if(Read(connfd,cblk_p,CHUNK_BLOCK_ENTRY_SZ) != CHUNK_BLOCK_ENTRY_SZ){ perror("read chunk_block_entry"); goto over3; } chunk_block_rollin_chksm = cblk_p->rolling_chksm; chunk_block_len = cblk_p->block_len; chunk_block_md5 = cblk_p->md5; cblk_p->cbe_hash.next = &(cblk_p->cbe_hash); cblk_p->cbe_hash.pre = &(cblk_p->cbe_hash); cblk_hash_v = ROLLING_CHECKSUM_HASH(cblk_p->rolling_chksm); lst_hd = &chunk_blk_entry_hash[cblk_hash_v]; if(*lst_hd == NULL){ *lst_hd = &(cblk_p->cbe_hash); continue; } while(1){ brk_v = 0; cblk_current = containerof(*lst_hd,chunk_block_entry,cbe_hash); if(cblk_current->block_len == chunk_block_len && \ ROLLING_CHKSM_EQUAL(cblk_current->rolling_chksm,chunk_block_rollin_chksm)){ if(MD5_EQUAL(cblk_current->md5,chunk_block_md5)){ printf("skip identical chunk_block_entry\n"); brk_v = 1; break; } } if(cblk_current->rolling_chksm > chunk_block_rollin_chksm){ /* insert into the place before cblk_current */ brk_v = 2; break; } if(IS_LAST_ENTRY(*lst_hd)){ /* insert to tail */ brk_v = 3; break; } lst_hd = &((*lst_hd)->next); } switch(brk_v){ case 1: break; case 2: is_first_entry = 0; if(IS_FIRST_ENTRY(*lst_hd)){ is_first_entry = 1; }else{ lh_pre = (*lst_hd)->pre; } (*lst_hd)->pre = &(cblk_p->cbe_hash); cblk_p->cbe_hash.next = *lst_hd; if(is_first_entry == 1){ chunk_blk_entry_hash[cblk_hash_v] = &(cblk_p->cbe_hash); }else{ lh_pre->next = &(cblk_p->cbe_hash); cblk_p->cbe_hash.pre = lh_pre; } break; case 3: (*lst_hd)->next = &(cblk_p->cbe_hash); cblk_p->cbe_hash.pre = *lst_hd; break; default: break; } } printf("%d chunk block entrys received!\n",i); /* all chunk_block_entryS have been received * Now find the duplicate block from the src file */ dup_blk_off = 0; dup_blk_len = block_sz; delta_region_off = 0; /* initialize buffer */ buf_init(fd,file_sz); dup_found = DUP_FOUND; /* find duplicate block * and generate the list of delta_block */ while(dup_blk_off < file_sz){ n = 0; p = read_from_buf(dup_blk_off,dup_blk_len,&n); if(p == NULL){ fprintf(stderr,"some errors happened when read_from_buf\n"); goto over3; } /* else p is the pointer of the block * which is going to be checked * and the number of bytes is 'n' */ if(dup_found == DUP_FOUND){ /* start a new search or * current block is the last block of src_file */ printf("calculate the rolling_checksum with cal_rollin_cksm \n"); akl = 0,bkl = 0,skl = 0; skl = cal_rollin_cksm(p,&akl,&bkl,n); }else if(dup_found == DUP_NOT_FOUND){ /* the only case that rolling_checksum is calculated with last value */ printf("calculate the rolling_checksum with cal_rollin_cksm_plus_1 \n"); oc = *(p - 1); nc = (n < dup_blk_len?0:(*(p + n - 1))); skl = cal_rollin_cksm_plus_1(oc,nc,&akl,&bkl,dup_blk_len); } dup_found = DUP_NOT_FOUND; rolling_chksm = skl; cblk_hash_v = ROLLING_CHECKSUM_HASH(rolling_chksm); lst_hd = &(chunk_blk_entry_hash[cblk_hash_v]); /* searching */ if(*lst_hd == NULL){ /* no match, * right shift one byte and continue */ goto MODIFY_SOME_VAR_AND_GOTO_NEXT_LOOP; } while(1){ cblk_current = containerof(*lst_hd,chunk_block_entry,cbe_hash); if(cblk_current->block_len == n && \ ROLLING_CHKSM_EQUAL(cblk_current->rolling_chksm,rolling_chksm)){ /* same block_len and rolling_chksm, * need further checking md5 */ cal_md5(p,n,md5); if(MD5_EQUAL(cblk_current->md5,md5)){ dup_found = DUP_FOUND; break; } } if(cblk_current->rolling_chksm > rolling_chksm){ /* because collided chunk_blk_entry are sorted * no need to search further here */ break; } if(IS_LAST_ENTRY(*lst_hd)){ /* the last entry */ break; } lst_hd = &((*lst_hd)->next); } MODIFY_SOME_VAR_AND_GOTO_NEXT_LOOP: if(dup_found == DUP_FOUND){ /* dup_block found, * 1) make delta_block_entry list, * 2) reset : delta_region_off * delta_region_len * dup_blk_off * mention that dup_blk_off should be right shifted 'n' bytes */ update_delta_block_list(delta_region_off,dup_blk_off,n,cblk_current,dup_blk_len); dup_blk_off += n; delta_region_off = dup_blk_off; }else if(dup_found == DUP_NOT_FOUND){ /* dup_block not found, right shift one byte and continue */ dup_blk_off++; } } printf("finding dup_block over,delta_block_entry has been in the list!\n"); /* sending delta_file_header */ send_delta_file_header: dfh.block_nr = delta_block_nr; if(Write(connfd,&dfh,DELTA_FILE_HEADER_SZ) != DELTA_FILE_HEADER_SZ){ fprintf(stderr,"write delta_file_header fail!\n"); goto over3; } if(send_delta_block(fd,connfd) != 0){ fprintf(stderr,"some errors happened when sending delta_block!\n"); } over3: if(chunk_block_nr == 0){ goto over2; } free(cblk_array); over2: close(fd); over1: close(connfd); return 0; }