Put file descriptor arg at the start of the arg list for consistency.
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index 2e449c0..a167c3b 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -51,6 +51,7 @@ extern int preserve_links;
 extern int preserve_hard_links;
 extern int preserve_devices;
 extern int preserve_specials;
+extern int missing_args;
 extern int uid_ndx;
 extern int gid_ndx;
 extern int eol_nulls;
@@ -78,14 +79,22 @@ extern char curr_dir[MAXPATHLEN];
 
 extern struct chmod_mode_struct *chmod_modes;
 
-extern struct filter_list_struct filter_list;
-extern struct filter_list_struct daemon_filter_list;
+extern filter_rule_list filter_list;
+extern filter_rule_list daemon_filter_list;
 
 #ifdef ICONV_OPTION
 extern int filesfrom_convert;
 extern iconv_t ic_send, ic_recv;
 #endif
 
+#ifdef HAVE_UTIMENSAT
+#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+#define ST_MTIME_NSEC st_mtim.tv_nsec
+#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
+#define ST_MTIME_NSEC st_mtimensec
+#endif
+#endif
+
 #define PTR_SIZE (sizeof (struct file_struct *))
 
 int io_error;
@@ -96,6 +105,7 @@ struct file_list *cur_flist, *first_flist, *dir_flist;
 int send_dir_ndx = -1, send_dir_depth = -1;
 int flist_cnt = 0; /* how many (non-tmp) file list objects exist */
 int file_total = 0; /* total of all active items over all file-lists */
+int file_old_total = 0; /* total of active items that will soon be gone */
 int flist_eof = 0; /* all the file-lists are now known */
 
 #define NORMAL_NAME 0
@@ -194,7 +204,7 @@ static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf)
        if (link_stat(path, stp, copy_dirlinks) < 0)
                return -1;
        if (S_ISLNK(stp->st_mode)) {
-               int llen = readlink(path, linkbuf, MAXPATHLEN - 1);
+               int llen = do_readlink(path, linkbuf, MAXPATHLEN - 1);
                if (llen < 0)
                        return -1;
                linkbuf[llen] = '\0';
@@ -431,7 +441,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
                        stats.num_symlinks++;
                else if (IS_DEVICE(file->mode))
                        stats.num_devices++;
-               else
+               else if (IS_SPECIAL(file->mode))
                        stats.num_specials++;
                xflags = 0;
        }
@@ -441,8 +451,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
        else
                mode = file->mode;
 
-       if ((preserve_devices && IS_DEVICE(mode))
-        || (preserve_specials && IS_SPECIAL(mode))) {
+       if (preserve_devices && IS_DEVICE(mode)) {
                if (protocol_version < 28) {
                        if (tmp_rdev == rdev)
                                xflags |= XMIT_SAME_RDEV_pre28;
@@ -457,6 +466,17 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
                        if (protocol_version < 30 && (uint32)minor(rdev) <= 0xFFu)
                                xflags |= XMIT_RDEV_MINOR_8_pre30;
                }
+       } else if (preserve_specials && IS_SPECIAL(mode) && protocol_version < 31) {
+               /* Special files don't need an rdev number, so just make
+                * the historical transmission of the value efficient. */
+               if (protocol_version < 28)
+                       xflags |= XMIT_SAME_RDEV_pre28;
+               else {
+                       rdev = MAKEDEV(major(rdev), 0);
+                       xflags |= XMIT_SAME_RDEV_MAJOR;
+                       if (protocol_version < 30)
+                               xflags |= XMIT_RDEV_MINOR_8_pre30;
+               }
        } else if (protocol_version < 28)
                rdev = MAKEDEV(0, 0);
        if (!preserve_uid || ((uid_t)F_OWNER(file) == uid && *lastname))
@@ -483,6 +503,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
                xflags |= XMIT_SAME_TIME;
        else
                modtime = file->modtime;
+       if (NSEC_BUMP(file) && protocol_version >= 31)
+               xflags |= XMIT_MOD_NSEC;
 
 #ifdef SUPPORT_HARD_LINKS
        if (tmp_dev != 0) {
@@ -565,6 +587,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
                else
                        write_int(f, modtime);
        }
+       if (xflags & XMIT_MOD_NSEC)
+               write_varint(f, F_MOD_NSEC(file));
        if (!(xflags & XMIT_SAME_MODE))
                write_int(f, to_wire_mode(mode));
        if (preserve_uid && !(xflags & XMIT_SAME_UID)) {
@@ -592,7 +616,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
                }
        }
        if ((preserve_devices && IS_DEVICE(mode))
-        || (preserve_specials && IS_SPECIAL(mode))) {
+        || (preserve_specials && IS_SPECIAL(mode) && protocol_version < 31)) {
                if (protocol_version < 28) {
                        if (!(xflags & XMIT_SAME_RDEV_pre28))
                                write_int(f, (int)rdev);
@@ -650,8 +674,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
                stats.total_size += F_LENGTH(file);
 }
 
-static struct file_struct *recv_file_entry(struct file_list *flist,
-                                          int xflags, int f)
+static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags)
 {
        static int64 modtime;
        static mode_t mode;
@@ -673,6 +696,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
        int extra_len = file_extra_cnt * EXTRA_LEN;
        int first_hlink_ndx = -1;
        int64 file_length;
+       uint32 modtime_nsec;
        const char *basename;
        struct file_struct *file;
        alloc_pool_t *pool;
@@ -756,13 +780,13 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                        struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start];
                        file_length = F_LENGTH(first);
                        modtime = first->modtime;
