SCP: Make COPY command more robust

This commit is contained in:
Mark Pizzolato 2017-04-07 14:35:04 -07:00
parent 64376cad58
commit 7317645dd7
3 changed files with 123 additions and 27 deletions

73
scp.c
View file

@ -5352,41 +5352,60 @@ if (stat == SCPE_OK)
return sim_messagef (SCPE_ARG, "No such file or directory: %s\n", cptr); return sim_messagef (SCPE_ARG, "No such file or directory: %s\n", cptr);
} }
typedef struct {
t_stat stat;
int count;
char destname[CBUFSIZE];
} COPY_CTX;
static void sim_copy_entry (const char *directory,
const char *filename,
t_offset FileSize,
const struct stat *filestat,
void *context)
{
COPY_CTX *ctx = (COPY_CTX *)context;
struct stat deststat;
char FullPath[PATH_MAX + 1];
char dname[CBUFSIZE];\
t_stat st;
sim_strlcpy (dname, ctx->destname, sizeof (dname));
sprintf (FullPath, "%s%s", directory, filename);
if ((dname[strlen (dname) - 1] == '/') || (dname[strlen (dname) - 1] == '\\'))
dname[strlen (dname) - 1] = '\0';
if ((!stat (dname, &deststat)) && (deststat.st_mode & S_IFDIR)) {
char *dslash = (strrchr (dname, '/') ? "/" : (strrchr (dname, '\\') ? "\\" : "/"));
dname[sizeof (dname) - 1] = '\0';
snprintf (&dname[strlen (dname)], sizeof (dname) - strlen (dname), "%s%s", dslash, filename);
}
st = sim_copyfile (FullPath, dname, TRUE);
if (SCPE_OK == st)
++ctx->count;
else
ctx->stat = st;
}
t_stat copy_cmd (int32 flg, CONST char *cptr) t_stat copy_cmd (int32 flg, CONST char *cptr)
{ {
char sname[CBUFSIZE], dname[CBUFSIZE]; char sname[CBUFSIZE];
FILE *fIn = NULL, *fOut = NULL; COPY_CTX copy_state;
t_stat stat = SCPE_OK; t_stat stat;
char *buf = NULL;
size_t bytes;
memset (&copy_state, 0, sizeof (copy_state));
if ((!cptr) || (*cptr == 0)) if ((!cptr) || (*cptr == 0))
return SCPE_2FARG; return SCPE_2FARG;
cptr = get_glyph_quoted (cptr, sname, 0); cptr = get_glyph_quoted (cptr, sname, 0);
if ((!cptr) || (*cptr == 0)) if ((!cptr) || (*cptr == 0))
return SCPE_2FARG; return SCPE_2FARG;
cptr = get_glyph_quoted (cptr, dname, 0); cptr = get_glyph_quoted (cptr, copy_state.destname, 0);
fIn = sim_fopen (sname, "rb"); stat = sim_dir_scan (sname, sim_copy_entry, &copy_state);
if (!fIn) { if ((stat == SCPE_OK) && (copy_state.count))
stat = sim_messagef (SCPE_ARG, "Can't open '%s' for input: %s\n", sname, strerror (errno)); return sim_messagef (SCPE_OK, " %3d file(s) copied\n", copy_state.count);
goto Cleanup_Return; return copy_state.stat;
}
fOut = sim_fopen (dname, "wb");
if (!fOut) {
stat = sim_messagef (SCPE_ARG, "Can't open '%s' for output: %s\n", dname, strerror (errno));
goto Cleanup_Return;
}
buf = malloc (BUFSIZ);
while (bytes = fread (buf, 1, BUFSIZ, fIn))
fwrite (buf, 1, bytes, fOut);
stat = sim_messagef (SCPE_OK, " 1 file copied\n");
Cleanup_Return:
free (buf);
if (fIn)
fclose (fIn);
if (fOut)
fclose (fOut);
return stat;
} }
/* Breakpoint commands */ /* Breakpoint commands */

View file

