/* Command code for the various _*STAT calls. rc is the return value * from *stat() and SB is the buffer. */ static uint32_t sftp_v456_stat_core(struct sftpjob *job, int rc, const struct stat *sb, const char *path) { struct sftpattr attrs; uint32_t flags; if(!rc) { pcheck(sftp_parse_uint32(job, &flags)); sftp_stat_to_attrs(job->a, sb, &attrs, flags, path); sftp_send_begin(job->worker); sftp_send_uint8(job->worker, SSH_FXP_ATTRS); sftp_send_uint32(job->worker, job->id); protocol->sendattrs(job, &attrs); sftp_send_end(job->worker); return HANDLER_RESPONDED; } else return HANDLER_ERRNO; }
uint32_t sftp_v6_realpath(struct sftpjob *job) { char *path, *compose, *resolvedpath; uint8_t control_byte = SSH_FXP_REALPATH_NO_CHECK; unsigned rpflags = 0; struct stat sb; struct sftpattr attrs; pcheck(sftp_parse_path(job, &path)); if(job->left) { pcheck(sftp_parse_uint8(job, &control_byte)); while(job->left) { pcheck(sftp_parse_path(job, &compose)); if(compose[0] == '/') path = compose; else { char *newpath = sftp_alloc(job->a, strlen(path) + strlen(compose) + 2); strcpy(newpath, path); strcat(newpath, "/"); strcat(newpath, compose); path = newpath; } } } D(("sftp_v6_realpath %s %#x", path, control_byte)); switch(control_byte) { case SSH_FXP_REALPATH_NO_CHECK: /* Don't follow links and don't fail if the path doesn't exist */ rpflags = 0; break; case SSH_FXP_REALPATH_STAT_IF: /* Follow links but don't fail if the path doesn't exist */ rpflags = RP_READLINK; break; case SSH_FXP_REALPATH_STAT_ALWAYS: /* Follow links and fail if the path doesn't exist */ rpflags = RP_READLINK|RP_MUST_EXIST; break; default: return SSH_FX_BAD_MESSAGE; } if(!(resolvedpath = sftp_find_realpath(job->a, path, rpflags))) return HANDLER_ERRNO; D(("...real path is %s", resolvedpath)); switch(control_byte) { case SSH_FXP_REALPATH_NO_CHECK: /* Don't stat, send dummy attributes */ memset(&attrs, 0, sizeof attrs); attrs.name = resolvedpath; break; case SSH_FXP_REALPATH_STAT_IF: /* stat as hard as we can but accept failure if it's just not there */ if(stat(resolvedpath, &sb) >= 0 || lstat(resolvedpath, &sb) >= 0) sftp_stat_to_attrs(job->a, &sb, &attrs, 0xFFFFFFFF, resolvedpath); else { memset(&attrs, 0, sizeof attrs); attrs.name = resolvedpath; } break; case SSH_FXP_REALPATH_STAT_ALWAYS: /* stat and error on failure */ if(stat(resolvedpath, &sb) >= 0 || lstat(resolvedpath, &sb) >= 0) sftp_stat_to_attrs(job->a, &sb, &attrs, 0xFFFFFFFF, resolvedpath); else /* Can only happen if path is deleted between realpath call and stat */ return HANDLER_ERRNO; break; } sftp_send_begin(job->worker); sftp_send_uint8(job->worker, SSH_FXP_NAME); sftp_send_uint32(job->worker, job->id); protocol->sendnames(job, 1, &attrs); sftp_send_end(job->worker); return HANDLER_RESPONDED; }