+
+ pathname = dir;
+ pathname_len = len >= 0 ? len : dir ? (int)strlen(dir) : 0;
+
+ return 1;
+}
+
+static void send_file_entry(int f, struct file_struct *file, int ndx)
+{
+ static time_t modtime;
+ static mode_t mode;
+ static int64 dev;
+ static dev_t rdev;
+ static uint32 rdev_major;
+ static uid_t uid;
+ static gid_t gid;
+ static char *user_name, *group_name;
+ static char lastname[MAXPATHLEN];
+ char fname[MAXPATHLEN];
+ int first_hlink_ndx = -1;
+ int l1, l2;
+ int flags;
+
+#ifdef ICONV_OPTION
+ if (ic_send != (iconv_t)-1) {
+ ICONV_CONST char *ibuf;
+ char *obuf = fname;
+ size_t ocnt = MAXPATHLEN, icnt;
+
+ iconv(ic_send, NULL,0, NULL,0);
+ if ((ibuf = (ICONV_CONST char *)file->dirname) != NULL) {
+ icnt = strlen(ibuf);
+ ocnt--; /* pre-subtract the space for the '/' */
+ if (iconv(ic_send, &ibuf,&icnt, &obuf,&ocnt) == (size_t)-1)
+ goto convert_error;
+ *obuf++ = '/';
+ }
+
+ ibuf = (ICONV_CONST char *)file->basename;
+ icnt = strlen(ibuf);
+ if (iconv(ic_send, &ibuf,&icnt, &obuf,&ocnt) == (size_t)-1) {
+ convert_error:
+ io_error |= IOERR_GENERAL;
+ rprintf(FINFO,
+ "[%s] cannot convert filename: %s (%s)\n",
+ who_am_i(), f_name(file, fname), strerror(errno));
+ return;
+ }
+ *obuf = '\0';
+ } else
+#endif
+ f_name(file, fname);
+
+ flags = file->flags & FLAG_TOP_DIR; /* FLAG_TOP_DIR == XMIT_TOP_DIR */
+
+ if (file->mode == mode)
+ flags |= XMIT_SAME_MODE;
+ else
+ mode = file->mode;
+ if ((preserve_devices && IS_DEVICE(mode))
+ || (preserve_specials && IS_SPECIAL(mode))) {
+ if (protocol_version < 28) {
+ if (tmp_rdev == rdev)
+ flags |= XMIT_SAME_RDEV_pre28;
+ else
+ rdev = tmp_rdev;
+ } else {
+ rdev = tmp_rdev;
+ if ((uint32)major(rdev) == rdev_major)
+ flags |= XMIT_SAME_RDEV_MAJOR;
+ else
+ rdev_major = major(rdev);
+ if (protocol_version < 30 && (uint32)minor(rdev) <= 0xFFu)
+ flags |= XMIT_RDEV_MINOR_8_pre30;
+ }
+ } else if (protocol_version < 28)
+ rdev = MAKEDEV(0, 0);
+ if (preserve_uid) {
+ if ((uid_t)F_OWNER(file) == uid && *lastname)
+ flags |= XMIT_SAME_UID;
+ else {
+ uid = F_OWNER(file);
+ if (preserve_uid && !numeric_ids) {
+ user_name = add_uid(uid);
+ if (inc_recurse && user_name)
+ flags |= XMIT_USER_NAME_FOLLOWS;
+ }
+ }
+ }
+ if (preserve_gid) {
+ if ((gid_t)F_GROUP(file) == gid && *lastname)
+ flags |= XMIT_SAME_GID;
+ else {
+ gid = F_GROUP(file);
+ if (preserve_gid && !numeric_ids) {
+ group_name = add_gid(gid);
+ if (inc_recurse && group_name)
+ flags |= XMIT_GROUP_NAME_FOLLOWS;
+ }
+ }
+ }
+ if (file->modtime == modtime)
+ flags |= XMIT_SAME_TIME;
+ else
+ modtime = file->modtime;
+
+#ifdef SUPPORT_HARD_LINKS
+ if (tmp_dev != 0) {
+ if (protocol_version >= 30) {
+ struct idev_node *np = idev_node(tmp_dev, tmp_ino);
+ first_hlink_ndx = (int32)(long)np->data - 1;
+ if (first_hlink_ndx < 0) {
+ np->data = (void*)(long)(ndx + 1);
+ flags |= XMIT_HLINK_FIRST;
+ }
+ flags |= XMIT_HLINKED;
+ } else {
+ if (tmp_dev == dev) {
+ if (protocol_version >= 28)
+ flags |= XMIT_SAME_DEV_pre30;
+ } else
+ dev = tmp_dev;
+ flags |= XMIT_HLINKED;
+ }
+ }
+#endif
+
+ for (l1 = 0;
+ lastname[l1] && (fname[l1] == lastname[l1]) && (l1 < 255);
+ l1++) {}
+ l2 = strlen(fname+l1);
+
+ if (l1 > 0)
+ flags |= XMIT_SAME_NAME;
+ if (l2 > 255)
+ flags |= XMIT_LONG_NAME;
+
+ /* We must make sure we don't send a zero flag byte or the
+ * other end will terminate the flist transfer. Note that
+ * the use of XMIT_TOP_DIR on a non-dir has no meaning, so
+ * it's harmless way to add a bit to the first flag byte. */
+ if (protocol_version >= 28) {
+ if (!flags && !S_ISDIR(mode))
+ flags |= XMIT_TOP_DIR;
+ if ((flags & 0xFF00) || !flags) {
+ flags |= XMIT_EXTENDED_FLAGS;
+ write_shortint(f, flags);
+ } else
+ write_byte(f, flags);
+ } else {
+ if (!(flags & 0xFF))
+ flags |= S_ISDIR(mode) ? XMIT_LONG_NAME : XMIT_TOP_DIR;
+ write_byte(f, flags);
+ }
+ if (flags & XMIT_SAME_NAME)
+ write_byte(f, l1);
+ if (flags & XMIT_LONG_NAME)
+ write_varint30(f, l2);
+ else
+ write_byte(f, l2);
+ write_buf(f, fname + l1, l2);
+
+ if (first_hlink_ndx >= 0) {
+ write_varint30(f, first_hlink_ndx);
+ goto the_end;
+ }
+
+ write_varlong30(f, F_LENGTH(file), 3);
+ if (!(flags & XMIT_SAME_TIME)) {
+ if (protocol_version >= 30)
+ write_varlong(f, modtime, 4);
+ else
+ write_int(f, modtime);
+ }
+ if (!(flags & XMIT_SAME_MODE))
+ write_int(f, to_wire_mode(mode));
+ if (preserve_uid && !(flags & XMIT_SAME_UID)) {
+ if (protocol_version < 30)
+ write_int(f, uid);
+ else {
+ write_varint(f, uid);
+ if (flags & XMIT_USER_NAME_FOLLOWS) {
+ int len = strlen(user_name);
+ write_byte(f, len);
+ write_buf(f, user_name, len);
+ }
+ }
+ }
+ if (preserve_gid && !(flags & XMIT_SAME_GID)) {
+ if (protocol_version < 30)
+ write_int(f, gid);
+ else {
+ write_varint(f, gid);
+ if (flags & XMIT_GROUP_NAME_FOLLOWS) {
+ int len = strlen(group_name);
+ write_byte(f, len);
+ write_buf(f, group_name, len);
+ }
+ }
+ }
+ if ((preserve_devices && IS_DEVICE(mode))
+ || (preserve_specials && IS_SPECIAL(mode))) {
+ if (protocol_version < 28) {
+ if (!(flags & XMIT_SAME_RDEV_pre28))
+ write_int(f, (int)rdev);
+ } else {
+ if (!(flags & XMIT_SAME_RDEV_MAJOR))
+ write_varint30(f, major(rdev));
+ if (protocol_version >= 30)
+ write_varint(f, minor(rdev));
+ else if (flags & XMIT_RDEV_MINOR_8_pre30)
+ write_byte(f, minor(rdev));
+ else
+ write_int(f, minor(rdev));
+ }
+ }
+
+#ifdef SUPPORT_LINKS
+ if (preserve_links && S_ISLNK(mode)) {
+ const char *sl = F_SYMLINK(file);
+ int len = strlen(sl);
+ write_varint30(f, len);
+ write_buf(f, sl, len);
+ }
+#endif
+
+#ifdef SUPPORT_HARD_LINKS
+ if (tmp_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_ino);
+ } else {
+ /* 64-bit dev_t and ino_t */
+ if (!(flags & XMIT_SAME_DEV_pre30))
+ write_longint(f, dev);
+ write_longint(f, tmp_ino);
+ }
+ }
+#endif
+
+ if (always_checksum && (S_ISREG(mode) || protocol_version < 28)) {
+ const char *sum;
+ if (S_ISREG(mode))
+ sum = tmp_sum;
+ else {
+ /* Prior to 28, we sent a useless set of nulls. */
+ sum = empty_sum;
+ }
+ write_buf(f, sum, checksum_len);
+ }
+
+ the_end:
+ strlcpy(lastname, fname, MAXPATHLEN);
+
+ if (S_ISREG(mode) || S_ISLNK(mode))
+ stats.total_size += F_LENGTH(file);