@ -375,6 +375,34 @@ return sim_fseeko (st, (t_offset)offset, whence);
} }
#if defined(_WIN32) #if defined(_WIN32)
static const char *
GetErrorText(DWORD dwError)
{
static char szMsgBuffer[2048];
DWORD dwStatus;
dwStatus = FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM|
FORMAT_MESSAGE_IGNORE_INSERTS, // __in DWORD dwFlags,
NULL, // __in_opt LPCVOID lpSource,
dwError, // __in DWORD dwMessageId,
0, // __in DWORD dwLanguageId,
szMsgBuffer, // __out LPTSTR lpBuffer,
sizeof (szMsgBuffer) -1, // __in DWORD nSize,
NULL); // __in_opt va_list *Arguments
if (0 == dwStatus)
snprintf(szMsgBuffer, sizeof(szMsgBuffer) - 1, "Error Code: %d", dwError);
while (sim_isspace (szMsgBuffer[strlen (szMsgBuffer)-1]))
szMsgBuffer[strlen (szMsgBuffer) - 1] = '\0';
return szMsgBuffer;
}
t_stat sim_copyfile (const char *source_file, const char *dest_file, t_bool overwrite_existing)
{
if (CopyFileA (source_file, dest_file, !overwrite_existing))
return SCPE_OK;
return sim_messagef (SCPE_ARG, "Error Copying '%s' to '%s': %s\n", source_file, dest_file, GetErrorText (GetLastError ()));
}
#include <io.h> #include <io.h>
int sim_set_fsize (FILE *fptr, t_addr size) int sim_set_fsize (FILE *fptr, t_addr size)
{ {
@ -439,6 +467,54 @@ return ftruncate(fileno(fptr), (off_t)size);
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#if HAVE_UTIME
#include <utime.h>
#endif
t_stat sim_copyfile (const char *source_file, const char *dest_file, t_bool overwrite_existing)
{
FILE *fIn = NULL, *fOut = NULL;
t_stat st = SCPE_OK;
char *buf = NULL;
size_t bytes;
fIn = sim_fopen (source_file, "rb");
if (!fIn) {
st = sim_messagef (SCPE_ARG, "Can't open '%s' for input: %s\n", source_file, strerror (errno));
goto Cleanup_Return;
}
fOut = sim_fopen (dest_file, "wb");
if (!fOut) {
st = sim_messagef (SCPE_ARG, "Can't open '%s' for output: %s\n", dest_file, strerror (errno));
goto Cleanup_Return;
}
buf = malloc (BUFSIZ);
while ((bytes = fread (buf, 1, BUFSIZ, fIn)))
fwrite (buf, 1, bytes, fOut);
Cleanup_Return:
free (buf);
if (fIn)
fclose (fIn);
if (fOut)
fclose (fOut);
#if defined(HAVE_UTIME)
if (st == SCPE_OK) {
struct stat statb;
if (!stat (source_file, &statb)) {
struct utimbuf utim;
utim.actime = statb.st_atime;
utim.modtime = statb.st_mtime;
if (utime (dest_file, &utim))
st = SCPE_IOERR;
}
else
st = SCPE_IOERR;
}
#endif
return st;
}
int sim_set_fifo_nonblock (FILE *fptr) int sim_set_fifo_nonblock (FILE *fptr)
{ {

View file

@ -66,6 +66,7 @@ uint32 sim_fsize_name (const char *fname);
t_offset sim_ftell (FILE *st); t_offset sim_ftell (FILE *st);
t_offset sim_fsize_ex (FILE *fptr); t_offset sim_fsize_ex (FILE *fptr);
t_offset sim_fsize_name_ex (const char *fname); t_offset sim_fsize_name_ex (const char *fname);
t_stat sim_copyfile (const char *source_file, const char *dest_file, t_bool overwrite_existing);
void sim_buf_swap_data (void *bptr, size_t size, size_t count); void sim_buf_swap_data (void *bptr, size_t size, size_t count);
void sim_buf_copy_swapped (void *dptr, const void *bptr, size_t size, size_t count); void sim_buf_copy_swapped (void *dptr, const void *bptr, size_t size, size_t count);
typedef struct SHMEM SHMEM; typedef struct SHMEM SHMEM;