1 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "fs-sis-common.h"
5 
6 #include <sys/stat.h>
7 
fs_sis_path_parse(struct fs_file * file,const char * path,const char ** dir_r,const char ** hash_r)8 int fs_sis_path_parse(struct fs_file *file, const char *path,
9 		      const char **dir_r, const char **hash_r)
10 {
11 	const char *fname, *p;
12 
13 	fname = strrchr(path, '/');
14 	if (fname == NULL) {
15 		*dir_r = ".";
16 		fname = path;
17 	} else {
18 		*dir_r = t_strdup_until(path, fname);
19 		fname++;
20 	}
21 
22 	/* assume filename begins with "<hash>-" */
23 	p = strchr(fname, '-');
24 	if (p == NULL) {
25 		fs_set_error(file->event, EINVAL, "open(%s) failed: "
26 			     "Filenames must begin with '<hash>-'", path);
27 		return -1;
28 	}
29 	*hash_r = t_strdup_until(fname, p);
30 	return 0;
31 }
32 
fs_sis_try_unlink_hash_file(struct fs_file * sis_file,struct fs_file * super_file)33 void fs_sis_try_unlink_hash_file(struct fs_file *sis_file,
34 				 struct fs_file *super_file)
35 {
36 	struct fs_file *hash_file;
37 	struct stat st1, st2;
38 	const char *dir, *hash, *hash_path;
39 
40 	if (fs_sis_path_parse(sis_file, super_file->path, &dir, &hash) == 0 &&
41 	    fs_stat(super_file, &st1) == 0 && st1.st_nlink == 2) {
42 		/* this may be the last link. if hashes/ file is the same,
43 		   delete it. */
44 		hash_path = t_strdup_printf("%s/"HASH_DIR_NAME"/%s", dir, hash);
45 		hash_file = fs_file_init_with_event(super_file->fs,
46 						    super_file->event, hash_path,
47 						    FS_OPEN_MODE_READONLY);
48 		if (fs_stat(hash_file, &st2) == 0 &&
49 		    st1.st_ino == st2.st_ino &&
50 		    CMP_DEV_T(st1.st_dev, st2.st_dev)) {
51 			if (fs_delete(hash_file) < 0) {
52 				e_error(hash_file->event, "%s",
53 					fs_file_last_error(hash_file));
54 			}
55 		}
56 		fs_file_deinit(&hash_file);
57 	}
58 }
59 
60