--- modules/mod_ls.c +++ modules/mod_ls.c @@ -81,6 +81,7 @@ static struct list_limit_rec list_nfiles /* ls options */ static int + opt_1 = 0, opt_a = 0, opt_A = 0, opt_B = 0, @@ -419,7 +420,6 @@ static int listfile(cmd_rec *cmd, pool * p = cmd->tmp_pool; if (pr_fsio_lstat(name, &st) == 0) { - char *display_name = NULL; suffix[0] = suffix[1] = '\0'; @@ -531,21 +531,24 @@ static int listfile(cmd_rec *cmd, pool * break; } - if (list_times_gmt) + if (list_times_gmt) { t = pr_gmtime(p, (time_t *) &sort_time); - else + + } else { t = pr_localtime(p, (time_t *) &sort_time); + } if (opt_F) { - if (S_ISLNK(st.st_mode)) + if (S_ISLNK(st.st_mode)) { suffix[0] = '@'; - else if (S_ISDIR(st.st_mode)) { + } else if (S_ISDIR(st.st_mode)) { suffix[0] = '/'; rval = 1; - } else if (st.st_mode & 0111) + } else if (st.st_mode & 0111) { suffix[0] = '*'; + } } if (opt_l) { @@ -614,32 +617,38 @@ static int listfile(cmd_rec *cmd, pool * m[2] = (mode & S_IWUSR) ? 'w' : '-'; m[1] = (mode & S_IRUSR) ? 'r' : '-'; - if (ls_curtime - sort_time > 180 * 24 * 60 * 60) + if (ls_curtime - sort_time > 180 * 24 * 60 * 60) { snprintf(timeline, sizeof(timeline), "%5d", t->tm_year+1900); - else + } else { snprintf(timeline, sizeof(timeline), "%02d:%02d", t->tm_hour, t->tm_min); + } ls_fmt_filesize(s, sizeof(s), st.st_size); - if (!opt_n) { - - /* Format nameline using user/group names. */ - snprintf(nameline, sizeof(nameline)-1, - "%s %3d %-8s %-8s %s %s %2d %s %s", m, (int) st.st_nlink, - MAP_UID(st.st_uid), MAP_GID(st.st_gid), s, - months[t->tm_mon], t->tm_mday, timeline, + if (opt_1) { + /* One file per line, with no info other than the file name. Easy. */ + snprintf(nameline, sizeof(nameline)-1, "%s", pr_fs_encode_path(cmd->tmp_pool, display_name)); } else { - - /* Format nameline using user/group IDs. */ - snprintf(nameline, sizeof(nameline)-1, - "%s %3d %-8u %-8u %s %s %2d %s %s", m, (int) st.st_nlink, - (unsigned) st.st_uid, (unsigned) st.st_gid, s, - months[t->tm_mon], t->tm_mday, timeline, - pr_fs_encode_path(cmd->tmp_pool, name)); + if (!opt_n) { + /* Format nameline using user/group names. */ + snprintf(nameline, sizeof(nameline)-1, + "%s %3d %-8s %-8s %s %s %2d %s %s", m, (int) st.st_nlink, + MAP_UID(st.st_uid), MAP_GID(st.st_gid), s, + months[t->tm_mon], t->tm_mday, timeline, + pr_fs_encode_path(cmd->tmp_pool, display_name)); + + } else { + /* Format nameline using user/group IDs. */ + snprintf(nameline, sizeof(nameline)-1, + "%s %3d %-8u %-8u %s %s %2d %s %s", m, (int) st.st_nlink, + (unsigned) st.st_uid, (unsigned) st.st_gid, s, + months[t->tm_mon], t->tm_mday, timeline, + pr_fs_encode_path(cmd->tmp_pool, name)); + } } nameline[sizeof(nameline)-1] = '\0'; @@ -649,40 +658,45 @@ static int listfile(cmd_rec *cmd, pool * suffix[0] = '\0'; if (opt_F && pr_fsio_stat(name, &st) == 0) { - if (S_ISLNK(st.st_mode)) + if (S_ISLNK(st.st_mode)) { suffix[0] = '@'; - else if (S_ISDIR(st.st_mode)) + } else if (S_ISDIR(st.st_mode)) { suffix[0] = '/'; - else if (st.st_mode & 0111) + } else if (st.st_mode & 0111) { suffix[0] = '*'; + } } if (!opt_L && list_show_symlinks) { - if (sizeof(nameline) - strlen(nameline) > 4) + if (sizeof(nameline) - strlen(nameline) > 4) { snprintf(buf, sizeof(nameline) - strlen(nameline) - 4, " -> %s", l); - else + } else { pr_log_pri(PR_LOG_NOTICE, "notice: symlink '%s' yields an " "excessive string, ignoring", name); + } } nameline[sizeof(nameline)-1] = '\0'; } - if (opt_STAT) + if (opt_STAT) { pr_response_add(R_211, "%s%s", nameline, suffix); - else + + } else { addfile(cmd, nameline, suffix, sort_time, st.st_size); + } } } else { if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || - S_ISLNK(st.st_mode)) + S_ISLNK(st.st_mode)) { addfile(cmd, pr_fs_encode_path(cmd->tmp_pool, name), suffix, sort_time, st.st_size); + } } } @@ -1340,6 +1354,7 @@ static void parse_list_opts(char **opt, switch (**opt) { case '1': if (strcmp(session.curr_cmd, C_STAT) != 0) { + opt_1 = 1; opt_l = opt_C = 0; } break; @@ -1392,6 +1407,7 @@ static void parse_list_opts(char **opt, if (strcmp(session.curr_cmd, C_NLST) != 0) { opt_l = 1; opt_C = 0; + opt_1 = 0; } break; @@ -1460,7 +1476,7 @@ static void parse_list_opts(char **opt, while ((*opt)++ && isalnum((int) **opt)) { switch (**opt) { case '1': - opt_l = opt_C = 0; + opt_1 = opt_l = opt_C = 0; break; case 'A': @@ -1609,8 +1625,8 @@ static int dolist(cmd_rec *cmd, const ch ls_curtime = time(NULL); if (clearflags) { - opt_A = opt_a = opt_B = opt_C = opt_d = opt_F = opt_h = opt_n = opt_r = - opt_R = opt_S = opt_t = opt_STAT = opt_L = 0; + opt_1 = opt_A = opt_a = opt_B = opt_C = opt_d = opt_F = opt_h = opt_n = + opt_r = opt_R = opt_S = opt_t = opt_STAT = opt_L = 0; } if (have_options(cmd, arg)) { @@ -1745,7 +1761,6 @@ static int dolist(cmd_rec *cmd, const ch skiparg = TRUE; } else { - skiparg = FALSE; if (use_globbing && @@ -1987,6 +2002,10 @@ static int nlstfile(cmd_rec *cmd, const return -1; } + /* XXX Note that "NLST <glob>" was sent, we might be receiving paths + * here, not just file names. And that is not what dir_hide_file() is + * expecting. + */ if (dir_hide_file(file)) return 1; @@ -2012,6 +2031,25 @@ static int nlstfile(cmd_rec *cmd, const } #endif /* PR_USE_NLS */ + if (opt_1) { + char *ptr; + + /* If the -1 option is configured, we want to make sure that we only + * display a file, not a path. And it's possible that we given a path + * here. + */ + ptr = strrchr(display_name, '/'); + if (ptr != NULL) { + size_t display_namelen; + + display_namelen = strlen(display_name); + if (display_namelen > 1) { + /* Make sure that we handle a possible display_name of '/' properly. */ + display_name = ptr + 1; + } + } + } + /* Be sure to flush the output */ res = sendline(0, "%s\r\n", pr_fs_encode_path(cmd->tmp_pool, display_name)); if (res < 0) @@ -2140,8 +2178,16 @@ static int nlstdir(cmd_rec *cmd, const c continue; if (!curdir) { - char *str = pr_fs_encode_path(cmd->tmp_pool, - pdircat(cmd->tmp_pool, dir, p, NULL)); + char *str = NULL; + + if (opt_1) { + /* Send just the file name, not the path. */ + str = pr_fs_encode_path(cmd->tmp_pool, p); + + } else { + str = pr_fs_encode_path(cmd->tmp_pool, + pdircat(cmd->tmp_pool, dir, p, NULL)); + } if (sendline(0, "%s\r\n", str) < 0) { count = -1; @@ -2246,26 +2292,32 @@ MODRET genericlist(cmd_rec *cmd) { fakeuser = get_param_ptr(CURRENT_CONF, "DirFakeUser", FALSE); /* Check for a configured "logged in user" DirFakeUser. */ - if (fakeuser && strcmp(fakeuser, "~") == 0) + if (fakeuser != NULL && + strcmp(fakeuser, "~") == 0) { fakeuser = session.user; + } fakegroup = get_param_ptr(CURRENT_CONF, "DirFakeGroup", FALSE); /* Check for a configured "logged in user" DirFakeGroup. */ - if (fakegroup && strcmp(fakegroup, "~") == 0) + if (fakegroup != NULL && + strcmp(fakegroup, "~") == 0) { fakegroup = session.group; + } fake_mode = get_param_ptr(CURRENT_CONF, "DirFakeMode", FALSE); if (fake_mode) { fakemode = *fake_mode; have_fake_mode = TRUE; - } else + } else { have_fake_mode = FALSE; + } tmp = get_param_ptr(TOPLEVEL_CONF, "TimesGMT", FALSE); - if (tmp != NULL) + if (tmp != NULL) { list_times_gmt = *tmp; + } res = dolist(cmd, pr_fs_decode_path(cmd->tmp_pool, cmd->arg), TRUE); @@ -2273,8 +2325,9 @@ MODRET genericlist(cmd_rec *cmd) { pr_data_abort(0, 0); res = -1; - } else if (session.sf_flags & SF_XFER) + } else if (session.sf_flags & SF_XFER) { ls_done(cmd); + } opt_l = 0; @@ -2457,8 +2510,9 @@ MODRET ls_nlst(cmd_rec *cmd) { list_nfiles.logged = list_ndirs.logged = list_ndepth.logged = FALSE; tmp = get_param_ptr(TOPLEVEL_CONF, "ShowSymlinks", FALSE); - if (tmp != NULL) + if (tmp != NULL) { list_show_symlinks = *tmp; + } target = cmd->argc == 1 ? "." : pr_fs_decode_path(cmd->tmp_pool, cmd->arg); @@ -2486,8 +2540,8 @@ MODRET ls_nlst(cmd_rec *cmd) { } /* Clear the listing option flags. */ - opt_A = opt_a = opt_B = opt_C = opt_d = opt_F = opt_n = opt_r = opt_R = - opt_S = opt_t = opt_STAT = opt_L = 0; + opt_1 = opt_A = opt_a = opt_B = opt_C = opt_d = opt_F = opt_n = opt_r = + opt_R = opt_S = opt_t = opt_STAT = opt_L = 0; if (have_options(cmd, target)) { if (!list_strict_opts) {