static int check_files(struct mystruct *find, struct file *newfile, struct stat *info, const char *ext, unsigned int maxlinks) { int found=0; FILE *nfp=NULL; FILE *ofp=NULL; struct file *f=NULL; //printf(" same size: %s, %s\n", find->files->path, newfile->path); for(f=find->files; f; f=f->next) { if(!f->path) { // If the full_match() function fails to open oldfile // (which could happen if burp deleted some old // directories), it will free path and set it to NULL. // Skip entries like this. continue; } if(newfile->dev!=f->dev) { // Different device. continue; } if(newfile->ino==f->ino) { // Same device, same inode, therefore these two files // are hardlinked to each other already. found++; break; } if((!newfile->part_cksum && get_part_cksum(newfile, &nfp)) || (!f->part_cksum && get_part_cksum(f, &ofp))) { // Some error with md5sums Give up. return -1; } if(newfile->part_cksum!=f->part_cksum) { close_fp(&ofp); continue; } //printf(" %s, %s\n", find->files->path, newfile->path); //printf(" part cksum matched\n"); if((!newfile->full_cksum && get_full_cksum(newfile, &nfp)) || (!f->full_cksum && get_full_cksum(f, &ofp))) { // Some error with md5sums Give up. return -1; } if(newfile->full_cksum!=f->full_cksum) { close_fp(&ofp); continue; } //printf(" full cksum matched\n"); if(!full_match(newfile, f, &nfp, &ofp)) { close_fp(&ofp); continue; } //printf(" full match\n"); //printf("%s, %s\n", find->files->path, newfile->path); // If there are already enough links to this file, replace // our memory of it with the new file so that files later on // can link to the new one. if(f->nlink>=maxlinks) { // Just need to reset the path name and the number // of links, and pretend that it was found otherwise // NULL newfile will get added to the memory. reset_old_file(f, newfile, info); found++; break; } found++; count++; if(verbose) printf("%s\n", newfile->path); // Now hardlink it. if(makelinks) { switch(do_hardlink(newfile, f, ext)) { case 0: f->nlink++; // Only count bytes as saved if we // removed the last link. if(newfile->nlink==1) savedbytes+=info->st_size; break; case -1: // On error, replace the memory of the // old file with the one that we just // found. It might work better when // someone later tries to link to the // new one instead of the old one. reset_old_file(f, newfile, info); count--; break; default: // Abandon all hope. // This could happen if renaming the // hardlink failed in such a way that // the target file was unlinked without // being replaced - ie, if the max // number of hardlinks is being hit. return -1; } } else if(deletedups) { if(unlink(newfile->path)) { logp("Could not delete %s: %s\n", newfile->path, strerror(errno)); } else { // Only count bytes as saved if we removed the // last link. if(newfile->nlink==1) savedbytes+=info->st_size; } } else { // To be able to tell how many bytes // are saveable. savedbytes+=info->st_size; } break; } close_fp(&nfp); close_fp(&ofp); if(found) { free_w(&newfile->path); return 0; } if(add_file(find, newfile)) return -1; return 0; }
static int maildir_copy_hardlink(struct mail_save_context *ctx, struct mail *mail) { struct maildir_mailbox *dest_mbox = (struct maildir_mailbox *)ctx->transaction->box; struct maildir_mailbox *src_mbox; struct maildir_filename *mf; struct hardlink_ctx do_ctx; const char *path, *guid, *dest_fname; uoff_t vsize, size; enum mail_lookup_abort old_abort; if (strcmp(mail->box->storage->name, MAILDIR_STORAGE_NAME) == 0) src_mbox = (struct maildir_mailbox *)mail->box; else if (strcmp(mail->box->storage->name, "raw") == 0) { /* lda uses raw format */ src_mbox = NULL; } else { /* Can't hard link files from the source storage */ return 0; } /* hard link to tmp/ with a newly generated filename and later when we have uidlist locked, move it to new/cur. */ dest_fname = maildir_filename_generate(); memset(&do_ctx, 0, sizeof(do_ctx)); do_ctx.dest_path = t_strdup_printf("%s/tmp/%s", mailbox_get_path(&dest_mbox->box), dest_fname); if (src_mbox != NULL) { /* maildir */ if (maildir_file_do(src_mbox, mail->uid, do_hardlink, &do_ctx) < 0) return -1; } else { /* raw / lda */ if (mail_get_special(mail, MAIL_FETCH_UIDL_FILE_NAME, &path) < 0 || *path == '\0') return 0; if (do_hardlink(dest_mbox, path, &do_ctx) < 0) return -1; } if (!do_ctx.success) { /* couldn't copy with hardlinking, fallback to copying */ return 0; } /* hardlinked to tmp/, treat as normal copied mail */ mf = maildir_save_add(ctx, dest_fname, mail); if (mail_get_special(mail, MAIL_FETCH_GUID, &guid) == 0) { if (*guid != '\0') maildir_save_set_dest_basename(ctx, mf, guid); } /* remember size/vsize if possible */ old_abort = mail->lookup_abort; mail->lookup_abort = MAIL_LOOKUP_ABORT_READ_MAIL; if (mail_get_physical_size(mail, &size) < 0) size = (uoff_t)-1; if (mail_get_virtual_size(mail, &vsize) < 0) vsize = (uoff_t)-1; maildir_save_set_sizes(mf, size, vsize); mail->lookup_abort = old_abort; return 1; }
void addPath(const char *path, int squash_uids, int squash_perms) { size_t len; char *full_name = NULL, *lnk = NULL; struct dirent *file = NULL; DIR *direc = NULL; struct stat st; int overWrite; __u16 inodeType; direc = opendir(path); if ( !direc ) log_error("[Local fs opendir] Cannot open directory %s", path); while (( file = readdir(direc)) != NULL ) { if (( !strcmp(file->d_name, "." )) || ( !strcmp(file->d_name, ".." ))) continue; len = strlen(path) + strlen( file->d_name ) + 3; if ( full_name ) { free( full_name ); full_name = NULL; } full_name = (char*)malloc(len + 2); if ( !full_name ) log_error("[Local fs stat] Memory allocation error ( full_name --> %s/%s )", path, file->d_name); memset(full_name, 0, len + 2); snprintf(full_name, len, "%s/%s", path, file->d_name); lstat(full_name, &st); mode_t fmt = st.st_mode & S_IFMT; if ( squash_uids ) st.st_uid = st.st_gid = 0; if ( squash_perms ) st.st_mode &= ~( LINUX_S_IRWXG | LINUX_S_IRWXO ); overWrite = name_to_inode( file->d_name ); if ( st.st_nlink > 1 ) { if (( lnk = linklist_add(st.st_dev, st.st_ino, full_name + modPath_path_len))) { if ( overWrite ) { log_action(ACT_RM, file->d_name, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !do_rm(file->d_name)) log_error("[Filesystem error] cannot rm %s/%s", log_cwd(), file->d_name); } log_action(ACT_HARDLINK, file->d_name, lnk, 0, 0, 0, 0, 0, 0, overWrite); if (!do_hardlink(&st, lnk, file->d_name)) log_error("[Filesystem error] cannot hardlink %s --> %s", file->d_name, lnk); continue; } } if ( overWrite ) inodeType = inode_mode( file->d_name ); if (( fmt == S_IFDIR ) && ( overWrite ) && ( !LINUX_S_ISDIR(inodeType))) log_error("[Remote fs mismatch] %s/%s exists but isn't a directory when it should be.", log_cwd(), file->d_name); else if (( fmt != S_IFDIR) && ( overWrite )) { if ( LINUX_S_ISDIR(inodeType)) log_error("[Remote fs mismatch] %s/%s exists but is a directory when it shouldn't be.", log_cwd(), file->d_name); if ((!LINUX_S_ISREG(inodeType)) && (!LINUX_S_ISLNK(inodeType)) && (!LINUX_S_ISBLK(inodeType)) && (!LINUX_S_ISCHR(inodeType)) && (!LINUX_S_ISFIFO(inodeType)) && (!LINUX_S_ISSOCK(inodeType))) log_error("[Remote fs mismatch] Existing file %s/%s has unknown/unsupported type [0x%x].", log_cwd(), file->d_name); } switch ( fmt ) { case S_IFDIR: // Directory log_action(ACT_MKDIR, file->d_name, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !overWrite ) if ( !do_mkdir( &st, file->d_name )) log_error("[Filesystem error] cannot mkdir %s/%s", log_cwd(), file->d_name); log_action(ACT_CHMODE, file->d_name, NULL, st.st_mode, 0, 0, 0, 0, 0, overWrite); if ( !do_chmode(file->d_name, st.st_mode)) log_error("[Filesystem error] Failed to chmode 0x%x for directory %s/%s", st.st_mode, log_cwd(), file->d_name); log_action(ACT_CHOWN, file->d_name, NULL, 0, st.st_uid, st.st_gid, 0, 0, 0, 0); if ( !do_chown(file->d_name, st.st_uid, st.st_gid)) log_error("[Filesystem error] Failed to chown %ld, %ld for directory %s/%s", st.st_uid, st.st_gid, log_cwd(), file->d_name); log_action(ACT_CHDIR, file->d_name, NULL, 0, 0, 0, 0, 0, 0, 0); if ( !do_chdir( file->d_name )) log_error("[Filesystem error] cannot chdir to newly created %s/%s", log_cwd(), file->d_name); addPath(full_name, squash_uids, squash_perms); log_action(ACT_CHDIR, "..", NULL, 0, 0, 0, 0, 0, 0, 0); if ( !do_chdir("..")) log_error("[Filesystem error] cannot chdir to parent directory"); break; case S_IFREG: // Regular file if ( overWrite ) { log_action(ACT_RM, file->d_name, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !do_rm(file->d_name)) log_error("[Filesystem error] cannot rm %s/%s", log_cwd(), file->d_name); } log_action(ACT_WRITE, file->d_name, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !do_write(full_name, file->d_name)) log_error("[Filesystem error] cannot write %s/%s", log_cwd(), file->d_name); break; case S_IFLNK: // Symbolic link lnk = (char*)malloc(MAX_PATHSIZE + 2); if ( !lnk ) log_error("[symlink] Memory allocation error (lnk)"); int len = readlink(full_name, lnk, MAX_PATHSIZE); if ( len == -1 ) { free(lnk); log_error("[Local filesystem error] Cannot read destination for link %s/%s", log_cwd(), file->d_name); } else lnk[len] = '\0'; if ( overWrite ) { log_action(ACT_RM, file->d_name, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !do_rm(file->d_name)) log_error("[Filesystem error] cannot rm %s/%s", log_cwd(), file->d_name); } log_action(ACT_SYMLINK, file->d_name, lnk, 0, 0, 0, 0, 0, 0, overWrite); if ( !do_symlink(&st, lnk, file->d_name)) log_error("[Filesystem error] cannot symlink %s/%s --> %s", log_cwd(), file->d_name, lnk); free(lnk); break; case S_IFBLK: // Block device node case S_IFCHR: // Character device node case S_IFSOCK: // socket case S_IFIFO: // fifo if ( overWrite ) { log_action(ACT_RM, file->d_name, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !do_rm(file->d_name)) log_error("[Filesystem error] cannot rm %s/%s", log_cwd(), file->d_name); } char nodetype = ( fmt == S_IFBLK ? 'b' : ( fmt == S_IFCHR ? 'c' : ( fmt == S_IFSOCK ? 's' : 'p' ))); unsigned long major = 0, minor = 0; if (( nodetype == 'b' ) || ( nodetype == 'c' )) { major = (long)major(st.st_rdev); minor = (long)minor(st.st_rdev); } log_action(ACT_MKNOD, file->d_name, NULL, 0, 0, 0, nodetype, major, minor, overWrite); if ( !do_mknod(file->d_name, nodetype, major, minor)) log_error("[Filesystem error] cannot mknod %c %ld,%ld %s/%s", log_cwd(), nodetype, major, minor, log_cwd(), file->d_name); break; } if ( fmt != S_IFDIR ) { // Not dir ? log_action(ACT_CHMODE, file->d_name, NULL, st.st_mode, 0, 0, 0, 0, 0, overWrite); if ( !do_chmode(file->d_name, st.st_mode)) log_error("[Filesystem error] Failed to chmode 0x%x for file %s/%s", st.st_mode, log_cwd(), file->d_name); log_action(ACT_CHOWN, file->d_name, NULL, 0, st.st_uid, st.st_gid, 0, 0, 0, 0); if ( !do_chown(file->d_name, st.st_uid, st.st_gid)) log_error("[Filesystem error] Failed to chown %ld, %ld for file %s/%s", st.st_uid, st.st_gid, log_cwd(), file->d_name); } if ( full_name ) { free( full_name ); full_name = NULL; } } closedir(direc); }
static int check_files(struct mystruct *find, struct file *newfile, struct stat *info, const char *ext, unsigned int maxlinks) { int found=0; FILE *nfp=NULL; FILE *ofp=NULL; struct file *f=NULL; //printf(" same size: %s, %s\n", find->files->path, newfile->path); for(f=find->files; f; f=f->next) { if(!f->path) { // If the full_match() function fails to open oldfile // (which could happen if burp deleted some old // directories), it will free path and set it to NULL. // Skip entries like this. continue; } if(newfile->dev!=f->dev) { // Different device. continue; } if(newfile->ino==f->ino) { // Same device, same inode, therefore these two files // are hardlinked to each other already. found++; break; } if((!newfile->part_cksum && get_part_cksum(newfile, &nfp)) || (!f->part_cksum && get_part_cksum(f, &ofp))) { // Some error with md5sums Give up. return -1; } if(newfile->part_cksum!=f->part_cksum) { if(ofp) { fclose(ofp); ofp=NULL; } continue; } //printf(" %s, %s\n", find->files->path, newfile->path); //printf(" part cksum matched\n"); if((!newfile->full_cksum && get_full_cksum(newfile, &nfp)) || (!f->full_cksum && get_full_cksum(f, &ofp))) { // Some error with md5sums Give up. return -1; } if(newfile->full_cksum!=f->full_cksum) { if(ofp) { fclose(ofp); ofp=NULL; } continue; } //printf(" full cksum matched\n"); if(!full_match(newfile, f, &nfp, &ofp)) { if(ofp) { fclose(ofp); ofp=NULL; } continue; } //printf(" full match\n"); //printf("%s, %s\n", find->files->path, newfile->path); // If there are already enough links to this file, replace // our memory of it with the new file so that files later on // can link to the new one. if(f->nlink>=maxlinks) { // Just need to reset the path name and the number // of links, and pretend that it was found otherwise // NULL newfile will get added to the memory. reset_old_file(f, newfile, info); found++; break; } found++; count++; // Now hardlink it. if(makelinks) { if(!do_hardlink(newfile, f, ext)) { f->nlink++; // Only count bytes as saved if we removed the // last link. if(newfile->nlink==1) savedbytes+=info->st_size; } else { // On error, replace the memory of the old file // with the one that we just found. It might // work better when someone later tries to // link to the new one instead of the old one. reset_old_file(f, newfile, info); count--; } } else { // To be able to tell how many bytes // are saveable. savedbytes+=info->st_size; } break; } if(nfp) { fclose(nfp); nfp=NULL; } if(ofp) { fclose(ofp); ofp=NULL; } if(found) { if(newfile->path) free(newfile->path); return 0; } if(add_file(find, newfile)) return -1; return 0; }