+                       modtime_nsec = F_MOD_NSEC(first);
                        mode = first->mode;
                        if (preserve_uid)
                                uid = F_OWNER(first);
                        if (preserve_gid)
                                gid = F_GROUP(first);
-                       if ((preserve_devices && IS_DEVICE(mode))
-                        || (preserve_specials && IS_SPECIAL(mode))) {
+                       if (preserve_devices && IS_DEVICE(mode)) {
                                uint32 *devp = F_RDEV_P(first);
                                rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
                                extra_len += DEV_EXTRA_CNT * EXTRA_LEN;
@@ -790,10 +814,14 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                } else
                        modtime = read_int(f);
        }
+       if (xflags & XMIT_MOD_NSEC)
+               modtime_nsec = read_varint(f);
+       else
+               modtime_nsec = 0;
        if (!(xflags & XMIT_SAME_MODE))
                mode = from_wire_mode(read_int(f));
 
-       if (chmod_modes && !S_ISLNK(mode))
+       if (chmod_modes && !S_ISLNK(mode) && mode)
                mode = tweak_mode(mode, chmod_modes);
 
        if (preserve_uid && !(xflags & XMIT_SAME_UID)) {
@@ -821,7 +849,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
        }
 
        if ((preserve_devices && IS_DEVICE(mode))
-        || (preserve_specials && IS_SPECIAL(mode))) {
+        || (preserve_specials && IS_SPECIAL(mode) && protocol_version < 31)) {
                if (protocol_version < 28) {
                        if (!(xflags & XMIT_SAME_RDEV_pre28))
                                rdev = (dev_t)read_int(f);
@@ -837,7 +865,8 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                                rdev_minor = read_int(f);
                        rdev = MAKEDEV(rdev_major, rdev_minor);
                }
-               extra_len += DEV_EXTRA_CNT * EXTRA_LEN;
+               if (IS_DEVICE(mode))
+                       extra_len += DEV_EXTRA_CNT * EXTRA_LEN;
                file_length = 0;
        } else if (protocol_version < 28)
                rdev = MAKEDEV(0, 0);
@@ -886,6 +915,10 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
 #if SIZEOF_INT64 >= 8
        if (file_length > 0xFFFFFFFFu && S_ISREG(mode))
                extra_len += EXTRA_LEN;
+#endif
+#ifdef HAVE_UTIMENSAT
+       if (modtime_nsec)
+               extra_len += EXTRA_LEN;
 #endif
        if (file_length < 0) {
                rprintf(FERROR, "Offset underflow: file-length is negative\n");
@@ -922,6 +955,12 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                file->flags |= FLAG_HLINKED;
 #endif
        file->modtime = (time_t)modtime;
+#ifdef HAVE_UTIMENSAT
+       if (modtime_nsec) {
+               file->flags |= FLAG_MOD_NSEC;
+               OPT_EXTRA(file, 0)->unum = modtime_nsec;
+       }
+#endif
        file->len32 = (uint32)file_length;
 #if SIZEOF_INT64 >= 8
        if (file_length > 0xFFFFFFFFu && S_ISREG(mode)) {
@@ -930,7 +969,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                exit_cleanup(RERR_UNSUPPORTED);
 #else
                file->flags |= FLAG_LENGTH64;
-               OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32);
+               OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(file_length >> 32);
 #endif
        }
 #endif
