@@ -357,6 +357,7 @@ static void ShowCommands(void)
357357 printf ("\n\nCommands :\n" );
358358 printf ("\tcd <string> change directory\n" );
359359 printf ("\tchmod <mode> <path> change mode\n" );
360+ printf ("\tcreat <mode> <path> create file with given permissions\n" );
360361 printf ("\tget <remote file> <local file> pulls file(s) from server\n" );
361362 printf ("\tlcd <path> change local directory\n" );
362363 printf ("\tlls list local directory\n" );
@@ -433,6 +434,76 @@ static INLINE char* SFTP_FGETS(func_args* args, char* msg, int msgSz)
433434}
434435
435436
437+ /*
438+ * Parse "<mode> <path>" from a SFTP command argument string.
439+ * pt: points past the command keyword (caller advanced by sizeof).
440+ * modeBuf: caller buffer of WOLFSSH_MAX_OCTET_LEN bytes; receives the
441+ * null-terminated octal mode token on success.
442+ * pathOut: receives a pointer to the resolved remote path on success.
443+ * allocOut: receives a malloc'd absolute-path buffer when pt was relative
444+ * (caller must WFREE); NULL when the path was already absolute.
445+ * remoteDir: current remote working directory.
446+ * Returns 0 on success,
447+ * 1 if no mode token found (caller prints error and continues),
448+ * -1 on malloc failure (caller returns -1).
449+ */
450+ static int sftpParseModeAndPath (char * pt , char * modeBuf , char * * pathOut ,
451+ char * * allocOut , const char * remoteDir )
452+ {
453+ word32 sz , idx ;
454+ char * f ;
455+
456+ * allocOut = NULL ;
457+ * pathOut = NULL ;
458+
459+ sz = (word32 )WSTRLEN (pt );
460+ if (sz > 0 && pt [sz - 1 ] == '\n' ) {
461+ pt [sz - 1 ] = '\0' ;
462+ sz -- ;
463+ }
464+
465+ for (idx = 0 ; idx < sz && pt [0 ] == ' ' ; idx ++ , pt ++ );
466+ sz = (word32 )WSTRLEN (pt );
467+
468+ sz = (sz < WOLFSSH_MAX_OCTET_LEN - 1 ) ? sz : WOLFSSH_MAX_OCTET_LEN - 1 ;
469+ WMEMCPY (modeBuf , pt , sz );
470+ modeBuf [sz ] = '\0' ;
471+ for (idx = 0 ; idx < sz ; idx ++ ) {
472+ if (modeBuf [idx ] == ' ' ) {
473+ modeBuf [idx ] = '\0' ;
474+ break ;
475+ }
476+ }
477+ if (idx == 0 || (idx == sz && pt [sz ] != ' ' ))
478+ return 1 ;
479+
480+ pt += (word32 )WSTRLEN (modeBuf );
481+ sz = (word32 )WSTRLEN (pt );
482+ for (idx = 0 ; idx < sz && pt [0 ] == ' ' ; idx ++ , pt ++ );
483+
484+ if (pt [0 ] == '\0' )
485+ return 1 ;
486+
487+ if (pt [0 ] != '/' ) {
488+ int maxSz = (int )WSTRLEN (remoteDir ) + (int )WSTRLEN (pt ) + 2 ;
489+ f = (char * )WMALLOC (maxSz , NULL , DYNAMIC_TYPE_TMP_BUFFER );
490+ if (f == NULL )
491+ return -1 ;
492+ f [0 ] = '\0' ;
493+ WSTRNCAT (f , remoteDir , maxSz );
494+ if (WSTRLEN (remoteDir ) > 1 )
495+ WSTRNCAT (f , "/" , maxSz );
496+ WSTRNCAT (f , pt , maxSz );
497+ * allocOut = f ;
498+ * pathOut = f ;
499+ }
500+ else {
501+ * pathOut = pt ;
502+ }
503+ return 0 ;
504+ }
505+
506+
436507/* main loop for handling commands */
437508static int doCmds (func_args * args )
438509{
@@ -822,54 +893,20 @@ static int doCmds(func_args* args)
822893 }
823894
824895 if ((pt = WSTRNSTR (msg , "chmod" , MAX_CMD_SZ )) != NULL ) {
825- word32 sz , idx ;
826896 char * f = NULL ;
827- char mode [WOLFSSH_MAX_OCTET_LEN ];
897+ char * path ;
898+ char mode [WOLFSSH_MAX_OCTET_LEN ];
899+ int parseRet ;
828900
829901 pt += sizeof ("chmod" );
830- sz = (word32 )WSTRLEN (pt );
831-
832- if (sz > 0 && pt [sz - 1 ] == '\n' ) pt [sz - 1 ] = '\0' ;
833-
834- /* advance pointer to first location of non space character */
835- for (idx = 0 ; idx < sz && pt [0 ] == ' ' ; idx ++ , pt ++ );
836- sz = (word32 )WSTRLEN (pt );
837-
838- /* get mode */
839- sz = (sz < WOLFSSH_MAX_OCTET_LEN - 1 )? sz :
840- WOLFSSH_MAX_OCTET_LEN - 1 ;
841- WMEMCPY (mode , pt , sz );
842- mode [WOLFSSH_MAX_OCTET_LEN - 1 ] = '\0' ;
843- for (idx = 0 ; idx < sz ; idx ++ ) {
844- if (mode [idx ] == ' ' ) {
845- mode [idx ] = '\0' ;
846- break ;
847- }
848- }
849- if (idx == 0 ) {
902+ parseRet = sftpParseModeAndPath (pt , mode , & path , & f , workingDir );
903+ if (parseRet == 1 ) {
850904 printf ("error with getting mode\r\n" );
851905 continue ;
852906 }
853- pt += (word32 )WSTRLEN (mode );
854- sz = (word32 )WSTRLEN (pt );
855- for (idx = 0 ; idx < sz && pt [0 ] == ' ' ; idx ++ , pt ++ );
856-
857- if (pt [0 ] != '/' ) {
858- int maxSz = (int )WSTRLEN (workingDir ) + sz + 2 ;
859- f = (char * )WMALLOC (maxSz , NULL , DYNAMIC_TYPE_TMP_BUFFER );
860- if (f == NULL ) {
861- err_msg ("Error malloc'ing" );
862- return -1 ;
863- }
864-
865- f [0 ] = '\0' ;
866- WSTRNCAT (f , workingDir , maxSz );
867- if (WSTRLEN (workingDir ) > 1 ) {
868- WSTRNCAT (f , "/" , maxSz );
869- }
870- WSTRNCAT (f , pt , maxSz );
871-
872- pt = f ;
907+ if (parseRet == -1 ) {
908+ err_msg ("Error malloc'ing" );
909+ return -1 ;
873910 }
874911
875912 /* update permissions */
@@ -881,21 +918,104 @@ static int doCmds(func_args* args)
881918 }
882919 }
883920
884- ret = wolfSSH_SFTP_CHMOD (ssh , pt , mode );
921+ ret = wolfSSH_SFTP_CHMOD (ssh , path , mode );
885922 err = wolfSSH_get_error (ssh );
886923 } while ((err == WS_WANT_READ || err == WS_WANT_WRITE ||
887924 err == WS_REKEYING ) && ret != WS_SUCCESS );
888925 if (ret != WS_SUCCESS ) {
889926 if (SFTP_FPUTS (args , "Unable to change permissions of " ) < 0 ) {
890927 err_msg ("fputs error" );
928+ WFREE (f , NULL , DYNAMIC_TYPE_TMP_BUFFER );
891929 return -1 ;
892930 }
893- if (SFTP_FPUTS (args , pt ) < 0 ) {
931+ if (SFTP_FPUTS (args , path ) < 0 ) {
894932 err_msg ("fputs error" );
933+ WFREE (f , NULL , DYNAMIC_TYPE_TMP_BUFFER );
895934 return -1 ;
896935 }
897936 if (SFTP_FPUTS (args , "\n" ) < 0 ) {
898937 err_msg ("fputs error" );
938+ WFREE (f , NULL , DYNAMIC_TYPE_TMP_BUFFER );
939+ return -1 ;
940+ }
941+ }
942+
943+ WFREE (f , NULL , DYNAMIC_TYPE_TMP_BUFFER );
944+ continue ;
945+ }
946+
947+ if ((pt = WSTRNSTR (msg , "creat" , MAX_CMD_SZ )) != NULL ) {
948+ char * f = NULL ;
949+ char * path ;
950+ char mode [WOLFSSH_MAX_OCTET_LEN ];
951+ byte handle [WOLFSSH_MAX_HANDLE ];
952+ word32 handleSz = WOLFSSH_MAX_HANDLE ;
953+ WS_SFTP_FILEATRB atr ;
954+ int parseRet ;
955+ int openRet = WS_FATAL_ERROR ;
956+ unsigned long perVal ;
957+ char * modeEnd ;
958+
959+ pt += sizeof ("creat" );
960+ parseRet = sftpParseModeAndPath (pt , mode , & path , & f , workingDir );
961+ if (parseRet == 1 ) {
962+ printf ("error with getting mode\r\n" );
963+ continue ;
964+ }
965+ if (parseRet == -1 ) {
966+ err_msg ("Error malloc'ing" );
967+ return -1 ;
968+ }
969+
970+ /* build permission attribute from octal mode string;
971+ * wolfSSH_oct2dec is internal scope so strtoul is used here */
972+ perVal = strtoul (mode , & modeEnd , 8 );
973+ if (* modeEnd == '\0' && perVal <= 07777 ) {
974+ WMEMSET (& atr , 0 , sizeof (WS_SFTP_FILEATRB ));
975+ atr .flags = WOLFSSH_FILEATRB_PERM ;
976+ atr .per = (word32 )perVal ;
977+
978+ /* open (create) remote file with the given permissions */
979+ handleSz = WOLFSSH_MAX_HANDLE ;
980+ do {
981+ while (ret == WS_REKEYING || ssh -> error == WS_REKEYING ) {
982+ ret = wolfSSH_worker (ssh , NULL );
983+ if (ret != WS_SUCCESS && ret == WS_FATAL_ERROR ) {
984+ ret = wolfSSH_get_error (ssh );
985+ }
986+ }
987+ ret = wolfSSH_SFTP_Open (ssh , path ,
988+ WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT |
989+ WOLFSSH_FXF_TRUNC , & atr , handle , & handleSz );
990+ err = wolfSSH_get_error (ssh );
991+ } while ((err == WS_WANT_READ || err == WS_WANT_WRITE ||
992+ err == WS_REKEYING ) && ret != WS_SUCCESS );
993+ openRet = ret ;
994+ }
995+ if (openRet == WS_SUCCESS ) {
996+ do {
997+ while (ret == WS_REKEYING || ssh -> error == WS_REKEYING ) {
998+ ret = wolfSSH_worker (ssh , NULL );
999+ if (ret != WS_SUCCESS && ret == WS_FATAL_ERROR ) {
1000+ ret = wolfSSH_get_error (ssh );
1001+ }
1002+ }
1003+ ret = wolfSSH_SFTP_Close (ssh , handle , handleSz );
1004+ err = wolfSSH_get_error (ssh );
1005+ } while ((err == WS_WANT_READ || err == WS_WANT_WRITE ||
1006+ err == WS_REKEYING ) && ret != WS_SUCCESS );
1007+ if (ret != WS_SUCCESS ) {
1008+ if (SFTP_FPUTS (args , "Unable to close file handle\n" ) < 0 ) {
1009+ err_msg ("fputs error" );
1010+ WFREE (f , NULL , DYNAMIC_TYPE_TMP_BUFFER );
1011+ return -1 ;
1012+ }
1013+ }
1014+ }
1015+ else {
1016+ if (SFTP_FPUTS (args , "Unable to create file\n" ) < 0 ) {
1017+ err_msg ("fputs error" );
1018+ WFREE (f , NULL , DYNAMIC_TYPE_TMP_BUFFER );
8991019 return -1 ;
9001020 }
9011021 }
0 commit comments