00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "rsync.h"
00022
00023 extern int dry_run;
00024 extern int verbose;
00025
00026 #if SUPPORT_HARD_LINKS
00027 static int hlink_compare(struct file_struct *f1, struct file_struct *f2)
00028 {
00029 if (!S_ISREG(f1->mode) && !S_ISREG(f2->mode))
00030 return 0;
00031 if (!S_ISREG(f1->mode))
00032 return -1;
00033 if (!S_ISREG(f2->mode))
00034 return 1;
00035
00036 if (f1->dev != f2->dev)
00037 return (int) (f1->dev > f2->dev ? 1 : -1);
00038
00039 if (f1->inode != f2->inode)
00040 return (int) (f1->inode > f2->inode ? 1 : -1);
00041
00042 return file_compare(&f1, &f2);
00043 }
00044
00045
00046 static struct file_struct *hlink_list;
00047 static int hlink_count;
00048 #endif
00049
00050 void init_hard_links(struct file_list *flist)
00051 {
00052 #if SUPPORT_HARD_LINKS
00053 int i;
00054 if (flist->count < 2)
00055 return;
00056
00057 if (hlink_list)
00058 free(hlink_list);
00059
00060 if (!(hlink_list =
00061 (struct file_struct *) malloc(sizeof(hlink_list[0]) *
00062 flist->count)))
00063 out_of_memory("init_hard_links");
00064
00065 for (i = 0; i < flist->count; i++)
00066 memcpy(&hlink_list[i], flist->files[i],
00067 sizeof(hlink_list[0]));
00068
00069 qsort(hlink_list, flist->count,
00070 sizeof(hlink_list[0]), (int (*)()) hlink_compare);
00071
00072 hlink_count = flist->count;
00073 #endif
00074 }
00075
00076
00077
00078 int check_hard_link(struct file_struct *file)
00079 {
00080 #if SUPPORT_HARD_LINKS
00081 int low = 0, high = hlink_count - 1;
00082 int ret = 0;
00083
00084 if (!hlink_list || !S_ISREG(file->mode))
00085 return 0;
00086
00087 while (low != high) {
00088 int mid = (low + high) / 2;
00089 ret = hlink_compare(&hlink_list[mid], file);
00090 if (ret == 0) {
00091 low = mid;
00092 break;
00093 }
00094 if (ret > 0)
00095 high = mid;
00096 else
00097 low = mid + 1;
00098 }
00099
00100
00101
00102 if (hlink_compare(&hlink_list[low], file) != 0)
00103 return 0;
00104
00105 if (low > 0 &&
00106 S_ISREG(hlink_list[low - 1].mode) &&
00107 file->dev == hlink_list[low - 1].dev &&
00108 file->inode == hlink_list[low - 1].inode) {
00109 if (verbose >= 2) {
00110 rprintf(FINFO, "check_hard_link: \"%s\" is a hard link to file %d, \"%s\"\n",
00111 f_name(file), low-1, f_name(&hlink_list[low-1]));
00112 }
00113 return 1;
00114 }
00115 #endif
00116
00117 return 0;
00118 }
00119
00120
00121 #if SUPPORT_HARD_LINKS
00122 static void hard_link_one(int i)
00123 {
00124 STRUCT_STAT st1, st2;
00125
00126 if (link_stat(f_name(&hlink_list[i - 1]), &st1) != 0)
00127 return;
00128
00129 if (link_stat(f_name(&hlink_list[i]), &st2) != 0) {
00130 if (do_link
00131 (f_name(&hlink_list[i - 1]),
00132 f_name(&hlink_list[i])) != 0) {
00133 if (verbose > 0)
00134 rprintf(FINFO, "link %s => %s : %s\n",
00135 f_name(&hlink_list[i]),
00136 f_name(&hlink_list[i - 1]),
00137 strerror(errno));
00138 return;
00139 }
00140 } else {
00141 if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino)
00142 return;
00143
00144 if (robust_unlink(f_name(&hlink_list[i])) != 0 ||
00145 do_link(f_name(&hlink_list[i - 1]),
00146 f_name(&hlink_list[i])) != 0) {
00147 if (verbose > 0)
00148 rprintf(FINFO, "link %s => %s : %s\n",
00149 f_name(&hlink_list[i]),
00150 f_name(&hlink_list[i - 1]),
00151 strerror(errno));
00152 return;
00153 }
00154 }
00155 if (verbose > 0)
00156 rprintf(FINFO, "%s => %s\n",
00157 f_name(&hlink_list[i]),
00158 f_name(&hlink_list[i - 1]));
00159 }
00160 #endif
00161
00162
00163
00164
00165
00166
00167
00168 void do_hard_links(void)
00169 {
00170 #if SUPPORT_HARD_LINKS
00171 int i;
00172
00173 if (!hlink_list)
00174 return;
00175
00176 for (i = 1; i < hlink_count; i++) {
00177 if (S_ISREG(hlink_list[i].mode) &&
00178 S_ISREG(hlink_list[i - 1].mode) &&
00179 hlink_list[i].basename && hlink_list[i - 1].basename &&
00180 hlink_list[i].dev == hlink_list[i - 1].dev &&
00181 hlink_list[i].inode == hlink_list[i - 1].inode) {
00182 hard_link_one(i);
00183 }
00184 }
00185 #endif
00186 }