@@ -978,8 +1017,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                }
        }
 
-       if ((preserve_devices && IS_DEVICE(mode))
-        || (preserve_specials && IS_SPECIAL(mode))) {
+       if (preserve_devices && IS_DEVICE(mode)) {
                uint32 *devp = F_RDEV_P(file);
                DEV_MAJOR(devp) = major(rdev);
                DEV_MINOR(devp) = minor(rdev);
@@ -1077,11 +1115,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
 
 #ifdef SUPPORT_ACLS
        if (preserve_acls && !S_ISLNK(mode))
-               receive_acl(file, f);
+               receive_acl(f, file);
 #endif
 #ifdef SUPPORT_XATTRS
        if (preserve_xattrs)
-               receive_xattr(file, f );
+               receive_xattr(f, file);
 #endif
 
        if (S_ISREG(mode) || S_ISLNK(mode))
@@ -1124,8 +1162,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
        if (sanitize_paths)
                sanitize_path(thisname, thisname, "", 0, SP_DEFAULT);
 
-       if (stp && S_ISDIR(stp->st_mode)) {
-               st = *stp; /* Needed for "symlink/." with --relative. */
+       if (stp && (S_ISDIR(stp->st_mode) || stp->st_mode == 0)) {
+               /* This is needed to handle a "symlink/." with a --relative
+                * dir, or a request to delete a specific file. */
+               st = *stp;
                *linkname = '\0'; /* make IBM code checker happy */
        } else if (readlink_stat(thisname, &st, linkname) != 0) {
                int save_errno = errno;
@@ -1166,6 +1206,11 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
                                full_fname(thisname));
                }
                return NULL;
+       } else if (st.st_mode == 0) {
+               io_error |= IOERR_GENERAL;
+               rprintf(FINFO, "skipping file with bogus (zero) st_mode: %s\n",
+                       full_fname(thisname));
+               return NULL;
        }
 
        if (filter_level == NO_FILTERS)
@@ -1254,6 +1299,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
        linkname_len = 0;
 #endif
 
+#ifdef ST_MTIME_NSEC
+       if (st.ST_MTIME_NSEC && protocol_version >= 31)
+               extra_len += EXTRA_LEN;
+#endif
 #if SIZEOF_CAPITAL_OFF_T >= 8
        if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode))
                extra_len += EXTRA_LEN;
@@ -1299,19 +1348,26 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
 #endif
 
 #ifdef HAVE_STRUCT_STAT_ST_RDEV
-       if (IS_DEVICE(st.st_mode) || IS_SPECIAL(st.st_mode)) {
+       if (IS_DEVICE(st.st_mode)) {
                tmp_rdev = st.st_rdev;
                st.st_size = 0;
-       }
+       } else if (IS_SPECIAL(st.st_mode))
+               st.st_size = 0;
 #endif
 
        file->flags = flags;
        file->modtime = st.st_mtime;
+#ifdef ST_MTIME_NSEC
+       if (st.ST_MTIME_NSEC && protocol_version >= 31) {
+               file->flags |= FLAG_MOD_NSEC;
+               OPT_EXTRA(file, 0)->unum = st.ST_MTIME_NSEC;
+       }
+#endif
        file->len32 = (uint32)st.st_size;
 #if SIZEOF_CAPITAL_OFF_T >= 8
        if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) {
                file->flags |= FLAG_LENGTH64;
-               OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32);
+               OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(st.st_size >> 32);
        }
 #endif
        file->mode = st.st_mode;
@@ -1364,7 +1420,7 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
        if (!file)
                return NULL;
 
