-
Notifications
You must be signed in to change notification settings - Fork 18
/
status.c
186 lines (178 loc) · 5.64 KB
/
status.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
* This file is part of the Green End SFTP Server.
* Copyright (C) 2007, 2011 Richard Kettlewell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
/** @file status.c @brief Status code implementation */
#include "sftpserver.h"
#include "sftp.h"
#include "send.h"
#include "types.h"
#include "globals.h"
#include <assert.h>
#include <errno.h>
#include <string.h>
const char *status_to_string(uint32_t status) {
switch(status) {
case SSH_FX_OK:
return "OK";
case SSH_FX_EOF:
return "end of file";
case SSH_FX_NO_SUCH_FILE:
return "file does not exist";
case SSH_FX_PERMISSION_DENIED:
return "permission denied";
case SSH_FX_FAILURE:
return "operation failed";
case SSH_FX_BAD_MESSAGE:
return "badly encoded SFTP packet";
case SSH_FX_NO_CONNECTION:
return "no connection";
case SSH_FX_CONNECTION_LOST:
return "connection lost";
case SSH_FX_OP_UNSUPPORTED:
return "operation not supported";
case SSH_FX_INVALID_HANDLE:
return "invalid handle";
case SSH_FX_NO_SUCH_PATH:
return "path does not exist or is invalid";
case SSH_FX_FILE_ALREADY_EXISTS:
return "file already exists";
case SSH_FX_WRITE_PROTECT:
return "file is on read-only medium";
case SSH_FX_NO_MEDIA:
return "no medium in drive";
case SSH_FX_NO_SPACE_ON_FILESYSTEM:
return "no space on filesystem";
case SSH_FX_QUOTA_EXCEEDED:
return "quota exceeded";
case SSH_FX_UNKNOWN_PRINCIPAL:
return "unknown principal";
case SSH_FX_LOCK_CONFLICT:
return "file is locked";
case SSH_FX_DIR_NOT_EMPTY:
return "directory is not empty";
case SSH_FX_NOT_A_DIRECTORY:
return "file is not a directory";
case SSH_FX_INVALID_FILENAME:
return "invalid filename";
case SSH_FX_LINK_LOOP:
return "too many symbolic links";
case SSH_FX_CANNOT_DELETE:
return "file cannot be deleted";
case SSH_FX_INVALID_PARAMETER:
return "invalid parameter";
case SSH_FX_FILE_IS_A_DIRECTORY:
return "file is a directory";
case SSH_FX_BYTE_RANGE_LOCK_CONFLICT:
return "byte range is locked";
case SSH_FX_BYTE_RANGE_LOCK_REFUSED:
return "cannot lock byte range";
case SSH_FX_DELETE_PENDING:
return "file deletion pending";
case SSH_FX_FILE_CORRUPT:
return "file is corrupt";
case SSH_FX_OWNER_INVALID:
return "invalid owner";
case SSH_FX_GROUP_INVALID:
return "invalid group";
case SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK:
return "no such lock";
default:
return "unknown status";
}
}
void sftp_send_status(struct sftpjob *job, uint32_t status, const char *msg) {
if(status == HANDLER_ERRNO) {
/* Bodge to allow us to treat -1 as a magical status meaning 'consult
* errno'. This goes back via the protocol-specific status callback, so
* statuses out of range for the current protocol version get properly
* laundered. */
sftp_send_errno_status(job);
return;
}
/* If there is no message, fill one in */
if(!msg)
msg = status_to_string(status);
/* Limit to status values known to this version of the protocol */
if(status > protocol->maxstatus) {
switch(status) {
case SSH_FX_INVALID_FILENAME:
status = SSH_FX_BAD_MESSAGE;
break;
case SSH_FX_NO_SUCH_PATH:
status = SSH_FX_NO_SUCH_FILE;
break;
default:
status = SSH_FX_FAILURE;
break;
}
}
sftp_send_begin(job->worker);
sftp_send_uint8(job->worker, SSH_FXP_STATUS);
sftp_send_uint32(job->worker, job->id);
sftp_send_uint32(job->worker, status);
sftp_send_path(job, job->worker, msg); /* needs to be UTF-8 */
/* We are not I18N'd yet. Doing so will require the following:
* - determine an RFC1766 interpretation of the current LC_MESSAGES
* setting
* - set LC_MESSAGES in setlocale()
* - send the right tag for messages from strerror()
* - _if_ we have a localization for one of our own messages, send the
* right tag (otherwise still send "en")
*/
sftp_send_string(job->worker, "en");
sftp_send_end(job->worker);
}
/** @brief Mapping of @c errno values to SFTP status codes */
static const struct {
int errno_value;
uint32_t status_value;
} errnotab[] = {
{0, SSH_FX_OK},
{EPERM, SSH_FX_PERMISSION_DENIED},
{EACCES, SSH_FX_PERMISSION_DENIED},
{ENOENT, SSH_FX_NO_SUCH_FILE},
{EIO, SSH_FX_FILE_CORRUPT},
{ENOSPC, SSH_FX_NO_SPACE_ON_FILESYSTEM},
{ENOTDIR, SSH_FX_NOT_A_DIRECTORY},
{EISDIR, SSH_FX_FILE_IS_A_DIRECTORY},
{EEXIST, SSH_FX_FILE_ALREADY_EXISTS},
{EROFS, SSH_FX_WRITE_PROTECT},
{ELOOP, SSH_FX_LINK_LOOP},
{ENAMETOOLONG, SSH_FX_INVALID_FILENAME},
{ENOTEMPTY, SSH_FX_DIR_NOT_EMPTY},
{EDQUOT, SSH_FX_QUOTA_EXCEEDED},
{-1, SSH_FX_FAILURE},
};
void sftp_send_errno_status(struct sftpjob *job) {
int n;
const int errno_value = errno;
for(n = 0;
errnotab[n].errno_value != errno_value && errnotab[n].errno_value != -1;
++n)
;
sftp_send_status(job, errnotab[n].status_value, strerror(errno_value));
}
/*
Local Variables:
c-basic-offset:2
comment-column:40
fill-column:79
indent-tabs-mode:nil
End:
*/