+ strlcpy(lastname, thisname, MAXPATHLEN);
+
+ clean_fname(thisname, 0);
+
+ if (sanitize_paths)
+ sanitize_path(thisname, thisname, "", 0, NULL);
+
+ if ((basename = strrchr(thisname, '/')) != NULL) {
+ int len = basename++ - thisname;
+ if (len != lastdir_len || memcmp(thisname, lastdir, len) != 0) {
+ lastdir = new_array(char, len + 1);
+ memcpy(lastdir, thisname, len);
+ lastdir[len] = '\0';
+ lastdir_len = len;
+ lastdir_depth = count_dir_elements(lastdir);
+ }
+ } else
+ basename = thisname;
+ 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_varint30(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));
+ extra_len += 2 * EXTRA_LEN;
+ }
+ if (preserve_links && S_ISLNK(mode))
+ linkname_len = strlen(F_SYMLINK(first)) + 1;
+ else
+ linkname_len = 0;
+ goto create_object;
+ }
+#endif
+
+ file_length = read_varlong30(f, 3);
+ if (!(flags & XMIT_SAME_TIME)) {
+ if (protocol_version >= 30)
+ modtime = (time_t)read_varlong(f, 4);
+ else
+ modtime = (time_t)read_int(f);
+ }
+ if (!(flags & XMIT_SAME_MODE))
+ mode = from_wire_mode(read_int(f));
+
+ if (chmod_modes && !S_ISLNK(mode))
+ mode = tweak_mode(mode, chmod_modes);
+
+ if (preserve_uid && !(flags & XMIT_SAME_UID)) {
+ if (protocol_version < 30)
+ uid = (uid_t)read_int(f);
+ else {
+ uid = (uid_t)read_varint(f);
+ if (flags & XMIT_USER_NAME_FOLLOWS)
+ uid = recv_user_name(f, uid);
+ else if (inc_recurse && am_root && !numeric_ids)
+ uid = match_uid(uid);
+ }
+ }
+ if (preserve_gid && !(flags & XMIT_SAME_GID)) {
+ if (protocol_version < 30)
+ gid = (gid_t)read_int(f);
+ else {
+ gid = (gid_t)read_varint(f);
+ if (flags & XMIT_GROUP_NAME_FOLLOWS)
+ gid = recv_group_name(f, gid);
+ else if (inc_recurse && (!am_root || !numeric_ids))
+ gid = match_gid(gid);
+ }
+ }
+
+ if ((preserve_devices && IS_DEVICE(mode))
+ || (preserve_specials && IS_SPECIAL(mode))) {
+ if (protocol_version < 28) {
+ if (!(flags & XMIT_SAME_RDEV_pre28))
+ rdev = (dev_t)read_int(f);
+ } else {
+ uint32 rdev_minor;
+ if (!(flags & XMIT_SAME_RDEV_MAJOR))
+ rdev_major = read_varint30(f);
+ if (protocol_version >= 30)
+ rdev_minor = read_varint(f);
+ else if (flags & XMIT_RDEV_MINOR_8_pre30)
+ rdev_minor = read_byte(f);
+ else
+ rdev_minor = read_int(f);
+ rdev = MAKEDEV(rdev_major, rdev_minor);
+ }
+ extra_len += 2 * EXTRA_LEN;
+ file_length = 0;
+ } else if (protocol_version < 28)
+ rdev = MAKEDEV(0, 0);
+
+#ifdef SUPPORT_LINKS
+ if (preserve_links && S_ISLNK(mode)) {
+ linkname_len = read_varint30(f) + 1; /* count the '\0' */
+ if (linkname_len <= 0 || linkname_len > MAXPATHLEN) {
+ rprintf(FERROR, "overflow: linkname_len=%d\n",
+ linkname_len - 1);
+ overflow_exit("recv_file_entry");
+ }
+ }
+ else
+#endif
+ linkname_len = 0;
+
+#ifdef SUPPORT_HARD_LINKS
+ 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
+
+#ifdef SUPPORT_ACLS
+ /* We need one or two index int32s when we're preserving ACLs. */
+ if (preserve_acls)
+ extra_len += (S_ISDIR(mode) ? 2 : 1) * EXTRA_LEN;
+#endif
+
+ if (always_checksum && S_ISREG(mode))
+ extra_len += SUM_EXTRA_CNT * EXTRA_LEN;
+
+ if (file_length > 0xFFFFFFFFu && S_ISREG(mode))
+ extra_len += EXTRA_LEN;
+
+#if EXTRA_ROUNDING > 0
+ if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN))
+ extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN;
+#endif
+
+ if (inc_recurse && S_ISDIR(mode)) {
+ if (one_file_system) {
+ /* Room to save the dir's device for -x */
+ extra_len += 2 * EXTRA_LEN;
+ }
+ flist = dir_flist;
+ }
+
+ alloc_len = FILE_STRUCT_LEN + extra_len + basename_len
+ + linkname_len;
+ bp = pool_alloc(flist->file_pool, alloc_len, "recv_file_entry");
+
+ memset(bp, 0, extra_len + FILE_STRUCT_LEN);
+ bp += extra_len;
+ file = (struct file_struct *)bp;
+ bp += FILE_STRUCT_LEN;
+
+ memcpy(bp, basename, basename_len);
+ bp += basename_len + linkname_len; /* skip space for symlink too */
+
+#ifdef SUPPORT_HARD_LINKS
+ if (flags & XMIT_HLINKED)
+ file->flags |= FLAG_HLINKED;
+#endif
+ file->modtime = modtime;
+ 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);
+ }
+ file->mode = mode;
+ if (preserve_uid)
+ F_OWNER(file) = uid;
+ if (preserve_gid)
+ F_GROUP(file) = gid;
+
+ if (basename != thisname) {
+ file->dirname = lastdir;
+ F_DEPTH(file) = lastdir_depth + 1;
+ } else
+ F_DEPTH(file) = 1;
+
+ if (S_ISDIR(mode)) {
+ if (basename_len == 1+1 && *basename == '.') /* +1 for '\0' */
+ F_DEPTH(file)--;
+ if (flags & XMIT_TOP_DIR) {
+ in_del_hier = recurse;
+ del_hier_name_len = F_DEPTH(file) == 0 ? 0 : l1 + l2;
+ if (relative_paths && del_hier_name_len > 2
+ && lastname[del_hier_name_len-1] == '.'
+ && lastname[del_hier_name_len-2] == '/')
+ del_hier_name_len -= 2;
+ file->flags |= FLAG_TOP_DIR | FLAG_XFER_DIR;
+ } else if (in_del_hier) {
+ if (!relative_paths || !del_hier_name_len
+ || (l1 >= del_hier_name_len
+ && lastname[del_hier_name_len] == '/'))
+ file->flags |= FLAG_XFER_DIR;
+ else
+ in_del_hier = 0;
+ }
+ }
+
+ if ((preserve_devices && IS_DEVICE(mode))
+ || (preserve_specials && IS_SPECIAL(mode))) {
+ uint32 *devp = F_RDEV_P(file);
+ DEV_MAJOR(devp) = major(rdev);
+ DEV_MINOR(devp) = minor(rdev);
+ }
+
+#ifdef SUPPORT_LINKS
+ if (linkname_len) {
+ 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 (preserve_hard_links && flags & XMIT_HLINKED) {
+ if (protocol_version >= 30) {
+ F_HL_GNUM(file) = flags & XMIT_HLINK_FIRST
+ ? flist->count : first_hlink_ndx;
+ } else {
+ static int32 cnt = 0;
+ struct idev_node *np;
+ int64 ino;
+ int32 ndx;
+ if (protocol_version < 26) {
+ dev = read_int(f);
+ ino = read_int(f);
+ } else {
+ if (!(flags & XMIT_SAME_DEV_pre30))
+ dev = read_longint(f);
+ ino = read_longint(f);
+ }
+ np = idev_node(dev, ino);
+ ndx = (int32)(long)np->data - 1;
+ if (ndx < 0) {
+ ndx = cnt++;
+ np->data = (void*)(long)cnt;
+ }
+ F_HL_GNUM(file) = ndx;
+ }
+ }
+#endif
+
+ if (always_checksum && (S_ISREG(mode) || protocol_version < 28)) {
+ if (S_ISREG(mode))
+ bp = (char*)F_SUM(file);
+ else {
+ /* Prior to 28, we get a useless set of nulls. */
+ bp = tmp_sum;
+ }
+ 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);
+ }
+
+#ifdef SUPPORT_ACLS
+ if (preserve_acls && !S_ISLNK(mode))
+ receive_acl(file, f);
+#endif
+#ifdef SUPPORT_XATTRS
+ if (preserve_xattrs)
+ receive_xattr(file, f );
+#endif
+
+ if (S_ISREG(mode) || S_ISLNK(mode))
+ stats.total_size += file_length;