⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 psftp.c

📁 putty
💻 C
📖 第 1 页 / 共 5 页
字号:
    }

    if (cmd->nwords < 2) {
	printf("rm: expects a filename\n");
	return 0;
    }

    ret = 1;
    for (i = 1; i < cmd->nwords; i++)
	ret &= wildcard_iterate(cmd->words[i], sftp_action_rm, NULL);

    return ret;
}

static int check_is_dir(char *dstfname)
{
    struct sftp_packet *pktin;
    struct sftp_request *req, *rreq;
    struct fxp_attrs attrs;
    int result;

    sftp_register(req = fxp_stat_send(dstfname));
    rreq = sftp_find_request(pktin = sftp_recv());
    assert(rreq == req);
    result = fxp_stat_recv(pktin, rreq, &attrs);

    if (result &&
	(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
	(attrs.permissions & 0040000))
	return TRUE;
    else
	return FALSE;
}

struct sftp_context_mv {
    char *dstfname;
    int dest_is_dir;
};

static int sftp_action_mv(void *vctx, char *srcfname)
{
    struct sftp_context_mv *ctx = (struct sftp_context_mv *)vctx;
    struct sftp_packet *pktin;
    struct sftp_request *req, *rreq;
    const char *error;
    char *finalfname, *newcanon = NULL;
    int ret, result;

    if (ctx->dest_is_dir) {
	char *p;
	char *newname;

	p = srcfname + strlen(srcfname);
	while (p > srcfname && p[-1] != '/') p--;
	newname = dupcat(ctx->dstfname, "/", p, NULL);
	newcanon = canonify(newname);
	if (!newcanon) {
	    printf("%s: canonify: %s\n", newname, fxp_error());
	    sfree(newname);
	    return 0;
	}
	sfree(newname);

	finalfname = newcanon;
    } else {
	finalfname = ctx->dstfname;
    }

    sftp_register(req = fxp_rename_send(srcfname, finalfname));
    rreq = sftp_find_request(pktin = sftp_recv());
    assert(rreq == req);
    result = fxp_rename_recv(pktin, rreq);

    error = result ? NULL : fxp_error();

    if (error) {
	printf("mv %s %s: %s\n", srcfname, finalfname, error);
	ret = 0;
    } else {
	printf("%s -> %s\n", srcfname, finalfname);
	ret = 1;
    }

    sfree(newcanon);
    return ret;
}

int sftp_cmd_mv(struct sftp_command *cmd)
{
    struct sftp_context_mv actx, *ctx = &actx;
    int i, ret;

    if (back == NULL) {
	not_connected();
	return 0;
    }

    if (cmd->nwords < 3) {
	printf("mv: expects two filenames\n");
	return 0;
    }

    ctx->dstfname = canonify(cmd->words[cmd->nwords-1]);
    if (!ctx->dstfname) {
	printf("%s: canonify: %s\n", ctx->dstfname, fxp_error());
	return 0;
    }

    /*
     * If there's more than one source argument, or one source
     * argument which is a wildcard, we _require_ that the
     * destination is a directory.
     */
    ctx->dest_is_dir = check_is_dir(ctx->dstfname);
    if ((cmd->nwords > 3 || is_wildcard(cmd->words[1])) && !ctx->dest_is_dir) {
	printf("mv: multiple or wildcard arguments require the destination"
	       " to be a directory\n");
	sfree(ctx->dstfname);
	return 0;
    }

    /*
     * Now iterate over the source arguments.
     */
    ret = 1;
    for (i = 1; i < cmd->nwords-1; i++)
	ret &= wildcard_iterate(cmd->words[i], sftp_action_mv, ctx);

    sfree(ctx->dstfname);
    return ret;
}

struct sftp_context_chmod {
    unsigned attrs_clr, attrs_xor;
};

static int sftp_action_chmod(void *vctx, char *fname)
{
    struct fxp_attrs attrs;
    struct sftp_packet *pktin;
    struct sftp_request *req, *rreq;
    int result;
    unsigned oldperms, newperms;
    struct sftp_context_chmod *ctx = (struct sftp_context_chmod *)vctx;

    sftp_register(req = fxp_stat_send(fname));
    rreq = sftp_find_request(pktin = sftp_recv());
    assert(rreq == req);
    result = fxp_stat_recv(pktin, rreq, &attrs);

    if (!result || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) {
	printf("get attrs for %s: %s\n", fname,
	       result ? "file permissions not provided" : fxp_error());
	return 0;
    }

    attrs.flags = SSH_FILEXFER_ATTR_PERMISSIONS;   /* perms _only_ */
    oldperms = attrs.permissions & 07777;
    attrs.permissions &= ~ctx->attrs_clr;
    attrs.permissions ^= ctx->attrs_xor;
    newperms = attrs.permissions & 07777;

    if (oldperms == newperms)
	return 1;		       /* no need to do anything! */

    sftp_register(req = fxp_setstat_send(fname, attrs));
    rreq = sftp_find_request(pktin = sftp_recv());
    assert(rreq == req);
    result = fxp_setstat_recv(pktin, rreq);

    if (!result) {
	printf("set attrs for %s: %s\n", fname, fxp_error());
	return 0;
    }

    printf("%s: %04o -> %04o\n", fname, oldperms, newperms);

    return 1;
}

int sftp_cmd_chmod(struct sftp_command *cmd)
{
    char *mode;
    int i, ret;
    struct sftp_context_chmod actx, *ctx = &actx;

    if (back == NULL) {
	not_connected();
	return 0;
    }

    if (cmd->nwords < 3) {
	printf("chmod: expects a mode specifier and a filename\n");
	return 0;
    }

    /*
     * Attempt to parse the mode specifier in cmd->words[1]. We
     * don't support the full horror of Unix chmod; instead we
     * support a much simpler syntax in which the user can either
     * specify an octal number, or a comma-separated sequence of
     * [ugoa]*[-+=][rwxst]+. (The initial [ugoa] sequence may
     * _only_ be omitted if the only attribute mentioned is t,
     * since all others require a user/group/other specification.
     * Additionally, the s attribute may not be specified for any
     * [ugoa] specifications other than exactly u or exactly g.
     */
    ctx->attrs_clr = ctx->attrs_xor = 0;
    mode = cmd->words[1];
    if (mode[0] >= '0' && mode[0] <= '9') {
	if (mode[strspn(mode, "01234567")]) {
	    printf("chmod: numeric file modes should"
		   " contain digits 0-7 only\n");
	    return 0;
	}
	ctx->attrs_clr = 07777;
	sscanf(mode, "%o", &ctx->attrs_xor);
	ctx->attrs_xor &= ctx->attrs_clr;
    } else {
	while (*mode) {
	    char *modebegin = mode;
	    unsigned subset, perms;
	    int action;

	    subset = 0;
	    while (*mode && *mode != ',' &&
		   *mode != '+' && *mode != '-' && *mode != '=') {
		switch (*mode) {
		  case 'u': subset |= 04700; break; /* setuid, user perms */
		  case 'g': subset |= 02070; break; /* setgid, group perms */
		  case 'o': subset |= 00007; break; /* just other perms */
		  case 'a': subset |= 06777; break; /* all of the above */
		  default:
		    printf("chmod: file mode '%.*s' contains unrecognised"
			   " user/group/other specifier '%c'\n",
			   (int)strcspn(modebegin, ","), modebegin, *mode);
		    return 0;
		}
		mode++;
	    }
	    if (!*mode || *mode == ',') {
		printf("chmod: file mode '%.*s' is incomplete\n",
		       (int)strcspn(modebegin, ","), modebegin);
		return 0;
	    }
	    action = *mode++;
	    if (!*mode || *mode == ',') {
		printf("chmod: file mode '%.*s' is incomplete\n",
		       (int)strcspn(modebegin, ","), modebegin);
		return 0;
	    }
	    perms = 0;
	    while (*mode && *mode != ',') {
		switch (*mode) {
		  case 'r': perms |= 00444; break;
		  case 'w': perms |= 00222; break;
		  case 'x': perms |= 00111; break;
		  case 't': perms |= 01000; subset |= 01000; break;
		  case 's':
		    if ((subset & 06777) != 04700 &&
			(subset & 06777) != 02070) {
			printf("chmod: file mode '%.*s': set[ug]id bit should"
			       " be used with exactly one of u or g only\n",
			       (int)strcspn(modebegin, ","), modebegin);
			return 0;
		    }
		    perms |= 06000;
		    break;
		  default:
		    printf("chmod: file mode '%.*s' contains unrecognised"
			   " permission specifier '%c'\n",
			   (int)strcspn(modebegin, ","), modebegin, *mode);
		    return 0;
		}
		mode++;
	    }
	    if (!(subset & 06777) && (perms &~ subset)) {
		printf("chmod: file mode '%.*s' contains no user/group/other"
		       " specifier and permissions other than 't' \n",
		       (int)strcspn(modebegin, ","), modebegin);
		return 0;
	    }
	    perms &= subset;
	    switch (action) {
	      case '+':
		ctx->attrs_clr |= perms;
		ctx->attrs_xor |= perms;
		break;
	      case '-':
		ctx->attrs_clr |= perms;
		ctx->attrs_xor &= ~perms;
		break;
	      case '=':
		ctx->attrs_clr |= subset;
		ctx->attrs_xor |= perms;
		break;
	    }
	    if (*mode) mode++;	       /* eat comma */
	}
    }

    ret = 1;
    for (i = 2; i < cmd->nwords; i++)
	ret &= wildcard_iterate(cmd->words[i], sftp_action_chmod, ctx);

    return ret;
}

static int sftp_cmd_open(struct sftp_command *cmd)
{
    int portnumber;

    if (back != NULL) {
	printf("psftp: already connected\n");
	return 0;
    }

    if (cmd->nwords < 2) {
	printf("open: expects a host name\n");
	return 0;
    }

    if (cmd->nwords > 2) {
	portnumber = atoi(cmd->words[2]);
	if (portnumber == 0) {
	    printf("open: invalid port number\n");
	    return 0;
	}
    } else
	portnumber = 0;

    if (psftp_connect(cmd->words[1], NULL, portnumber)) {
	back = NULL;		       /* connection is already closed */
	return -1;		       /* this is fatal */
    }
    do_sftp_init();
    return 1;
}

static int sftp_cmd_lcd(struct sftp_command *cmd)
{
    char *currdir, *errmsg;

    if (cmd->nwords < 2) {
	printf("lcd: expects a local directory name\n");
	return 0;
    }

    errmsg = psftp_lcd(cmd->words[1]);
    if (errmsg) {
	printf("lcd: unable to change directory: %s\n", errmsg);
	sfree(errmsg);
	return 0;
    }

    currdir = psftp_getcwd();
    printf("New local directory is %s\n", currdir);
    sfree(currdir);

    return 1;
}

static int sftp_cmd_lpwd(struct sftp_command *cmd)
{
    char *currdir;

    currdir = psftp_getcwd();
    printf("Current local directory is %s\n", currdir);
    sfree(currdir);

    return 1;
}

static int sftp_cmd_pling(struct sftp_command *cmd)
{
    int exitcode;

    exitcode = system(cmd->words[1]);
    return (exitcode == 0);
}

static int sftp_cmd_help(struct sftp_command *cmd);

static struct sftp_cmd_lookup {
    char *name;
    /*
     * For help purposes, there are two kinds of command:
     * 
     *  - primary commands, in which `longhelp' is non-NULL. In
     *    this case `shorthelp' is descriptive text, and `longhelp'
     *    is longer descriptive text intended to be printed after
     *    the command name.
     * 
     *  - alias commands, in which `longhelp' is NULL. In this case
     *    `shorthelp' is the name of a primary command, which
     *    contains the help that should double up for this command.
     */
    int listed;			       /* do we list this in primary help? */
    char *shorthelp;
    char *longhelp;
    int (*obey) (struct sftp_command *);
} sftp_lookup[] = {
    /*
     * List of sftp commands. This is binary-searched so it MUST be
     * in ASCII order.
     */
    {
	"!", TRUE, "run a local command",
	    "<command>\n"
	    /* FIXME: this example is crap for non-Windows. */
	    "  Runs a local command. For example, \"!del myfile\".\n",
	    sftp_cmd_pling
    },
    {
	"bye", TRUE, "finish your SFTP session",
	    "\n"
	    "  Terminates your SFTP session and quits the PSFTP program.\n",
	    sftp_cmd_quit
    },
    {
	"cd", TRUE, "change your remote working directory",
	    " [ <new working directory> ]\n"
	    "  Change the remote working directory for your SFTP session.\n"
	    "  If a new working directory is not supplied, you will be\n"
	    "  returned to your home directory.\n",
	    sftp_cmd_cd
    },
    {
	"chmod", TRUE, "change file permissions and modes",
	    " <modes> <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
	    "  Change the file permissions on one or more remote files or\n"
	    "  directories.\n"
	    "  <modes> can be any octal Unix permission specifier.\n"
	    "  Alternatively, <modes> can include the following modifiers:\n"
	    "    u+r     make file readable by owning user\n"
	    "    u+w     make file writable by owning user\n"
	    "    u+x     make file executable by owning user\n"
	    "    u-r     make file not readable by owning user\n"
	    "    [also u-w, u-x]\n"
	    "    g+r     make file readable by members of owning group\n"
	    "    [also g+w, g+x, g-r, g-w, g-x]\n"
	    "    o+r     make file readable by all other users\n"
	    "    [also o+w, o+x, o-r, o-w, o-x]\n"
	    "    a+r     make file readable by absolutely everybody\n"
	    "    [also a+w, a+x, a-r, a-w, a-x]\n"
	    "    u+s     enable the Unix set-user-ID bit\n"
	    "    u-s     disable the Unix set-user-ID bit\n"
	    "    g+s     enable the Unix set-group-ID bit\n"
	    "    g-s     disable the Unix set-group-ID bit\n"
	    "    +t      enable the Unix \"sticky bit\"\n"
	    "  You can give more than one modifier for the same user (\"g-rwx\"), and\n"
	    "  more than one user for the same modifier (\"ug+w\"). You can\n"
	    "  use commas to separate different modifiers (\"u+rwx,g+s\").\n",
	    sftp_cmd_chmod
    },
    {
	"close", TRUE, "finish your SFTP session but do not quit PSFTP",
	    "\n"
	    "  Terminates your SFTP session, but does not quit the PSFTP\n"
	    "  program. You can then use \"open\" to start another SFTP\n"
	    "  session, to the same server or to a different one.\n",
	    sftp_cmd_close
    },
    {
	"del", TRUE, "delete files on the remote server",
	    " <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
	    "  Delete a file or files from the server.\n",
	    sftp_cmd_rm
    },
    {
	"delete", FALSE, "del", NULL, sftp_cmd_rm
    },
    {
	"dir", TRUE, "list remote files",
	    " [ <directory-name> ]/[ <wildcard> ]\n"
	    "  List the contents of a specified directory on the server.\n"
	    "  If <directory-name> is not given, the current working directory\n"
	    "  is assumed.\n"
	    "  If <wildcard> is given, it is treated as a set of files to\n"
	    "  list; otherwise, all files are listed.\n",
	    sftp_cmd_ls
    },
    {
	"exit", TRUE, "bye", NULL, sftp_cmd_quit
    },
    {
	"get", TRUE, "download a file from the server to your local machine",
	    " [ -r ] [ -- ] <filename> [ <local-filename> ]\n"
	    "  Downloads a file on the server and stores it locally under\n"
	    "  the same name, or under a different one if you supply the\n"
	    "  argument <local-filename>.\n"
	    "  If -r specified, recursively fetch a directory.\n",
	    sftp_cmd_get
    },
    {
	"help", TRUE, "give help",
	    " [ <command> [ <command> ... ] ]\n"
	    "  Give general help if no commands are specified.\n"
	    "  If one or more commands are specified, give specific help on\n"

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -