Пример #1
0
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;
}
Пример #2
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;
}
Пример #3
0
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);

}
Пример #4
0
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;
}