Index: modules/mod_facts.c
===================================================================
RCS file: /cvsroot/proftp/proftpd/modules/mod_facts.c,v
retrieving revision 1.47
diff -u -r1.47 mod_facts.c
--- modules/mod_facts.c 17 Jan 2012 00:51:02 -0000 1.47
+++ modules/mod_facts.c 3 Feb 2012 06:56:26 -0000
@@ -46,7 +46,9 @@
#define FACTS_OPT_SHOW_UNIX_MODE 0x00040
#define FACTS_OPT_SHOW_UNIX_OWNER 0x00080
-#define FACTS_MLINFO_FL_SHOW_SYMLINKS 0x00001
+static unsigned long facts_mlinfo_opts = 0;
+#define FACTS_MLINFO_FL_SHOW_SYMLINKS 0x00001
+#define FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK 0x00002
struct mlinfo {
pool *pool;
@@ -339,7 +341,56 @@
info->st.st_ino = target_st.st_ino;
if (flags & FACTS_MLINFO_FL_SHOW_SYMLINKS) {
- info->type = "OS.unix=symlink";
+
+ /* Do we use the proper RFC 3659 syntax (i.e. following the BNF rules
+ * of RFC 3659), which would be:
+ *
+ * type=OS.unix=symlink
+ *
+ * See:
+ * http://www.rfc-editor.org/errata_search.php?rfc=3659
+ *
+ * and search for "OS.unix=slink".
+ *
+ * Or do we use the syntax in the _examples_ presented in RFC 3659,
+ * which is what clients such as FileZilla expect:
+ *
+ * type=OS.unix=slink:<target>
+ *
+ * See:
+ * http://trac.filezilla-project.org/ticket/4490
+ */
+
+ if (flags & FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK) {
+ char target[PR_TUNABLE_PATH_MAX+1];
+ int targetlen;
+
+ targetlen = pr_fsio_readlink(path, target, sizeof(target)-1);
+ if (targetlen < 0) {
+ int xerrno = errno;
+
+ pr_log_debug(DEBUG4, MOD_FACTS_VERSION
+ ": error reading symlink '%s': %s", path, strerror(xerrno));
+
+ errno = xerrno;
+ return -1;
+ }
+
+ if (targetlen >= sizeof(target)-1) {
+ targetlen = sizeof(target)-1;
+ }
+
+ target[targetlen] = '\0';
+
+ info->type = pstrcat(info->pool, "OS.unix=slink:",
+ dir_best_path(info->pool, target), NULL);
+
+ } else {
+ /* Use the proper syntax. Too bad for the not-really-compliant
+ * FileZilla.
+ */
+ info->type = "OS.unix=symlink";
+ }
} else {
info->type = "file";
@@ -1024,6 +1075,10 @@
if (ptr &&
*ptr == TRUE) {
flags |= FACTS_MLINFO_FL_SHOW_SYMLINKS;
+
+ if (facts_mlinfo_opts & FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK) {
+ flags |= FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK;
+ }
}
best_path = dir_best_path(cmd->tmp_pool, decoded_path);
@@ -1087,11 +1142,11 @@
}
/* Open data connection */
- session.sf_flags |= SF_ASCII_OVERRIDE;
if (pr_data_open(NULL, C_MLSD, PR_NETIO_IO_WR, 0) < 0) {
pr_fsio_closedir(dirh);
return PR_ERROR(cmd);
}
+ session.sf_flags |= SF_ASCII_OVERRIDE;
pr_fs_clear_cache();
facts_mlinfobuf_init();
@@ -1207,6 +1262,10 @@
if (ptr &&
*ptr == TRUE) {
flags |= FACTS_MLINFO_FL_SHOW_SYMLINKS;
+
+ if (facts_mlinfo_opts & FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK) {
+ flags |= FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK;
+ }
}
fake_mode = get_param_ptr(get_dir_ctxt(cmd->tmp_pool, (char *) decoded_path),
@@ -1274,10 +1333,15 @@
/* XXX What about chroots? */
if (flags & FACTS_MLINFO_FL_SHOW_SYMLINKS) {
- /* If we are supposed to symlinks, then use dir_best_path() to get the
- * full path, including dereferencing the symlink.
- */
- info.path = dir_best_path(cmd->tmp_pool, path);
+ if (flags & FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK) {
+ info.path = dir_canonical_path(cmd->tmp_pool, path);
+
+ } else {
+ /* If we are supposed to show symlinks, then use dir_best_path() to get
+ * the full path, including dereferencing the symlink.
+ */
+ info.path = dir_best_path(cmd->tmp_pool, path);
+ }
} else {
info.path = dir_canonical_path(cmd->tmp_pool, path);
@@ -1407,6 +1471,36 @@
return PR_HANDLED(cmd);
}
+/* usage: FactsOptions opt1 ... optN */
+MODRET set_factsoptions(cmd_rec *cmd) {
+ register unsigned int i;
+ config_rec *c;
+ unsigned long opts = 0UL;
+
+ if (cmd->argc-1 == 0) {
+ CONF_ERROR(cmd, "wrong number of parameters");
+ }
+
+ CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
+
+ c = add_config_param(cmd->argv[0], 1, NULL);
+
+ for (i = 1; i < cmd->argc; i++) {
+ if (strncmp(cmd->argv[i], "UseSlink", 9) == 0) {
+ opts |= FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK;
+
+ } else {
+ CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown FactsOption '",
+ cmd->argv[i], "'", NULL));
+ }
+ }
+
+ c->argv[0] = palloc(c->pool, sizeof(unsigned long));
+ *((unsigned long *) c->argv[0]) = opts;
+
+ return PR_HANDLED(cmd);
+}
+
/* Initialization functions
*/
@@ -1426,8 +1520,14 @@
advertise = *((int *) c->argv[0]);
}
- if (advertise == FALSE)
+ if (advertise == FALSE) {
return 0;
+ }
+
+ c = find_config(main_server->conf, CONF_PARAM, "FactsOptions", FALSE);
+ if (c) {
+ facts_mlinfo_opts = *((unsigned long *) c->argv[0]);
+ }
facts_opts = FACTS_OPT_SHOW_MODIFY|FACTS_OPT_SHOW_PERM|FACTS_OPT_SHOW_SIZE|
FACTS_OPT_SHOW_TYPE|FACTS_OPT_SHOW_UNIQUE|FACTS_OPT_SHOW_UNIX_GROUP|
@@ -1451,6 +1551,7 @@
static conftable facts_conftab[] = {
{ "FactsAdvertise", set_factsadvertise, NULL },
+ { "FactsOptions", set_factsoptions, NULL },
{ NULL }
};