2003-08-24 12:47:46 +00:00
|
|
|
/*
|
2022-01-22 15:38:53 +00:00
|
|
|
* sftp.c: the Windows-specific parts of PSFTP and PSCP.
|
2003-08-24 12:47:46 +00:00
|
|
|
*/
|
|
|
|
|
2017-02-14 23:19:13 +00:00
|
|
|
#include <winsock2.h> /* need to put this first, for winelib builds */
|
2004-11-27 13:20:21 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
2017-02-14 23:19:13 +00:00
|
|
|
#define NEED_DECLARATION_OF_SELECT
|
|
|
|
|
2003-08-24 12:47:46 +00:00
|
|
|
#include "putty.h"
|
|
|
|
#include "psftp.h"
|
2009-09-27 15:31:08 +00:00
|
|
|
#include "ssh.h"
|
2021-04-23 05:19:05 +00:00
|
|
|
#include "security-api.h"
|
2005-04-21 13:57:08 +00:00
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
SeatPromptResult filexfer_get_userpass_input(Seat *seat, prompts_t *p)
|
2005-10-30 20:24:09 +00:00
|
|
|
{
|
Fix command-line password handling in Restart Session.
When the user provides a password on the PuTTY command line, via -pw
or -pwfile, the flag 'tried_once' inside cmdline_get_passwd_input() is
intended to arrange that we only try sending that password once, and
after we've sent it, we don't try again.
But this plays badly with the 'Restart Session' operation. If the
connection is lost and then restarted at user request, we _do_ want to
send that password again!
So this commit moves that static variable out into a small state
structure held by the client of cmdline_get_passwd_input. Each client
can decide how to manage that state itself.
Clients that support 'Restart Session' - i.e. just GUI PuTTY itself -
will initialise the state at the same time as instantiating the
backend, so that every time the session is restarted, we return
to (correctly) believing that we _haven't_ yet tried the password
provided on the command line.
But clients that don't support 'Restart Session' - i.e. Plink and file
transfer tools - can do the same thing that cmdline.c was doing
before: just keep the state in a static variable.
This also means that the GUI login tools will now retain the
command-line password in memory, whereas previously they'd have wiped
it out once it was used. But the other tools will still wipe and free
the password, because I've also added a 'bool restartable' flag to
cmdline_get_passwd_input to let it know when it _is_ allowed to do
that.
In the GUI tools, I don't see any way to get round that, because if
the session is restarted you _have_ to still have the password to use
again. (And you can't infer that that will never happen from the
CONF_close_on_exit setting, because that too could be changed in
mid-session.) On the other hand, I think it's not all that worrying,
because the use of either -pw or -pwfile means that a persistent copy
of your password is *already* stored somewhere, so another one isn't
too big a stretch.
(Due to the change of -pw policy in 0.77, the effect of this bug was
that an attempt to reconnect in a session set up this way would lead
to "Configured password was not accepted". In 0.76, the failure mode
was different: PuTTY would interactively prompt for the password,
having wiped it out of memory after it was used the first time round.)
2022-05-18 12:04:56 +00:00
|
|
|
/* The file transfer tools don't support Restart Session, so we
|
|
|
|
* can just have a single static cmdline_get_passwd_input_state
|
|
|
|
* that's never reset */
|
|
|
|
static cmdline_get_passwd_input_state cmdline_state =
|
|
|
|
CMDLINE_GET_PASSWD_INPUT_STATE_INIT;
|
|
|
|
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
SeatPromptResult spr;
|
Fix command-line password handling in Restart Session.
When the user provides a password on the PuTTY command line, via -pw
or -pwfile, the flag 'tried_once' inside cmdline_get_passwd_input() is
intended to arrange that we only try sending that password once, and
after we've sent it, we don't try again.
But this plays badly with the 'Restart Session' operation. If the
connection is lost and then restarted at user request, we _do_ want to
send that password again!
So this commit moves that static variable out into a small state
structure held by the client of cmdline_get_passwd_input. Each client
can decide how to manage that state itself.
Clients that support 'Restart Session' - i.e. just GUI PuTTY itself -
will initialise the state at the same time as instantiating the
backend, so that every time the session is restarted, we return
to (correctly) believing that we _haven't_ yet tried the password
provided on the command line.
But clients that don't support 'Restart Session' - i.e. Plink and file
transfer tools - can do the same thing that cmdline.c was doing
before: just keep the state in a static variable.
This also means that the GUI login tools will now retain the
command-line password in memory, whereas previously they'd have wiped
it out once it was used. But the other tools will still wipe and free
the password, because I've also added a 'bool restartable' flag to
cmdline_get_passwd_input to let it know when it _is_ allowed to do
that.
In the GUI tools, I don't see any way to get round that, because if
the session is restarted you _have_ to still have the password to use
again. (And you can't infer that that will never happen from the
CONF_close_on_exit setting, because that too could be changed in
mid-session.) On the other hand, I think it's not all that worrying,
because the use of either -pw or -pwfile means that a persistent copy
of your password is *already* stored somewhere, so another one isn't
too big a stretch.
(Due to the change of -pw policy in 0.77, the effect of this bug was
that an attempt to reconnect in a session set up this way would lead
to "Configured password was not accepted". In 0.76, the failure mode
was different: PuTTY would interactively prompt for the password,
having wiped it out of memory after it was used the first time round.)
2022-05-18 12:04:56 +00:00
|
|
|
spr = cmdline_get_passwd_input(p, &cmdline_state, false);
|
Richer data type for interactive prompt results.
All the seat functions that request an interactive prompt of some kind
to the user - both the main seat_get_userpass_input and the various
confirmation dialogs for things like host keys - were using a simple
int return value, with the general semantics of 0 = "fail", 1 =
"proceed" (and in the case of seat_get_userpass_input, answers to the
prompts were provided), and -1 = "request in progress, wait for a
callback".
In this commit I change all those functions' return types to a new
struct called SeatPromptResult, whose primary field is an enum
replacing those simple integer values.
The main purpose is that the enum has not three but _four_ values: the
"fail" result has been split into 'user abort' and 'software abort'.
The distinction is that a user abort occurs as a result of an
interactive UI action, such as the user clicking 'cancel' in a dialog
box or hitting ^D or ^C at a terminal password prompt - and therefore,
there's no need to display an error message telling the user that the
interactive operation has failed, because the user already knows,
because they _did_ it. 'Software abort' is from any other cause, where
PuTTY is the first to know there was a problem, and has to tell the
user.
We already had this 'user abort' vs 'software abort' distinction in
other parts of the code - the SSH backend has separate termination
functions which protocol layers can call. But we assumed that any
failure from an interactive prompt request fell into the 'user abort'
category, which is not true. A couple of examples: if you configure a
host key fingerprint in your saved session via the SSH > Host keys
pane, and the server presents a host key that doesn't match it, then
verify_ssh_host_key would report that the user had aborted the
connection, and feel no need to tell the user what had gone wrong!
Similarly, if a password provided on the command line was not
accepted, then (after I fixed the semantics of that in the previous
commit) the same wrong handling would occur.
So now, those Seat prompt functions too can communicate whether the
user or the software originated a connection abort. And in the latter
case, we also provide an error message to present to the user. Result:
in those two example cases (and others), error messages should no
longer go missing.
Implementation note: to avoid the hassle of having the error message
in a SeatPromptResult being a dynamically allocated string (and hence,
every recipient of one must always check whether it's non-NULL and
free it on every exit path, plus being careful about copying the
struct around), I've instead arranged that the structure contains a
function pointer and a couple of parameters, so that the string form
of the message can be constructed on demand. That way, the only users
who need to free it are the ones who actually _asked_ for it in the
first place, which is a much smaller set.
(This is one of the rare occasions that I regret not having C++'s
extra features available in this code base - a unique_ptr or
shared_ptr to a string would have been just the thing here, and the
compiler would have done all the hard work for me of remembering where
to insert the frees!)
2021-12-28 17:52:00 +00:00
|
|
|
if (spr.kind == SPRK_INCOMPLETE)
|
|
|
|
spr = console_get_userpass_input(p);
|
|
|
|
return spr;
|
2005-10-30 20:24:09 +00:00
|
|
|
}
|
2003-08-24 12:47:46 +00:00
|
|
|
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
void platform_get_x11_auth(struct X11Display *display, Conf *conf)
|
2008-11-17 18:38:09 +00:00
|
|
|
{
|
|
|
|
/* Do nothing, therefore no auth. */
|
|
|
|
}
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
const bool platform_uses_x11_unix_by_default = true;
|
2008-11-17 18:38:09 +00:00
|
|
|
|
2003-08-25 13:53:41 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* File access abstraction.
|
|
|
|
*/
|
|
|
|
|
2003-08-24 12:47:46 +00:00
|
|
|
/*
|
|
|
|
* Set local current directory. Returns NULL on success, or else an
|
|
|
|
* error message which must be freed after printing.
|
|
|
|
*/
|
|
|
|
char *psftp_lcd(char *dir)
|
|
|
|
{
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (!SetCurrentDirectory(dir)) {
|
2019-09-08 19:29:00 +00:00
|
|
|
LPVOID message;
|
|
|
|
int i;
|
|
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, GetLastError(),
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
(LPTSTR)&message, 0, NULL);
|
|
|
|
i = strcspn((char *)message, "\n");
|
|
|
|
ret = dupprintf("%.*s", i, (LPCTSTR)message);
|
|
|
|
LocalFree(message);
|
2003-08-24 12:47:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get local current directory. Returns a string which must be
|
|
|
|
* freed.
|
|
|
|
*/
|
|
|
|
char *psftp_getcwd(void)
|
|
|
|
{
|
|
|
|
char *ret = snewn(256, char);
|
New array-growing macros: sgrowarray and sgrowarrayn.
The idea of these is that they centralise the common idiom along the
lines of
if (logical_array_len >= physical_array_size) {
physical_array_size = logical_array_len * 5 / 4 + 256;
array = sresize(array, physical_array_size, ElementType);
}
which happens at a zillion call sites throughout this code base, with
different random choices of the geometric factor and additive
constant, sometimes forgetting them completely, and generally doing a
lot of repeated work.
The new macro sgrowarray(array,size,n) has the semantics: here are the
array pointer and its physical size for you to modify, now please
ensure that the nth element exists, so I can write into it. And
sgrowarrayn(array,size,n,m) is the same except that it ensures that
the array has size at least n+m (so sgrowarray is just the special
case where m=1).
Now that this is a single centralised implementation that will be used
everywhere, I've also gone to more effort in the implementation, with
careful overflow checks that would have been painful to put at all the
previous call sites.
This commit also switches over every use of sresize(), apart from a
few where I really didn't think it would gain anything. A consequence
of that is that a lot of array-size variables have to have their types
changed to size_t, because the macros require that (they address-take
the size to pass to the underlying function).
2019-02-28 20:07:30 +00:00
|
|
|
size_t len = GetCurrentDirectory(256, ret);
|
2003-08-24 12:47:46 +00:00
|
|
|
if (len > 256)
|
2019-09-08 19:29:00 +00:00
|
|
|
ret = sresize(ret, len, char);
|
2003-08-24 12:47:46 +00:00
|
|
|
GetCurrentDirectory(len, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-10-26 22:08:58 +00:00
|
|
|
static inline uint64_t uint64_from_words(uint32_t hi, uint32_t lo)
|
|
|
|
{
|
|
|
|
return (((uint64_t)hi) << 32) | lo;
|
|
|
|
}
|
|
|
|
|
2009-09-27 15:52:13 +00:00
|
|
|
#define TIME_POSIX_TO_WIN(t, ft) do { \
|
|
|
|
ULARGE_INTEGER uli; \
|
|
|
|
uli.QuadPart = ((ULONGLONG)(t) + 11644473600ull) * 10000000ull; \
|
|
|
|
(ft).dwLowDateTime = uli.LowPart; \
|
|
|
|
(ft).dwHighDateTime = uli.HighPart; \
|
2022-12-28 15:32:24 +00:00
|
|
|
} while (0)
|
2009-09-27 15:52:13 +00:00
|
|
|
#define TIME_WIN_TO_POSIX(ft, t) do { \
|
|
|
|
ULARGE_INTEGER uli; \
|
|
|
|
uli.LowPart = (ft).dwLowDateTime; \
|
|
|
|
uli.HighPart = (ft).dwHighDateTime; \
|
|
|
|
uli.QuadPart = uli.QuadPart / 10000000ull - 11644473600ull; \
|
|
|
|
(t) = (unsigned long) uli.QuadPart; \
|
2022-12-28 15:32:24 +00:00
|
|
|
} while (0)
|
2003-08-25 13:53:41 +00:00
|
|
|
|
|
|
|
struct RFile {
|
|
|
|
HANDLE h;
|
|
|
|
};
|
|
|
|
|
2018-10-26 22:08:58 +00:00
|
|
|
RFile *open_existing_file(const char *name, uint64_t *size,
|
2019-09-08 19:29:00 +00:00
|
|
|
unsigned long *mtime, unsigned long *atime,
|
2011-08-11 17:59:30 +00:00
|
|
|
long *perms)
|
2003-08-25 13:53:41 +00:00
|
|
|
{
|
|
|
|
HANDLE h;
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
RFile *f;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
|
|
|
h = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL,
|
2019-09-08 19:29:00 +00:00
|
|
|
OPEN_EXISTING, 0, 0);
|
2003-08-25 13:53:41 +00:00
|
|
|
if (h == INVALID_HANDLE_VALUE)
|
2019-09-08 19:29:00 +00:00
|
|
|
return NULL;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
f = snew(RFile);
|
|
|
|
f->h = h;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
2016-04-02 13:11:18 +00:00
|
|
|
if (size) {
|
|
|
|
DWORD lo, hi;
|
|
|
|
lo = GetFileSize(h, &hi);
|
2018-10-26 22:08:58 +00:00
|
|
|
*size = uint64_from_words(hi, lo);
|
2016-04-02 13:11:18 +00:00
|
|
|
}
|
2003-08-25 13:53:41 +00:00
|
|
|
|
|
|
|
if (mtime || atime) {
|
2019-09-08 19:29:00 +00:00
|
|
|
FILETIME actime, wrtime;
|
|
|
|
GetFileTime(h, NULL, &actime, &wrtime);
|
|
|
|
if (atime)
|
|
|
|
TIME_WIN_TO_POSIX(actime, *atime);
|
|
|
|
if (mtime)
|
|
|
|
TIME_WIN_TO_POSIX(wrtime, *mtime);
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
2011-08-11 17:59:30 +00:00
|
|
|
if (perms)
|
|
|
|
*perms = -1;
|
|
|
|
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
return f;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int read_from_file(RFile *f, void *buffer, int length)
|
|
|
|
{
|
2009-09-27 15:31:08 +00:00
|
|
|
DWORD read;
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
if (!ReadFile(f->h, buffer, length, &read, NULL))
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1; /* error */
|
2003-08-25 13:53:41 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
return read;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void close_rfile(RFile *f)
|
|
|
|
{
|
|
|
|
CloseHandle(f->h);
|
|
|
|
sfree(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct WFile {
|
|
|
|
HANDLE h;
|
|
|
|
};
|
|
|
|
|
2015-05-15 10:15:42 +00:00
|
|
|
WFile *open_new_file(const char *name, long perms)
|
2003-08-25 13:53:41 +00:00
|
|
|
{
|
|
|
|
HANDLE h;
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
WFile *f;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
|
|
|
h = CreateFile(name, GENERIC_WRITE, 0, NULL,
|
2019-09-08 19:29:00 +00:00
|
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
2003-08-25 13:53:41 +00:00
|
|
|
if (h == INVALID_HANDLE_VALUE)
|
2019-09-08 19:29:00 +00:00
|
|
|
return NULL;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
f = snew(WFile);
|
|
|
|
f->h = h;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
return f;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
2018-10-26 22:08:58 +00:00
|
|
|
WFile *open_existing_wfile(const char *name, uint64_t *size)
|
2006-08-12 15:20:19 +00:00
|
|
|
{
|
|
|
|
HANDLE h;
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
WFile *f;
|
2006-08-12 15:20:19 +00:00
|
|
|
|
|
|
|
h = CreateFile(name, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
2019-09-08 19:29:00 +00:00
|
|
|
OPEN_EXISTING, 0, 0);
|
2006-08-12 15:20:19 +00:00
|
|
|
if (h == INVALID_HANDLE_VALUE)
|
2019-09-08 19:29:00 +00:00
|
|
|
return NULL;
|
2006-08-12 15:20:19 +00:00
|
|
|
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
f = snew(WFile);
|
|
|
|
f->h = h;
|
2006-08-12 15:20:19 +00:00
|
|
|
|
2016-04-02 13:11:18 +00:00
|
|
|
if (size) {
|
|
|
|
DWORD lo, hi;
|
|
|
|
lo = GetFileSize(h, &hi);
|
2018-10-26 22:08:58 +00:00
|
|
|
*size = uint64_from_words(hi, lo);
|
2016-04-02 13:11:18 +00:00
|
|
|
}
|
2006-08-12 15:20:19 +00:00
|
|
|
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
return f;
|
2006-08-12 15:20:19 +00:00
|
|
|
}
|
|
|
|
|
2003-08-25 13:53:41 +00:00
|
|
|
int write_to_file(WFile *f, void *buffer, int length)
|
|
|
|
{
|
2009-09-27 15:31:08 +00:00
|
|
|
DWORD written;
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
if (!WriteFile(f->h, buffer, length, &written, NULL))
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1; /* error */
|
2003-08-25 13:53:41 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
return written;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_file_times(WFile *f, unsigned long mtime, unsigned long atime)
|
|
|
|
{
|
|
|
|
FILETIME actime, wrtime;
|
|
|
|
TIME_POSIX_TO_WIN(atime, actime);
|
|
|
|
TIME_POSIX_TO_WIN(mtime, wrtime);
|
|
|
|
SetFileTime(f->h, NULL, &actime, &wrtime);
|
|
|
|
}
|
|
|
|
|
|
|
|
void close_wfile(WFile *f)
|
|
|
|
{
|
|
|
|
CloseHandle(f->h);
|
|
|
|
sfree(f);
|
|
|
|
}
|
|
|
|
|
2006-08-12 15:20:19 +00:00
|
|
|
/* Seek offset bytes through file, from whence, where whence is
|
|
|
|
FROM_START, FROM_CURRENT, or FROM_END */
|
2018-10-26 22:08:58 +00:00
|
|
|
int seek_file(WFile *f, uint64_t offset, int whence)
|
2006-08-12 15:20:19 +00:00
|
|
|
{
|
|
|
|
DWORD movemethod;
|
|
|
|
|
|
|
|
switch (whence) {
|
2022-08-03 19:48:46 +00:00
|
|
|
case FROM_START:
|
2019-09-08 19:29:00 +00:00
|
|
|
movemethod = FILE_BEGIN;
|
|
|
|
break;
|
2022-08-03 19:48:46 +00:00
|
|
|
case FROM_CURRENT:
|
2019-09-08 19:29:00 +00:00
|
|
|
movemethod = FILE_CURRENT;
|
|
|
|
break;
|
2022-08-03 19:48:46 +00:00
|
|
|
case FROM_END:
|
2019-09-08 19:29:00 +00:00
|
|
|
movemethod = FILE_END;
|
|
|
|
break;
|
2022-08-03 19:48:46 +00:00
|
|
|
default:
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
2006-08-12 15:20:19 +00:00
|
|
|
}
|
|
|
|
|
2016-04-02 13:11:18 +00:00
|
|
|
{
|
2018-10-26 22:08:58 +00:00
|
|
|
LONG lo = offset & 0xFFFFFFFFU, hi = offset >> 32;
|
2016-04-02 13:11:18 +00:00
|
|
|
SetFilePointer(f->h, lo, &hi, movemethod);
|
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
|
2006-08-12 15:20:19 +00:00
|
|
|
if (GetLastError() != NO_ERROR)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return 0;
|
2006-08-12 15:20:19 +00:00
|
|
|
}
|
|
|
|
|
2018-10-26 22:08:58 +00:00
|
|
|
uint64_t get_file_posn(WFile *f)
|
2006-08-12 15:20:19 +00:00
|
|
|
{
|
2016-05-03 21:27:57 +00:00
|
|
|
LONG lo, hi = 0;
|
2006-08-12 15:20:19 +00:00
|
|
|
|
2016-04-02 13:11:18 +00:00
|
|
|
lo = SetFilePointer(f->h, 0L, &hi, FILE_CURRENT);
|
2018-10-26 22:08:58 +00:00
|
|
|
return uint64_from_words(hi, lo);
|
2006-08-12 15:20:19 +00:00
|
|
|
}
|
|
|
|
|
2015-05-15 10:15:42 +00:00
|
|
|
int file_type(const char *name)
|
2003-08-25 13:53:41 +00:00
|
|
|
{
|
|
|
|
DWORD attr;
|
|
|
|
attr = GetFileAttributes(name);
|
|
|
|
/* We know of no `weird' files under Windows. */
|
|
|
|
if (attr == (DWORD)-1)
|
2019-09-08 19:29:00 +00:00
|
|
|
return FILE_TYPE_NONEXISTENT;
|
2003-08-25 13:53:41 +00:00
|
|
|
else if (attr & FILE_ATTRIBUTE_DIRECTORY)
|
2019-09-08 19:29:00 +00:00
|
|
|
return FILE_TYPE_DIRECTORY;
|
2003-08-25 13:53:41 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
return FILE_TYPE_FILE;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct DirHandle {
|
|
|
|
HANDLE h;
|
|
|
|
char *name;
|
|
|
|
};
|
|
|
|
|
2018-12-27 16:52:23 +00:00
|
|
|
DirHandle *open_directory(const char *name, const char **errmsg)
|
2003-08-25 13:53:41 +00:00
|
|
|
{
|
|
|
|
HANDLE h;
|
|
|
|
WIN32_FIND_DATA fdat;
|
|
|
|
char *findfile;
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
DirHandle *dir;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
2004-10-13 12:10:30 +00:00
|
|
|
/* Enumerate files in dir `foo'. */
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
findfile = dupcat(name, "/*");
|
2003-08-25 13:53:41 +00:00
|
|
|
h = FindFirstFile(findfile, &fdat);
|
2018-12-27 16:52:23 +00:00
|
|
|
if (h == INVALID_HANDLE_VALUE) {
|
|
|
|
*errmsg = win_strerror(GetLastError());
|
2019-09-08 19:29:00 +00:00
|
|
|
return NULL;
|
2018-12-27 16:52:23 +00:00
|
|
|
}
|
2003-08-25 14:30:59 +00:00
|
|
|
sfree(findfile);
|
2003-08-25 13:53:41 +00:00
|
|
|
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
dir = snew(DirHandle);
|
|
|
|
dir->h = h;
|
|
|
|
dir->name = dupstr(fdat.cFileName);
|
|
|
|
return dir;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char *read_filename(DirHandle *dir)
|
|
|
|
{
|
2005-02-26 00:41:36 +00:00
|
|
|
do {
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (!dir->name) {
|
|
|
|
WIN32_FIND_DATA fdat;
|
|
|
|
if (!FindNextFile(dir->h, &fdat))
|
|
|
|
return NULL;
|
|
|
|
else
|
|
|
|
dir->name = dupstr(fdat.cFileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(dir->name);
|
|
|
|
if (dir->name[0] == '.' &&
|
|
|
|
(dir->name[1] == '\0' ||
|
|
|
|
(dir->name[1] == '.' && dir->name[2] == '\0'))) {
|
|
|
|
sfree(dir->name);
|
|
|
|
dir->name = NULL;
|
|
|
|
}
|
2005-02-26 00:41:36 +00:00
|
|
|
|
|
|
|
} while (!dir->name);
|
2003-08-25 13:53:41 +00:00
|
|
|
|
|
|
|
if (dir->name) {
|
2019-09-08 19:29:00 +00:00
|
|
|
char *ret = dir->name;
|
|
|
|
dir->name = NULL;
|
|
|
|
return ret;
|
2003-08-25 13:53:41 +00:00
|
|
|
} else
|
2019-09-08 19:29:00 +00:00
|
|
|
return NULL;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void close_directory(DirHandle *dir)
|
|
|
|
{
|
|
|
|
FindClose(dir->h);
|
|
|
|
if (dir->name)
|
2019-09-08 19:29:00 +00:00
|
|
|
sfree(dir->name);
|
2003-08-25 13:53:41 +00:00
|
|
|
sfree(dir);
|
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
int test_wildcard(const char *name, bool cmdline)
|
2003-08-25 13:53:41 +00:00
|
|
|
{
|
|
|
|
HANDLE fh;
|
|
|
|
WIN32_FIND_DATA fdat;
|
|
|
|
|
|
|
|
/* First see if the exact name exists. */
|
|
|
|
if (GetFileAttributes(name) != (DWORD)-1)
|
2019-09-08 19:29:00 +00:00
|
|
|
return WCTYPE_FILENAME;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
|
|
|
/* Otherwise see if a wildcard match finds anything. */
|
|
|
|
fh = FindFirstFile(name, &fdat);
|
|
|
|
if (fh == INVALID_HANDLE_VALUE)
|
2019-09-08 19:29:00 +00:00
|
|
|
return WCTYPE_NONEXISTENT;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
|
|
|
FindClose(fh);
|
|
|
|
return WCTYPE_WILDCARD;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct WildcardMatcher {
|
|
|
|
HANDLE h;
|
|
|
|
char *name;
|
|
|
|
char *srcpath;
|
|
|
|
};
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
char *stripslashes(const char *str, bool local)
|
2003-08-25 13:53:41 +00:00
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
2015-09-24 16:47:10 +00:00
|
|
|
/*
|
|
|
|
* On Windows, \ / : are all path component separators.
|
|
|
|
*/
|
|
|
|
|
2003-08-25 13:53:41 +00:00
|
|
|
if (local) {
|
|
|
|
p = strchr(str, ':');
|
|
|
|
if (p) str = p+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = strrchr(str, '/');
|
|
|
|
if (p) str = p+1;
|
|
|
|
|
|
|
|
if (local) {
|
2019-09-08 19:29:00 +00:00
|
|
|
p = strrchr(str, '\\');
|
|
|
|
if (p) str = p+1;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
2015-09-24 16:47:10 +00:00
|
|
|
return (char *)str;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
2015-05-15 10:15:42 +00:00
|
|
|
WildcardMatcher *begin_wildcard_matching(const char *name)
|
2003-08-25 13:53:41 +00:00
|
|
|
{
|
|
|
|
HANDLE h;
|
|
|
|
WIN32_FIND_DATA fdat;
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
WildcardMatcher *dir;
|
2003-08-25 13:53:41 +00:00
|
|
|
char *last;
|
|
|
|
|
|
|
|
h = FindFirstFile(name, &fdat);
|
|
|
|
if (h == INVALID_HANDLE_VALUE)
|
2019-09-08 19:29:00 +00:00
|
|
|
return NULL;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
dir = snew(WildcardMatcher);
|
|
|
|
dir->h = h;
|
|
|
|
dir->srcpath = dupstr(name);
|
|
|
|
last = stripslashes(dir->srcpath, true);
|
2003-08-25 13:53:41 +00:00
|
|
|
*last = '\0';
|
|
|
|
if (fdat.cFileName[0] == '.' &&
|
2019-09-08 19:29:00 +00:00
|
|
|
(fdat.cFileName[1] == '\0' ||
|
|
|
|
(fdat.cFileName[1] == '.' && fdat.cFileName[2] == '\0')))
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
dir->name = NULL;
|
2003-08-25 13:53:41 +00:00
|
|
|
else
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
dir->name = dupcat(dir->srcpath, fdat.cFileName);
|
2003-08-25 13:53:41 +00:00
|
|
|
|
Rename 'ret' variables passed from allocation to return.
I mentioned recently (in commit 9e7d4c53d80b6eb) message that I'm no
longer fond of the variable name 'ret', because it's used in two quite
different contexts: it's the return value from a subroutine you just
called (e.g. 'int ret = read(fd, buf, len);' and then check for error
or EOF), or it's the value you're preparing to return from the
_containing_ routine (maybe by assigning it a default value and then
conditionally modifying it, or by starting at NULL and reallocating,
or setting it just before using the 'goto out' cleanup idiom). In the
past I've occasionally made mistakes by forgetting which meaning the
variable had, or accidentally conflating both uses.
If all else fails, I now prefer 'retd' (short for 'returned') in the
former situation, and 'toret' (obviously, the value 'to return') in
the latter case. But even better is to pick a name that actually says
something more specific about what the thing actually is.
One particular bad habit throughout this codebase is to have a set of
functions that deal with some object type (say 'Foo'), all *but one*
of which take a 'Foo *foo' parameter, but the foo_new() function
starts with 'Foo *ret = snew(Foo)'. If all the rest of them think the
canonical name for the ambient Foo is 'foo', so should foo_new()!
So here's a no-brainer start on cutting down on the uses of 'ret': I
looked for all the cases where it was being assigned the result of an
allocation, and renamed the variable to be a description of the thing
being allocated. In the case of a new() function belonging to a
family, I picked the same name as the rest of the functions in its own
family, for consistency. In other cases I picked something sensible.
One case where it _does_ make sense not to use your usual name for the
variable type is when you're cloning an existing object. In that case,
_neither_ of the Foo objects involved should be called 'foo', because
it's ambiguous! They should be named so you can see which is which. In
the two cases I found here, I've called them 'orig' and 'copy'.
As in the previous refactoring, many thanks to clang-rename for the
help.
2022-09-13 13:53:36 +00:00
|
|
|
return dir;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char *wildcard_get_filename(WildcardMatcher *dir)
|
|
|
|
{
|
|
|
|
while (!dir->name) {
|
2019-09-08 19:29:00 +00:00
|
|
|
WIN32_FIND_DATA fdat;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (!FindNextFile(dir->h, &fdat))
|
|
|
|
return NULL;
|
2003-08-25 13:53:41 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (fdat.cFileName[0] == '.' &&
|
|
|
|
(fdat.cFileName[1] == '\0' ||
|
|
|
|
(fdat.cFileName[1] == '.' && fdat.cFileName[2] == '\0')))
|
|
|
|
dir->name = NULL;
|
|
|
|
else
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
dir->name = dupcat(dir->srcpath, fdat.cFileName);
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dir->name) {
|
2019-09-08 19:29:00 +00:00
|
|
|
char *ret = dir->name;
|
|
|
|
dir->name = NULL;
|
|
|
|
return ret;
|
2003-08-25 13:53:41 +00:00
|
|
|
} else
|
2019-09-08 19:29:00 +00:00
|
|
|
return NULL;
|
2003-08-25 13:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void finish_wildcard_matching(WildcardMatcher *dir)
|
|
|
|
{
|
|
|
|
FindClose(dir->h);
|
|
|
|
if (dir->name)
|
2019-09-08 19:29:00 +00:00
|
|
|
sfree(dir->name);
|
2003-08-25 13:53:41 +00:00
|
|
|
sfree(dir->srcpath);
|
|
|
|
sfree(dir);
|
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool vet_filename(const char *name)
|
2004-12-16 19:36:47 +00:00
|
|
|
{
|
|
|
|
if (strchr(name, '/') || strchr(name, '\\') || strchr(name, ':'))
|
2019-09-08 19:29:00 +00:00
|
|
|
return false;
|
2004-12-16 19:36:47 +00:00
|
|
|
|
|
|
|
if (!name[strspn(name, ".")]) /* entirely composed of dots */
|
2019-09-08 19:29:00 +00:00
|
|
|
return false;
|
2004-12-16 19:36:47 +00:00
|
|
|
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2004-12-16 19:36:47 +00:00
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool create_directory(const char *name)
|
2003-08-25 13:53:41 +00:00
|
|
|
{
|
|
|
|
return CreateDirectory(name, NULL) != 0;
|
|
|
|
}
|
|
|
|
|
2015-05-15 10:15:42 +00:00
|
|
|
char *dir_file_cat(const char *dir, const char *file)
|
2003-08-25 14:30:59 +00:00
|
|
|
{
|
2019-03-09 16:15:51 +00:00
|
|
|
ptrlen dir_pl = ptrlen_from_asciz(dir);
|
|
|
|
return dupcat(
|
|
|
|
dir, (ptrlen_endswith(dir_pl, PTRLEN_LITERAL("\\"), NULL) ||
|
|
|
|
ptrlen_endswith(dir_pl, PTRLEN_LITERAL("/"), NULL)) ? "" : "\\",
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
file);
|
2003-08-25 14:30:59 +00:00
|
|
|
}
|
|
|
|
|
2003-08-25 13:53:41 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Platform-specific network handling.
|
|
|
|
*/
|
2020-02-07 19:15:13 +00:00
|
|
|
struct winsftp_cliloop_ctx {
|
|
|
|
HANDLE other_event;
|
|
|
|
int toret;
|
|
|
|
};
|
|
|
|
static bool winsftp_cliloop_pre(void *vctx, const HANDLE **extra_handles,
|
|
|
|
size_t *n_extra_handles)
|
2004-11-27 13:20:21 +00:00
|
|
|
{
|
2020-02-07 19:15:13 +00:00
|
|
|
struct winsftp_cliloop_ctx *ctx = (struct winsftp_cliloop_ctx *)vctx;
|
2006-08-25 22:10:16 +00:00
|
|
|
|
2020-02-07 19:15:13 +00:00
|
|
|
if (ctx->other_event != INVALID_HANDLE_VALUE) {
|
|
|
|
*extra_handles = &ctx->other_event;
|
|
|
|
*n_extra_handles = 1;
|
2004-11-27 13:20:21 +00:00
|
|
|
}
|
|
|
|
|
2020-02-07 19:15:13 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
static bool winsftp_cliloop_post(void *vctx, size_t extra_handle_index)
|
|
|
|
{
|
|
|
|
struct winsftp_cliloop_ctx *ctx = (struct winsftp_cliloop_ctx *)vctx;
|
2004-11-27 13:20:21 +00:00
|
|
|
|
2020-02-07 19:15:13 +00:00
|
|
|
if (ctx->other_event != INVALID_HANDLE_VALUE &&
|
|
|
|
extra_handle_index == 0)
|
|
|
|
ctx->toret = 1; /* other_event was set */
|
2004-11-27 13:20:21 +00:00
|
|
|
|
2020-02-07 19:15:13 +00:00
|
|
|
return false; /* always run only one loop iteration */
|
|
|
|
}
|
|
|
|
int do_eventsel_loop(HANDLE other_event)
|
|
|
|
{
|
|
|
|
struct winsftp_cliloop_ctx ctx[1];
|
|
|
|
ctx->other_event = other_event;
|
|
|
|
ctx->toret = 0;
|
|
|
|
cli_main_loop(winsftp_cliloop_pre, winsftp_cliloop_post, ctx);
|
|
|
|
return ctx->toret;
|
2004-11-27 13:20:21 +00:00
|
|
|
}
|
|
|
|
|
2003-08-24 12:47:46 +00:00
|
|
|
/*
|
|
|
|
* Wait for some network data and process it.
|
2004-11-27 13:20:21 +00:00
|
|
|
*
|
|
|
|
* We have two variants of this function. One uses select() so that
|
|
|
|
* it's compatible with WinSock 1. The other uses WSAEventSelect
|
|
|
|
* and MsgWaitForMultipleObjects, so that we can consistently use
|
|
|
|
* WSAEventSelect throughout; this enables us to also implement
|
|
|
|
* ssh_sftp_get_cmdline() using a parallel mechanism.
|
2003-08-24 12:47:46 +00:00
|
|
|
*/
|
|
|
|
int ssh_sftp_loop_iteration(void)
|
|
|
|
{
|
2004-11-27 13:20:21 +00:00
|
|
|
if (p_WSAEventSelect == NULL) {
|
2019-09-08 19:29:00 +00:00
|
|
|
fd_set readfds;
|
|
|
|
int ret;
|
|
|
|
unsigned long now = GETTICKCOUNT(), then;
|
2020-01-01 11:10:22 +00:00
|
|
|
SOCKET skt = winselcli_unique_socket();
|
2019-09-08 19:29:00 +00:00
|
|
|
|
2020-01-01 11:10:22 +00:00
|
|
|
if (skt == INVALID_SOCKET)
|
2019-09-08 19:29:00 +00:00
|
|
|
return -1; /* doom */
|
|
|
|
|
2020-01-01 11:10:22 +00:00
|
|
|
if (socket_writable(skt))
|
|
|
|
select_result((WPARAM) skt, (LPARAM) FD_WRITE);
|
2019-09-08 19:29:00 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
unsigned long next;
|
|
|
|
long ticks;
|
|
|
|
struct timeval tv, *ptv;
|
|
|
|
|
|
|
|
if (run_timers(now, &next)) {
|
|
|
|
then = now;
|
|
|
|
now = GETTICKCOUNT();
|
|
|
|
if (now - then > next - then)
|
|
|
|
ticks = 0;
|
|
|
|
else
|
|
|
|
ticks = next - now;
|
|
|
|
tv.tv_sec = ticks / 1000;
|
|
|
|
tv.tv_usec = ticks % 1000 * 1000;
|
|
|
|
ptv = &tv;
|
|
|
|
} else {
|
|
|
|
ptv = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
FD_ZERO(&readfds);
|
2020-01-01 11:10:22 +00:00
|
|
|
FD_SET(skt, &readfds);
|
2019-09-08 19:29:00 +00:00
|
|
|
ret = p_select(1, &readfds, NULL, NULL, ptv);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
return -1; /* doom */
|
|
|
|
else if (ret == 0)
|
|
|
|
now = next;
|
|
|
|
else
|
|
|
|
now = GETTICKCOUNT();
|
|
|
|
|
|
|
|
} while (ret == 0);
|
|
|
|
|
2020-01-01 11:10:22 +00:00
|
|
|
select_result((WPARAM) skt, (LPARAM) FD_READ);
|
2019-09-08 19:29:00 +00:00
|
|
|
|
|
|
|
return 0;
|
2004-11-27 13:20:21 +00:00
|
|
|
} else {
|
2019-09-08 19:29:00 +00:00
|
|
|
return do_eventsel_loop(INVALID_HANDLE_VALUE);
|
2004-11-27 13:20:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read a command line from standard input.
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2004-11-27 13:20:21 +00:00
|
|
|
* In the presence of WinSock 2, we can use WSAEventSelect to
|
|
|
|
* mediate between the socket and stdin, meaning we can send
|
|
|
|
* keepalives and respond to server events even while waiting at
|
|
|
|
* the PSFTP command prompt. Without WS2, we fall back to a simple
|
|
|
|
* fgets.
|
|
|
|
*/
|
|
|
|
struct command_read_ctx {
|
|
|
|
HANDLE event;
|
|
|
|
char *line;
|
|
|
|
};
|
|
|
|
|
|
|
|
static DWORD WINAPI command_read_thread(void *param)
|
|
|
|
{
|
|
|
|
struct command_read_ctx *ctx = (struct command_read_ctx *) param;
|
|
|
|
|
|
|
|
ctx->line = fgetline(stdin);
|
|
|
|
|
|
|
|
SetEvent(ctx->event);
|
2003-08-24 12:47:46 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
char *ssh_sftp_get_cmdline(const char *prompt, bool no_fds_ok)
|
2004-11-27 13:20:21 +00:00
|
|
|
{
|
|
|
|
int ret;
|
2019-12-22 08:15:52 +00:00
|
|
|
struct command_read_ctx ctx[1];
|
2004-11-27 13:20:21 +00:00
|
|
|
DWORD threadid;
|
2014-12-20 18:42:22 +00:00
|
|
|
HANDLE hThread;
|
2004-11-27 13:20:21 +00:00
|
|
|
|
|
|
|
fputs(prompt, stdout);
|
|
|
|
fflush(stdout);
|
|
|
|
|
2020-01-01 11:10:22 +00:00
|
|
|
if ((winselcli_unique_socket() == INVALID_SOCKET && no_fds_ok) ||
|
2019-09-08 19:29:00 +00:00
|
|
|
p_WSAEventSelect == NULL) {
|
|
|
|
return fgetline(stdin); /* very simple */
|
2004-11-27 13:20:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a second thread to read from stdin. Process network
|
|
|
|
* and timing events until it terminates.
|
|
|
|
*/
|
2018-10-29 19:50:29 +00:00
|
|
|
ctx->event = CreateEvent(NULL, false, false, NULL);
|
2004-11-27 13:20:21 +00:00
|
|
|
ctx->line = NULL;
|
|
|
|
|
2014-12-20 18:42:22 +00:00
|
|
|
hThread = CreateThread(NULL, 0, command_read_thread, ctx, 0, &threadid);
|
|
|
|
if (!hThread) {
|
2019-09-08 19:29:00 +00:00
|
|
|
CloseHandle(ctx->event);
|
|
|
|
fprintf(stderr, "Unable to create command input thread\n");
|
|
|
|
cleanup_exit(1);
|
2004-11-27 13:20:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2019-09-08 19:29:00 +00:00
|
|
|
ret = do_eventsel_loop(ctx->event);
|
2004-11-27 13:20:21 +00:00
|
|
|
|
winsftp.c: avoid creating multiple netevents.
The do_select function is called with a boolean parameter indicating
whether we're supposed to start or stop paying attention to network
activity on a given socket. So if we freeze and unfreeze the socket in
mid-session because of backlog, we'll call do_select(s, false) to
freeze it, and do_select(s, true) to unfreeze it.
But the implementation of do_select in the Windows SFTP code predated
the rigorous handling of socket backlogs, so it assumed that
do_select(s, true) would only be called at initialisation time, i.e.
only once, and therefore that it was safe to use that flag as a cue to
set up the Windows event object to associate with socket activity.
Hence, every time the socket was frozen and unfrozen, we would create
a new netevent at unfreeze time, leaking the old one.
I think perhaps part of the reason why that was hard to figure out was
that the boolean parameter was called 'startup' rather than 'enable'.
To make it less confusing the next time I read this code, I've also
renamed it, and while I was at it, adjusted another related comment.
2019-12-21 13:31:02 +00:00
|
|
|
/* do_eventsel_loop can't return an error (unlike
|
|
|
|
* ssh_sftp_loop_iteration, which can return -1 if select goes
|
|
|
|
* wrong or if the socket doesn't exist). */
|
2019-09-08 19:29:00 +00:00
|
|
|
assert(ret >= 0);
|
2004-11-27 13:20:21 +00:00
|
|
|
} while (ret == 0);
|
|
|
|
|
2014-12-20 18:42:22 +00:00
|
|
|
CloseHandle(hThread);
|
|
|
|
CloseHandle(ctx->event);
|
|
|
|
|
2004-11-27 13:20:21 +00:00
|
|
|
return ctx->line;
|
|
|
|
}
|
|
|
|
|
Remove FLAG_VERBOSE.
The global 'int flags' has always been an ugly feature of this code
base, and I suddenly thought that perhaps it's time to start throwing
it out, one flag at a time, until it's totally unused.
My first target is FLAG_VERBOSE. This was usually set by cmdline.c
when it saw a -v option on the program's command line, except that GUI
PuTTY itself sets it unconditionally on startup. And then various bits
of the code would check it in order to decide whether to print a given
message.
In the current system of front-end abstraction traits, there's no
_one_ place that I can move it to. But there are two: every place that
checked FLAG_VERBOSE has access to either a Seat or a LogPolicy. So
now each of those traits has a query method for 'do I want verbose
messages?'.
A good effect of this is that subsidiary Seats, like the ones used in
Uppity for the main SSH server module itself and the server end of
shell channels, now get to have their own verbosity setting instead of
inheriting the one global one. In fact I don't expect any code using
those Seats to be generating any messages at all, but if that changes
later, we'll have a way to control it. (Who knows, perhaps logging in
Uppity might become a thing.)
As part of this cleanup, I've added a new flag to cmdline_tooltype,
called TOOLTYPE_NO_VERBOSE_OPTION. The unconditionally-verbose tools
now set that, and it has the effect of making cmdline.c disallow -v
completely. So where 'putty -v' would previously have been silently
ignored ("I was already verbose"), it's now an error, reminding you
that that option doesn't actually do anything.
Finally, the 'default_logpolicy' provided by uxcons.c and wincons.c
(with identical definitions) has had to move into a new file of its
own, because now it has to ask cmdline.c for the verbosity setting as
well as asking console.c for the rest of its methods. So there's a new
file clicons.c which can only be included by programs that link
against both cmdline.c _and_ one of the *cons.c, and I've renamed the
logpolicy to reflect that.
2020-01-30 06:40:21 +00:00
|
|
|
void platform_psftp_pre_conn_setup(LogPolicy *lp)
|
2016-04-02 07:00:07 +00:00
|
|
|
{
|
2020-02-02 10:00:42 +00:00
|
|
|
if (restricted_acl()) {
|
Remove FLAG_VERBOSE.
The global 'int flags' has always been an ugly feature of this code
base, and I suddenly thought that perhaps it's time to start throwing
it out, one flag at a time, until it's totally unused.
My first target is FLAG_VERBOSE. This was usually set by cmdline.c
when it saw a -v option on the program's command line, except that GUI
PuTTY itself sets it unconditionally on startup. And then various bits
of the code would check it in order to decide whether to print a given
message.
In the current system of front-end abstraction traits, there's no
_one_ place that I can move it to. But there are two: every place that
checked FLAG_VERBOSE has access to either a Seat or a LogPolicy. So
now each of those traits has a query method for 'do I want verbose
messages?'.
A good effect of this is that subsidiary Seats, like the ones used in
Uppity for the main SSH server module itself and the server end of
shell channels, now get to have their own verbosity setting instead of
inheriting the one global one. In fact I don't expect any code using
those Seats to be generating any messages at all, but if that changes
later, we'll have a way to control it. (Who knows, perhaps logging in
Uppity might become a thing.)
As part of this cleanup, I've added a new flag to cmdline_tooltype,
called TOOLTYPE_NO_VERBOSE_OPTION. The unconditionally-verbose tools
now set that, and it has the effect of making cmdline.c disallow -v
completely. So where 'putty -v' would previously have been silently
ignored ("I was already verbose"), it's now an error, reminding you
that that option doesn't actually do anything.
Finally, the 'default_logpolicy' provided by uxcons.c and wincons.c
(with identical definitions) has had to move into a new file of its
own, because now it has to ask cmdline.c for the verbosity setting as
well as asking console.c for the rest of its methods. So there's a new
file clicons.c which can only be included by programs that link
against both cmdline.c _and_ one of the *cons.c, and I've renamed the
logpolicy to reflect that.
2020-01-30 06:40:21 +00:00
|
|
|
lp_eventlog(lp, "Running with restricted process ACL");
|
2017-02-11 00:44:00 +00:00
|
|
|
}
|
2016-04-02 07:00:07 +00:00
|
|
|
}
|
|
|
|
|
2003-08-25 13:53:41 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
2003-08-24 12:47:46 +00:00
|
|
|
* Main program. Parse arguments etc.
|
|
|
|
*/
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2016-07-18 19:02:32 +00:00
|
|
|
dll_hijacking_protection();
|
Arm: turn on PSTATE.DIT if available and needed.
DIT, for 'Data-Independent Timing', is a bit you can set in the
processor state on sufficiently new Arm CPUs, which promises that a
long list of instructions will deliberately avoid varying their timing
based on the input register values. Just what you want for keeping
your constant-time crypto primitives constant-time.
As far as I'm aware, no CPU has _yet_ implemented any data-dependent
optimisations, so DIT is a safety precaution against them doing so in
future. It would be embarrassing to be caught without it if a future
CPU does do that, so we now turn on DIT in the PuTTY process state.
I've put a call to the new enable_dit() function at the start of every
main() and WinMain() belonging to a program that might do
cryptography (even testcrypt, in case someone uses it for something!),
and in case I missed one there, also added a second call at the first
moment that any cryptography-using part of the code looks as if it
might become active: when an instance of the SSH protocol object is
configured, when the system PRNG is initialised, and when selecting
any cryptographic authentication protocol in an HTTP or SOCKS proxy
connection. With any luck those precautions between them should ensure
it's on whenever we need it.
Arm's own recommendation is that you should carefully choose the
granularity at which you enable and disable DIT: there's a potential
time cost to turning it on and off (I'm not sure what, but plausibly
something of the order of a pipeline flush), so it's a performance hit
to do it _inside_ each individual crypto function, but if CPUs start
supporting significant data-dependent optimisation in future, then it
will also become a noticeable performance hit to just leave it on
across the whole process. So you'd like to do it somewhere in the
middle: for example, you might turn on DIT once around the whole
process of verifying and decrypting an SSH packet, instead of once for
decryption and once for MAC.
With all respect to that recommendation as a strategy for maximum
performance, I'm not following it here. I turn on DIT at the start of
the PuTTY process, and then leave it on. Rationale:
1. PuTTY is not otherwise a performance-critical application: it's
not likely to max out your CPU for any purpose _other_ than
cryptography. The most CPU-intensive non-cryptographic thing I can
imagine a PuTTY process doing is the complicated computation of
font rendering in the terminal, and that will normally be cached
(you don't recompute each glyph from its outline and hints for
every time you display it).
2. I think a bigger risk lies in accidental side channels from having
DIT turned off when it should have been on. I can imagine lots of
causes for that. Missing a crypto operation in some unswept corner
of the code; confusing control flow (like my coroutine macros)
jumping with DIT clear into the middle of a region of code that
expected DIT to have been set at the beginning; having a reference
counter of DIT requests and getting it out of sync.
In a more sophisticated programming language, it might be possible to
avoid the risk in #2 by cleverness with the type system. For example,
in Rust, you could have a zero-sized type that acts as a proof token
for DIT being enabled (it would be constructed by a function that also
sets DIT, have a Drop implementation that clears DIT, and be !Send so
you couldn't use it in a thread other than the one where DIT was set),
and then you could require all the actual crypto functions to take a
DitToken as an extra parameter, at zero runtime cost. Then "oops I
forgot to set DIT around this piece of crypto" would become a compile
error. Even so, you'd have to take some care with coroutine-structured
code (what happens if a Rust async function yields while holding a DIT
token?) and with nesting (if you have two DIT tokens, you don't want
dropping the inner one to clear DIT while the outer one is still there
to wrongly convince callees that it's set). Maybe in Rust you could
get this all to work reliably. But not in C!
DIT is an optional feature of the Arm architecture, so we must first
test to see if it's supported. This is done the same way as we already
do for the various Arm crypto accelerators: on ELF-based systems,
check the appropriate bit in the 'hwcap' words in the ELF aux vector;
on Mac, look for an appropriate sysctl flag.
On Windows I don't know of a way to query the DIT feature, _or_ of a
way to write the necessary enabling instruction in an MSVC-compatible
way. I've _heard_ that it might not be necessary, because Windows
might just turn on DIT unconditionally and leave it on, in an even
more extreme version of my own strategy. I don't have a source for
that - I heard it by word of mouth - but I _hope_ it's true, because
that would suit me very well! Certainly I can't write code to enable
DIT without knowing (a) how to do it, (b) how to know if it's safe.
Nonetheless, I've put the enable_dit() call in all the right places in
the Windows main programs as well as the Unix and cross-platform code,
so that if I later find out that I _can_ put in an explicit enable of
DIT in some way, I'll only have to arrange to set HAVE_ARM_DIT and
compile the enable_dit() function appropriately.
2024-12-19 08:47:08 +00:00
|
|
|
enable_dit();
|
2016-07-18 19:02:32 +00:00
|
|
|
|
New abstraction for command-line arguments.
This begins the process of enabling our Windows applications to handle
Unicode characters on their command lines which don't fit in the
system code page.
Instead of passing plain strings to cmdline_process_param, we now pass
a partially opaque and platform-specific thing called a CmdlineArg.
This has a method that extracts the argument word as a default-encoded
string, and another one that tries to extract it as UTF-8 (though it
may fail if the UTF-8 isn't available).
On Windows, the command line is now constructed by calling
split_into_argv_w on the Unicode command line returned by
GetCommandLineW(), and the UTF-8 method returns text converted
directly from that wide-character form, not going via the system code
page. So it _can_ include UTF-8 characters that wouldn't have
round-tripped via CP_ACP.
This commit introduces the abstraction and switches over the
cross-platform and Windows argv-handling code to use it, with minimal
functional change. Nothing yet tries to call cmdline_arg_get_utf8().
I say 'cross-platform and Windows' because on the Unix side there's
still a lot of use of plain old argv which I haven't converted. That
would be a much larger project, and isn't currently needed: the
_current_ aim of this abstraction is to get the right things to happen
relating to Unicode on Windows, so for code that doesn't run on
Windows anyway, it's not adding value. (Also there's a tension with
GTK, which wants to talk to standard argv and extract arguments _it_
knows about, so at the very least we'd have to let it munge argv
before importing it into this new system.)
2024-09-25 09:18:38 +00:00
|
|
|
CmdlineArgList *arglist = cmdline_arg_list_from_GetCommandLineW();
|
|
|
|
ret = psftp_main(arglist);
|
2003-08-24 12:47:46 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|