result = fxp_stat_recv(pktin, &attrs);
result = fxp_stat_recv(pktin, rreq, &attrs);
int sftp_cmd_chmod(struct sftp_command *cmd){    char *fname, *mode;    int result;    struct fxp_attrs attrs;    unsigned attrs_clr, attrs_xor, oldperms, newperms;    struct sftp_packet *pktin;    struct sftp_request *req, *rreq;    if (back == NULL) {	printf("psftp: not connected to a host; use \"open host.name\"\n");	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.     */    attrs_clr = 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;	}	attrs_clr = 07777;	sscanf(mode, "%o", &attrs_xor);	attrs_xor &= 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",			   strcspn(modebegin, ","), modebegin, *mode);		    return 0;		}		mode++;	    }	    if (!*mode || *mode == ',') {		printf("chmod: file mode '%.*s' is incomplete\n",		       strcspn(modebegin, ","), modebegin);		return 0;	    }	    action = *mode++;	    if (!*mode || *mode == ',') {		printf("chmod: file mode '%.*s' is incomplete\n",		       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",			       strcspn(modebegin, ","), modebegin);			return 0;		    }		    perms |= 06000;		    break;		  default:		    printf("chmod: file mode '%.*s' contains unrecognised"			   " permission specifier '%c'\n",			   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",		       strcspn(modebegin, ","), modebegin);		return 0;	    }	    perms &= subset;	    switch (action) {	      case '+':		attrs_clr |= perms;		attrs_xor |= perms;		break;	      case '-':		attrs_clr |= perms;		attrs_xor &= ~perms;		break;	      case '=':		attrs_clr |= subset;		attrs_xor |= perms;		break;	    }	    if (*mode) mode++;	       /* eat comma */	}    }    fname = canonify(cmd->words[2]);    if (!fname) {	printf("%s: %s\n", fname, fxp_error());	return 0;    }    sftp_register(req = fxp_stat_send(fname));    rreq = sftp_find_request(pktin = sftp_recv());    assert(rreq == req);    result = fxp_stat_recv(pktin, &attrs);    if (!result || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) {	printf("get attrs for %s: %s\n", fname,	       result ? "file permissions not provided" : fxp_error());	sfree(fname);	return 0;    }    attrs.flags = SSH_FILEXFER_ATTR_PERMISSIONS;   /* perms _only_ */    oldperms = attrs.permissions & 07777;    attrs.permissions &= ~attrs_clr;    attrs.permissions ^= attrs_xor;    newperms = attrs.permissions & 07777;    sftp_register(req = fxp_setstat_send(fname, attrs));    rreq = sftp_find_request(pktin = sftp_recv());    assert(rreq == req);    result = fxp_setstat_recv(pktin);    if (!result) {	printf("set attrs for %s: %s\n", fname, fxp_error());	sfree(fname);	return 0;    }    printf("%s: %04o -> %04o\n", fname, oldperms, newperms);    sfree(fname);    return 1;}