Commit | Line | Data |
---|---|---|
dc5ddbcc AT |
1 | /* |
2 | Copyright (C) Andrew Tridgell 1996 | |
3 | Copyright (C) Paul Mackerras 1996 | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | */ | |
19 | ||
20 | #include "rsync.h" | |
21 | ||
dc5ddbcc | 22 | extern int dry_run; |
9a52223b | 23 | extern int verbose; |
dc5ddbcc AT |
24 | |
25 | #if SUPPORT_HARD_LINKS | |
26 | static int hlink_compare(struct file_struct *f1,struct file_struct *f2) | |
27 | { | |
28 | if (!S_ISREG(f1->mode) && !S_ISREG(f2->mode)) return 0; | |
29 | if (!S_ISREG(f1->mode)) return -1; | |
30 | if (!S_ISREG(f2->mode)) return 1; | |
31 | ||
32 | if (f1->dev != f2->dev) | |
a16bbc39 | 33 | return (int)(f1->dev>f2->dev?1:-1); |
dc5ddbcc AT |
34 | |
35 | if (f1->inode != f2->inode) | |
a16bbc39 | 36 | return (int)(f1->inode>f2->inode?1:-1); |
dc5ddbcc | 37 | |
3ec4dd97 | 38 | return file_compare(&f1,&f2); |
dc5ddbcc AT |
39 | } |
40 | ||
41 | ||
3a6a366f AT |
42 | static struct file_struct *hlink_list; |
43 | static int hlink_count; | |
dc5ddbcc AT |
44 | #endif |
45 | ||
46 | void init_hard_links(struct file_list *flist) | |
47 | { | |
48 | #if SUPPORT_HARD_LINKS | |
dd04a034 AT |
49 | int i; |
50 | if (flist->count < 2) return; | |
dc5ddbcc | 51 | |
dd04a034 | 52 | if (hlink_list) free(hlink_list); |
dc5ddbcc | 53 | |
dd04a034 AT |
54 | if (!(hlink_list = |
55 | (struct file_struct *)malloc(sizeof(hlink_list[0])*flist->count))) | |
56 | out_of_memory("init_hard_links"); | |
dc5ddbcc | 57 | |
dd04a034 | 58 | for (i = 0; i < flist->count; i++) |
f5780433 | 59 | memcpy(&hlink_list[i], flist->files[i], sizeof(hlink_list[0])); |
dc5ddbcc | 60 | |
dd04a034 AT |
61 | qsort(hlink_list,flist->count, |
62 | sizeof(hlink_list[0]), | |
63 | (int (*)())hlink_compare); | |
dc5ddbcc | 64 | |
dd04a034 | 65 | hlink_count=flist->count; |
dc5ddbcc AT |
66 | #endif |
67 | } | |
68 | ||
69 | /* check if a file should be skipped because it is the same as an | |
70 | earlier hard link */ | |
71 | int check_hard_link(struct file_struct *file) | |
72 | { | |
73 | #if SUPPORT_HARD_LINKS | |
527cea66 | 74 | int low=0,high=hlink_count-1; |
e3cd198f | 75 | int ret=0; |
dc5ddbcc AT |
76 | |
77 | if (!hlink_list || !S_ISREG(file->mode)) return 0; | |
78 | ||
79 | while (low != high) { | |
e3cd198f | 80 | int mid = (low+high)/2; |
dc5ddbcc | 81 | ret = hlink_compare(&hlink_list[mid],file); |
c778aaa0 AT |
82 | if (ret == 0) { |
83 | low = mid; | |
84 | break; | |
85 | } | |
dc5ddbcc AT |
86 | if (ret > 0) |
87 | high=mid; | |
88 | else | |
89 | low=mid+1; | |
90 | } | |
91 | ||
e3cd198f | 92 | if (hlink_compare(&hlink_list[low],file) != 0) return 0; |
dc5ddbcc | 93 | |
e3cd198f AT |
94 | if (low > 0 && |
95 | S_ISREG(hlink_list[low-1].mode) && | |
96 | file->dev == hlink_list[low-1].dev && | |
97 | file->inode == hlink_list[low-1].inode) | |
dc5ddbcc AT |
98 | return 1; |
99 | #endif | |
100 | ||
101 | return 0; | |
102 | } | |
103 | ||
104 | ||
a16bbc39 AT |
105 | #if SUPPORT_HARD_LINKS |
106 | static void hard_link_one(int i) | |
107 | { | |
bcacc18b | 108 | STRUCT_STAT st1,st2; |
a16bbc39 AT |
109 | |
110 | if (link_stat(f_name(&hlink_list[i-1]),&st1) != 0) return; | |
111 | ||
112 | if (link_stat(f_name(&hlink_list[i]),&st2) != 0) { | |
113 | if (do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) { | |
114 | if (verbose > 0) | |
9486289c | 115 | rprintf(FINFO,"link %s => %s : %s\n", |
a16bbc39 AT |
116 | f_name(&hlink_list[i]), |
117 | f_name(&hlink_list[i-1]),strerror(errno)); | |
118 | return; | |
119 | } | |
120 | } else { | |
121 | if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino) return; | |
122 | ||
123 | if (do_unlink(f_name(&hlink_list[i])) != 0 || | |
124 | do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) { | |
125 | if (verbose > 0) | |
9486289c | 126 | rprintf(FINFO,"link %s => %s : %s\n", |
a16bbc39 AT |
127 | f_name(&hlink_list[i]), |
128 | f_name(&hlink_list[i-1]),strerror(errno)); | |
129 | return; | |
130 | } | |
131 | } | |
132 | if (verbose > 0) | |
9486289c | 133 | rprintf(FINFO,"%s => %s\n", |
a16bbc39 AT |
134 | f_name(&hlink_list[i]),f_name(&hlink_list[i-1])); |
135 | } | |
136 | #endif | |
137 | ||
dc5ddbcc AT |
138 | /* create any hard links in the flist */ |
139 | void do_hard_links(struct file_list *flist) | |
140 | { | |
141 | #if SUPPORT_HARD_LINKS | |
a16bbc39 | 142 | int i; |
dc5ddbcc | 143 | |
a16bbc39 AT |
144 | if (!hlink_list) return; |
145 | ||
146 | for (i=1;i<hlink_count;i++) { | |
147 | if (S_ISREG(hlink_list[i].mode) && | |
148 | S_ISREG(hlink_list[i-1].mode) && | |
149 | hlink_list[i].basename && hlink_list[i-1].basename && | |
150 | hlink_list[i].dev == hlink_list[i-1].dev && | |
151 | hlink_list[i].inode == hlink_list[i-1].inode) { | |
152 | hard_link_one(i); | |
153 | } | |
dc5ddbcc | 154 | } |
dc5ddbcc AT |
155 | #endif |
156 | } |