-       if (chmod_modes && !S_ISLNK(file->mode))
+       if (chmod_modes && !S_ISLNK(file->mode) && file->mode)
                file->mode = tweak_mode(file->mode, chmod_modes);
 
        if (f >= 0) {
@@ -1385,6 +1441,14 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
                if (preserve_links && S_ISLNK(file->mode)) {
                        symlink_name = F_SYMLINK(file);
                        symlink_len = strlen(symlink_name);
+                       if (symlink_len == 0) {
+                               io_error |= IOERR_GENERAL;
+                               f_name(file, fbuf);
+                               rprintf(FERROR_XFER,
+                                   "skipping symlink with 0-length value: %s\n",
+                                   full_fname(fbuf));
+                               return NULL;
+                       }
                } else {
                        symlink_name = NULL;
                        symlink_len = 0;
@@ -1450,6 +1514,7 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
 #endif
 #ifdef SUPPORT_XATTRS
                if (preserve_xattrs) {
+                       sx.st.st_mode = file->mode;
                        if (get_xattr(fname, &sx) < 0) {
                                io_error |= IOERR_GENERAL;
                                return NULL;
@@ -1465,13 +1530,13 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
 
 #ifdef SUPPORT_ACLS
                if (preserve_acls && !S_ISLNK(file->mode)) {
-                       send_acl(&sx, f);
+                       send_acl(f, &sx);
                        free_acl(&sx);
                }
 #endif
 #ifdef SUPPORT_XATTRS
                if (preserve_xattrs) {
-                       F_XATTR(file) = send_xattr(&sx, f);
+                       F_XATTR(file) = send_xattr(f, &sx);
                        free_xattr(&sx);
                }
 #endif
@@ -1619,6 +1684,19 @@ static void add_dirs_to_tree(int parent_ndx, struct file_list *from_flist,
                DIR_NEXT_SIBLING(dp) = -1;
 }
 
+static void interpret_stat_error(const char *fname, int is_dir)
+{
+       if (errno == ENOENT) {
+               io_error |= IOERR_VANISHED;
+               rprintf(FWARNING, "%s has vanished: %s\n",
+                       is_dir ? "directory" : "file", full_fname(fname));
+       } else {
+               io_error |= IOERR_GENERAL;
+               rsyserr(FERROR_XFER, errno, "link_stat %s failed",
+                       full_fname(fname));
+       }
+}
+
 /* This function is normally called by the sender, but the receiving side also
  * calls it from get_dirlist() with f set to -1 so that we just construct the
  * file list in memory without sending it over the wire.  Also, get_dirlist()
@@ -1638,8 +1716,11 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len,
        assert(flist != NULL);
 
        if (!(d = opendir(fbuf))) {
-               if (errno == ENOENT)
+               if (errno == ENOENT) {
+                       if (am_sender) /* Can abuse this for vanished error w/ENOENT: */
+                               interpret_stat_error(fbuf, True);
                        return;
+               }
                io_error |= IOERR_GENERAL;
                rsyserr(FERROR_XFER, errno, "opendir %s failed", full_fname(fbuf));
                return;
@@ -1701,7 +1782,7 @@ static void send_implied_dirs(int f, struct file_list *flist, char *fname,
        item_list *relname_list;
        relnamecache **rnpp;
        int len, need_new_dir, depth = 0;
-       struct filter_list_struct save_filter_list = filter_list;
+       filter_rule_list save_filter_list = filter_list;
 
        flags = (flags | FLAG_IMPLIED_DIR) & ~(FLAG_TOP_DIR | FLAG_CONTENT_DIR);
        filter_list.head = filter_list.tail = NULL; /* Don't filter implied dirs. */
@@ -1811,9 +1892,7 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist)
                if (one_file_system) {
                        STRUCT_STAT st;
                        if (link_stat(fbuf, &st, copy_dirlinks) != 0) {
-                               io_error |= IOERR_GENERAL;
-                               rsyserr(FERROR_XFER, errno, "link_stat %s failed",
-                                       full_fname(fbuf));
+                               interpret_stat_error(fbuf, True);
                                return;
                        }
                        filesystem_dev = st.st_dev;
@@ -1848,9 +1927,7 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist)
                if (name_type != NORMAL_NAME) {
                        STRUCT_STAT st;
                        if (link_stat(fbuf, &st, 1) != 0) {
-                               io_error |= IOERR_GENERAL;
-                               rsyserr(FERROR_XFER, errno, "link_stat %s failed",
-                                       full_fname(fbuf));
+                               interpret_stat_error(fbuf, True);
                                continue;
                        }
                        send_file_name(f, flist, fbuf, &st, FLAG_TOP_DIR | flags, ALL_FILTERS);
@@ -1866,17 +1943,17 @@ void send_extra_file_list(int f, int at_least)
        struct file_list *flist;
        int64 start_write;
        uint16 prev_flags;
-       int old_cnt, save_io_error = io_error;
+       int save_io_error = io_error;
 
        if (flist_eof)
                return;
 
+       if (at_least < 0)
+               at_least = file_total - file_old_total + 1;
+
        /* Keep sending data until we have the requested number of
         * files in the upcoming file-lists. */
-       old_cnt = cur_flist->used;
-       for (flist = first_flist; flist != cur_flist; flist = flist->next)
-               old_cnt += flist->used;
-       while (file_total - old_cnt < at_least) {
+       while (file_total - file_old_total < at_least) {
                struct file_struct *file = dir_flist->sorted[send_dir_ndx];
                int dir_ndx, dstart = stats.num_dirs;
                const char *pathname = F_PATHNAME(file);
@@ -1915,7 +1992,7 @@ void send_extra_file_list(int f, int at_least)
                        write_byte(f, 0);
                else {
                        write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
-                       write_int(f, io_error);
+                       write_varint(f, io_error);
                }
 
                if (need_unsorted_flist) {
@@ -2149,14 +2226,26 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0
                 || (name_type != DOTDIR_NAME && is_daemon_excluded(fbuf, S_ISDIR(st.st_mode)))
                 || (relative_paths && path_is_daemon_excluded(fbuf, 1))) {
-                       io_error |= IOERR_GENERAL;
-                       rsyserr(FERROR_XFER, errno, "link_stat %s failed",
-                               full_fname(fbuf));
-                       continue;
+                       if (errno != ENOENT || missing_args == 0) {
+                               /* This is a transfer error, but inhibit deletion
+                                * only if we might be omitting an existing file. */
+                               if (errno != ENOENT)
+                                       io_error |= IOERR_GENERAL;
+                               rsyserr(FERROR_XFER, errno, "link_stat %s failed",
+                                       full_fname(fbuf));
+                               continue;
+                       } else if (missing_args == 1) {
+                               /* Just ignore the arg. */
+                               continue;
+                       } else /* (missing_args == 2) */ {
+                               /* Send the arg as a "missing" entry with
+                                * mode 0, which tells the generator to delete it. */
+                               memset(&st, 0, sizeof st);
+                       }
                }
 
                /* A dot-dir should not be excluded! */
-               if (name_type != DOTDIR_NAME
+               if (name_type != DOTDIR_NAME && st.st_mode != 0
                 && is_excluded(fbuf, S_ISDIR(st.st_mode) != 0, ALL_FILTERS))
                        continue;
 
@@ -2218,7 +2307,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                write_byte(f, 0);
        else {
                write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
-               write_int(f, io_error);
+               write_varint(f, io_error);
        }
 
 #ifdef SUPPORT_HARD_LINKS
@@ -2254,6 +2343,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
        if (numeric_ids <= 0 && !inc_recurse)
                send_id_list(f);
 
+       set_msg_fd_in(-1);
+
        /* send the io_error flag */
        if (protocol_version < 30)
                write_int(f, ignore_errors ? 0 : io_error);
@@ -2288,7 +2379,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                         * file-list to check if this is a 1-file xfer. */
                        send_extra_file_list(f, 1);
                }
-       }
+       } else
+               flist_eof = 1;
 
        return flist;
 }
@@ -2341,14 +2433,14 @@ struct file_list *recv_file_list(int f)
                                rprintf(FERROR, "Invalid flist flag: %x\n", flags);
                                exit_cleanup(RERR_PROTOCOL);
                        }
-                       err = read_int(f);
+                       err = read_varint(f);
                        if (!ignore_errors)
                                io_error |= err;
                        break;
                }
 
                flist_expand(flist, 1);
-               file = recv_file_entry(flist, flags, f);
+               file = recv_file_entry(f, flist, flags);
 
                if (S_ISREG(file->mode)) {
                        /* Already counted */
@@ -2414,8 +2506,10 @@ struct file_list *recv_file_list(int f)
 
        if (inc_recurse)
                flist_done_allocating(flist);
-       else if (f >= 0)
+       else if (f >= 0) {
                recv_id_list(f, flist);
+               flist_eof = 1;
+       }
 
        flist_sort_and_clean(flist, relative_paths);
 
@@ -3061,7 +3155,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules)
 
        recurse = 0;
        xfer_dirs = 1;
-       send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen, 0);
+       send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen, FLAG_CONTENT_DIR);
        xfer_dirs = save_xfer_dirs;
        recurse = save_recurse;
        if (INFO_GTE(PROGRESS, 1))