X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/96293cf991fc9b550f48c08af74d834723a00a3a..3a5a7de6c91a1943f2a264a1606450e3a7f0c295:/flist.c diff --git a/flist.c b/flist.c index 36384de8..11bd2598 100644 --- a/flist.c +++ b/flist.c @@ -58,6 +58,7 @@ extern int protocol_version; extern int sanitize_paths; extern struct stats stats; extern struct file_list *the_file_list; +extern alloc_pool_t hlink_pool; extern char curr_dir[MAXPATHLEN]; @@ -74,11 +75,13 @@ dev_t filesystem_dev; /* used to implement -x */ * that the sender doesn't need to remember in its file list. The data * will survive just long enough to be used by send_file_entry(). */ static dev_t tmp_rdev; +#ifdef SUPPORT_HARD_LINKS static struct idev tmp_idev; +#endif static char tmp_sum[MD4_SUM_LENGTH]; static char empty_sum[MD4_SUM_LENGTH]; -static int flist_count_offset; +static int flist_count_offset; /* for --delete --progress */ static void clean_flist(struct file_list *flist, int strip_root, int no_dups); static void output_flist(struct file_list *flist); @@ -87,7 +90,7 @@ void init_flist(void) { if (verbose > 4) { rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n", - FILE_STRUCT_LEN, EXTRA_LEN); + (int)FILE_STRUCT_LEN, (int)EXTRA_LEN); } checksum_len = protocol_version < 21 ? 2 : MD4_SUM_LENGTH; } @@ -307,7 +310,7 @@ void flist_expand(struct file_list *flist) out_of_memory("flist_expand"); } -static void send_file_entry(struct file_struct *file, int f) +static void send_file_entry(struct file_struct *file, int f, int ndx) { unsigned short flags; static time_t modtime; @@ -319,21 +322,9 @@ static void send_file_entry(struct file_struct *file, int f) static gid_t gid; static char lastname[MAXPATHLEN]; char fname[MAXPATHLEN]; + int first_hlink_ndx = -1; int l1, l2; - if (f < 0) - return; - - if (!file) { - write_byte(f, 0); - modtime = 0, mode = 0; - dev = 0, rdev = MAKEDEV(0, 0); - rdev_major = 0; - uid = 0, gid = 0; - *lastname = '\0'; - return; - } - f_name(file, fname); flags = file->flags & FLAG_TOP_DIR; /* FLAG_TOP_DIR == XMIT_TOP_DIR */ @@ -379,12 +370,22 @@ static void send_file_entry(struct file_struct *file, int f) #ifdef SUPPORT_HARD_LINKS if (tmp_idev.dev != 0) { - if (tmp_idev.dev == dev) { - if (protocol_version >= 28) - flags |= XMIT_SAME_DEV; - } else - dev = tmp_idev.dev; - flags |= XMIT_HAS_IDEV_DATA; + if (protocol_version >= 30) { + struct idev_node *np = idev_node(tmp_idev.dev, tmp_idev.ino); + first_hlink_ndx = (int32)np->data - 1; + if (first_hlink_ndx < 0) { + np->data = (void*)(ndx + 1); + flags |= XMIT_HLINK_FIRST; + } + flags |= XMIT_HLINKED; + } else { + if (tmp_idev.dev == dev) { + if (protocol_version >= 28) + flags |= XMIT_SAME_DEV_pre30; + } else + dev = tmp_idev.dev; + flags |= XMIT_HLINKED; + } } #endif @@ -423,6 +424,11 @@ static void send_file_entry(struct file_struct *file, int f) write_byte(f, l2); write_buf(f, fname + l1, l2); + if (first_hlink_ndx >= 0) { + write_int(f, first_hlink_ndx); + goto the_end; + } + write_longint(f, F_LENGTH(file)); if (!(flags & XMIT_SAME_TIME)) write_int(f, modtime); @@ -463,14 +469,14 @@ static void send_file_entry(struct file_struct *file, int f) #endif #ifdef SUPPORT_HARD_LINKS - if (tmp_idev.dev != 0) { + if (tmp_idev.dev != 0 && protocol_version < 30) { if (protocol_version < 26) { /* 32-bit dev_t and ino_t */ write_int(f, (int32)dev); write_int(f, (int32)tmp_idev.ino); } else { /* 64-bit dev_t and ino_t */ - if (!(flags & XMIT_SAME_DEV)) + if (!(flags & XMIT_SAME_DEV_pre30)) write_longint(f, dev); write_longint(f, tmp_idev.ino); } @@ -488,6 +494,7 @@ static void send_file_entry(struct file_struct *file, int f) write_buf(f, sum, checksum_len); } + the_end: strlcpy(lastname, fname, MAXPATHLEN); } @@ -509,6 +516,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, unsigned int l1 = 0, l2 = 0; int alloc_len, basename_len, dirname_len, linkname_len; int extra_len = (flist_extra_cnt - 1) * EXTRA_LEN; + int first_hlink_ndx = -1; OFF_T file_length; char *basename, *dirname, *bp; struct file_struct *file; @@ -565,6 +573,38 @@ static struct file_struct *recv_file_entry(struct file_list *flist, } basename_len = strlen(basename) + 1; /* count the '\0' */ +#ifdef SUPPORT_HARD_LINKS + if (protocol_version >= 30 + && BITS_SETnUNSET(flags, XMIT_HLINKED, XMIT_HLINK_FIRST)) { + struct file_struct *first; + first_hlink_ndx = read_int(f); + if (first_hlink_ndx < 0 || first_hlink_ndx >= flist->count) { + rprintf(FERROR, + "hard-link reference out of range: %d (%d)\n", + first_hlink_ndx, flist->count); + exit_cleanup(RERR_PROTOCOL); + } + first = flist->files[first_hlink_ndx]; + file_length = F_LENGTH(first); + modtime = first->modtime; + mode = first->mode; + if (preserve_uid) + uid = F_UID(first); + if (preserve_gid) + gid = F_GID(first); + if ((preserve_devices && IS_DEVICE(mode)) + || (preserve_specials && IS_SPECIAL(mode))) { + uint32 *devp = F_RDEV_P(first); + rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); + } + if (preserve_links && S_ISLNK(mode)) + linkname_len = strlen(F_SYMLINK(first)) + 1; + else + linkname_len = 0; + goto create_object; + } +#endif + file_length = read_longint(f); if (!(flags & XMIT_SAME_TIME)) modtime = (time_t)read_int(f); @@ -613,11 +653,12 @@ static struct file_struct *recv_file_entry(struct file_list *flist, linkname_len = 0; #ifdef SUPPORT_HARD_LINKS - if (preserve_hard_links && protocol_version < 28 && S_ISREG(mode)) - flags |= XMIT_HAS_IDEV_DATA; - if (flags & XMIT_HAS_IDEV_DATA) { - extra_len += EXTRA_LEN; - assert(flist->hlink_pool != NULL); + create_object: + if (preserve_hard_links) { + if (protocol_version < 28 && S_ISREG(mode)) + flags |= XMIT_HLINKED; + if (flags & XMIT_HLINKED) + extra_len += EXTRA_LEN; } #endif @@ -640,11 +681,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist, bp += basename_len + linkname_len; /* skip space for symlink too */ #ifdef SUPPORT_HARD_LINKS - if (flags & XMIT_HAS_IDEV_DATA) + if (flags & XMIT_HLINKED) file->flags |= FLAG_HLINKED; #endif file->modtime = modtime; - file->len32 = file_length; + file->len32 = (uint32)file_length; if (file_length > 0xFFFFFFFFu && S_ISREG(mode)) { file->flags |= FLAG_LENGTH64; OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32); @@ -692,32 +733,42 @@ static struct file_struct *recv_file_entry(struct file_list *flist, if ((preserve_devices && IS_DEVICE(mode)) || (preserve_specials && IS_SPECIAL(mode))) { - F_DMAJOR(file) = major(rdev); - F_DMINOR(file) = minor(rdev); + uint32 *devp = F_RDEV_P(file); + DEV_MAJOR(devp) = major(rdev); + DEV_MINOR(devp) = minor(rdev); } #ifdef SUPPORT_LINKS if (linkname_len) { - bp = (char*)F_BASENAME(file) + basename_len; - read_sbuf(f, bp, linkname_len - 1); + bp = (char*)file->basename + basename_len; + if (first_hlink_ndx >= 0) { + struct file_struct *first = flist->files[first_hlink_ndx]; + memcpy(bp, F_SYMLINK(first), linkname_len); + } else + read_sbuf(f, bp, linkname_len - 1); if (sanitize_paths) sanitize_path(bp, bp, "", lastdir_depth, NULL); } #endif #ifdef SUPPORT_HARD_LINKS - if (flags & XMIT_HAS_IDEV_DATA) { - struct idev *idevp = pool_talloc(flist->hlink_pool, struct idev, - 1, "inode_table"); - F_IDEV(file) = idevp; - if (protocol_version < 26) { - idevp->dev = read_int(f); - idevp->ino = read_int(f); + if (preserve_hard_links && flags & XMIT_HLINKED) { + if (protocol_version >= 30) { + F_HL_GNUM(file) = flags & XMIT_HLINK_FIRST + ? flist->count : first_hlink_ndx; } else { - if (!(flags & XMIT_SAME_DEV)) - dev = read_longint(f); - idevp->dev = dev; - idevp->ino = read_longint(f); + struct idev *idevp = pool_talloc(hlink_pool, struct idev, + 1, "inode_table"); + F_HL_IDEV(file) = idevp; + if (protocol_version < 26) { + idevp->dev = read_int(f); + idevp->ino = read_int(f); + } else { + if (!(flags & XMIT_SAME_DEV_pre30)) + dev = read_longint(f); + idevp->dev = dev; + idevp->ino = read_longint(f); + } } } #endif @@ -729,7 +780,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist, /* Prior to 28, we get a useless set of nulls. */ bp = tmp_sum; } - read_buf(f, bp, checksum_len); + if (first_hlink_ndx >= 0) { + struct file_struct *first = flist->files[first_hlink_ndx]; + memcpy(bp, F_SUM(first), checksum_len); + } else + read_buf(f, bp, checksum_len); } return file; @@ -920,7 +975,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, file->flags = flags; file->modtime = st.st_mtime; - file->len32 = st.st_size; + file->len32 = (uint32)st.st_size; if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) { file->flags |= FLAG_LENGTH64; OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32); @@ -942,7 +997,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, #ifdef SUPPORT_LINKS if (linkname_len) { - bp = (char*)F_BASENAME(file) + basename_len; + bp = (char*)file->basename + basename_len; memcpy(bp, linkname, linkname_len); } #endif @@ -980,10 +1035,11 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, return file; } -/* Only called for temporary file_struct entries. */ +/* Only called for temporary file_struct entries created by make_file(). */ void unmake_file(struct file_struct *file) { - free(file->extras - (flist_extra_cnt - 1)); + int extra_cnt = flist_extra_cnt - 1 + LEN64_BUMP(file); + free(file->extras - extra_cnt); } static struct file_struct *send_file_name(int f, struct file_list *flist, @@ -1004,7 +1060,8 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, flist_expand(flist); flist->files[flist->count++] = file; - send_file_entry(file, f); + if (f >= 0) + send_file_entry(file, f, flist->count - 1); return file; } @@ -1040,8 +1097,7 @@ static void send_if_directory(int f, struct file_list *flist, * file list in memory without sending it over the wire. Also, get_dirlist() * might call this with f set to -2, which also indicates that local filter * rules should be ignored. */ -static void send_directory(int f, struct file_list *flist, - char *fbuf, int len) +static void send_directory(int f, struct file_list *flist, char *fbuf, int len) { struct dirent *di; unsigned remainder; @@ -1088,6 +1144,7 @@ static void send_directory(int f, struct file_list *flist, if (recurse) { int i, end = flist->count - 1; + /* send_if_directory() bumps flist->count, so use "end". */ for (i = start; i <= end; i++) send_if_directory(f, flist, flist->files[i], fbuf, len); } @@ -1111,7 +1168,12 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) start_write = stats.total_written; gettimeofday(&start_tv, NULL); - flist = flist_new(0, "send_file_list"); +#ifdef SUPPORT_HARD_LINKS + if (preserve_hard_links && protocol_version >= 30) + init_hard_links(); +#endif + + flist = flist_new("send_file_list"); io_start_buffering_out(); if (filesfrom_fd >= 0) { @@ -1329,7 +1391,12 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) stats.flist_buildtime = 1; start_tv = end_tv; - send_file_entry(NULL, f); + write_byte(f, 0); /* Indicate end of file list */ + +#ifdef SUPPORT_HARD_LINKS + if (preserve_hard_links && protocol_version >= 30) + idev_destroy(); +#endif if (show_filelist_p()) finish_filelist_progress(flist); @@ -1375,8 +1442,12 @@ struct file_list *recv_file_list(int f) start_read = stats.total_read; - flist = flist_new(WITH_HLINK, "recv_file_list"); + flist = flist_new("recv_file_list"); +#ifdef SUPPORT_HARD_LINKS + if (preserve_hard_links && protocol_version < 30) + init_hard_links(); +#endif while ((flags = read_byte(f)) != 0) { struct file_struct *file; @@ -1507,10 +1578,8 @@ void clear_file(struct file_struct *file) file->len32 = file->dir.depth = 1; } -/* - * allocate a new file list - */ -struct file_list *flist_new(int with_hlink, char *msg) +/* Allocate a new file list. */ +struct file_list *flist_new(char *msg) { struct file_list *flist; @@ -1523,24 +1592,13 @@ struct file_list *flist_new(int with_hlink, char *msg) if (!(flist->file_pool = pool_create(FILE_EXTENT, 0, out_of_memory, POOL_INTERN))) out_of_memory(msg); -#ifdef SUPPORT_HARD_LINKS - if (with_hlink && preserve_hard_links) { - if (!(flist->hlink_pool = pool_create(HLINK_EXTENT, - sizeof (struct idev), out_of_memory, POOL_INTERN))) - out_of_memory(msg); - } -#endif - return flist; } -/* - * free up all elements in a flist - */ +/* Free up all elements in a flist. */ void flist_free(struct file_list *flist) { pool_destroy(flist->file_pool); - pool_destroy(flist->hlink_pool); free(flist->files); free(flist); } @@ -1737,7 +1795,7 @@ static void output_flist(struct file_list *flist) dir = slash = ""; else slash = "/"; - name = F_BASENAME(file); + name = file->basename; trail = S_ISDIR(file->mode) ? "/" : ""; } else dir = slash = name = trail = ""; @@ -1788,7 +1846,7 @@ int f_name_cmp(struct file_struct *f1, struct file_struct *f2) c1 = c2 = NULL; if (!c1) { type1 = S_ISDIR(f1->mode) ? t_path : t_ITEM; - c1 = (uchar*)F_BASENAME(f1); + c1 = (const uchar*)f1->basename; if (type1 == t_PATH && *c1 == '.' && !c1[1]) { type1 = t_ITEM; state1 = s_TRAILING; @@ -1801,7 +1859,7 @@ int f_name_cmp(struct file_struct *f1, struct file_struct *f2) } if (!c2) { type2 = S_ISDIR(f2->mode) ? t_path : t_ITEM; - c2 = (uchar*)F_BASENAME(f2); + c2 = (const uchar*)f2->basename; if (type2 == t_PATH && *c2 == '.' && !c2[1]) { type2 = t_ITEM; state2 = s_TRAILING; @@ -1825,7 +1883,7 @@ int f_name_cmp(struct file_struct *f1, struct file_struct *f2) break; case s_SLASH: type1 = S_ISDIR(f1->mode) ? t_path : t_ITEM; - c1 = (uchar*)F_BASENAME(f1); + c1 = (const uchar*)f1->basename; if (type1 == t_PATH && *c1 == '.' && !c1[1]) { type1 = t_ITEM; state1 = s_TRAILING; @@ -1855,7 +1913,7 @@ int f_name_cmp(struct file_struct *f1, struct file_struct *f2) break; case s_SLASH: type2 = S_ISDIR(f2->mode) ? t_path : t_ITEM; - c2 = (uchar*)F_BASENAME(f2); + c2 = (const uchar*)f2->basename; if (type2 == t_PATH && *c2 == '.' && !c2[1]) { type2 = t_ITEM; state2 = s_TRAILING; @@ -1910,9 +1968,9 @@ char *f_name(struct file_struct *f, char *fbuf) int len = strlen(f->dirname); memcpy(fbuf, f->dirname, len); fbuf[len] = '/'; - strlcpy(fbuf + len + 1, F_BASENAME(f), MAXPATHLEN - (len + 1)); + strlcpy(fbuf + len + 1, f->basename, MAXPATHLEN - (len + 1)); } else - strlcpy(fbuf, F_BASENAME(f), MAXPATHLEN); + strlcpy(fbuf, f->basename, MAXPATHLEN); return fbuf; } @@ -1922,8 +1980,7 @@ char *f_name(struct file_struct *f, char *fbuf) * of the dirname string, and also indicates that "dirname" is a MAXPATHLEN * buffer (the functions we call will append names onto the end, but the old * dir value will be restored on exit). */ -struct file_list *get_dirlist(char *dirname, int dlen, - int ignore_filter_rules) +struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules) { struct file_list *dirlist; char dirbuf[MAXPATHLEN]; @@ -1937,7 +1994,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, dirname = dirbuf; } - dirlist = flist_new(WITHOUT_HLINK, "get_dirlist"); + dirlist = flist_new("get_dirlist"); recurse = 0; xfer_dirs = 1;