1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved.
3 * Licensed under Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
8 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 * Description: strncpy_s function
12 * Author: lishunda
13 * Create: 2014-02-25
14 */
15
16 #include "securecutil.h"
17
18 #if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
19 #define SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count) \
20 (((destMax) > 0 && (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && \
21 ((count) <= SECUREC_STRING_MAX_LEN || (count) == ((size_t)(-1))) && (count) > 0))
22 #else
23 #define SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count) \
24 (((destMax) > 0 && (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && \
25 (count) <= SECUREC_STRING_MAX_LEN && (count) > 0))
26 #endif
27
28 /*
29 * Check Src Count Range
30 */
CheckSrcCountRange(char * strDest,size_t destMax,const char * strSrc,size_t count)31 SECUREC_INLINE errno_t CheckSrcCountRange(char *strDest, size_t destMax, const char *strSrc, size_t count)
32 {
33 size_t tmpDestMax = destMax;
34 size_t tmpCount = count;
35 const char *endPos = strSrc;
36
37 /* Use destMax and count as boundary checker and destMax must be greater than zero */
38 while (*(endPos) != '\0' && tmpDestMax > 0 && tmpCount > 0) {
39 ++endPos;
40 --tmpCount;
41 --tmpDestMax;
42 }
43 if (tmpDestMax == 0) {
44 strDest[0] = '\0';
45 SECUREC_ERROR_INVALID_RANGE("strncpy_s");
46 return ERANGE_AND_RESET;
47 }
48 return EOK;
49 }
50
51 /*
52 * Handling errors, when dest euqal src return EOK
53 */
strncpy_error(char * strDest,size_t destMax,const char * strSrc,size_t count)54 errno_t strncpy_error(char *strDest, size_t destMax, const char *strSrc, size_t count)
55 {
56 if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
57 SECUREC_ERROR_INVALID_RANGE("strncpy_s");
58 return ERANGE;
59 }
60 if (strDest == NULL || strSrc == NULL) {
61 SECUREC_ERROR_INVALID_PARAMTER("strncpy_s");
62 if (strDest != NULL) {
63 strDest[0] = '\0';
64 return EINVAL_AND_RESET;
65 }
66 return EINVAL;
67 }
68 if (count > SECUREC_STRING_MAX_LEN) {
69 strDest[0] = '\0'; /* Clear dest string */
70 SECUREC_ERROR_INVALID_RANGE("strncpy_s");
71 return ERANGE_AND_RESET;
72 }
73 if (count == 0) {
74 strDest[0] = '\0';
75 return EOK;
76 }
77 return CheckSrcCountRange(strDest, destMax, strSrc, count);
78 }
79
80 /*
81 * <FUNCTION DESCRIPTION>
82 * The strncpy_s function copies not more than n successive characters (not including the terminating null character)
83 * from the array pointed to by strSrc to the array pointed to by strDest.
84 *
85 * <INPUT PARAMETERS>
86 * strDest Destination string.
87 * destMax The size of the destination string, in characters.
88 * strSrc Source string.
89 * count Number of characters to be copied.
90 *
91 * <OUTPUT PARAMETERS>
92 * strDest is updated
93 *
94 * <RETURN VALUE>
95 * EOK Success
96 * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
97 * EINVAL_AND_RESET strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
98 * ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
99 * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap
100 * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid
101 *
102 * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
103 */
strncpy_s(char * strDest,size_t destMax,const char * strSrc,size_t count)104 errno_t strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count)
105 {
106 if (SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count)) {
107 size_t minCpLen; /* Use it to store the maxi length limit */
108 if (count < destMax) {
109 SECUREC_CALC_STR_LEN(strSrc, count, &minCpLen); /* No ending terminator */
110 } else {
111 size_t tmpCount = destMax;
112 #ifdef SECUREC_COMPATIBLE_WIN_FORMAT
113 if (count == ((size_t)(-1))) {
114 tmpCount = destMax - 1;
115 }
116 #endif
117 SECUREC_CALC_STR_LEN(strSrc, tmpCount, &minCpLen); /* No ending terminator */
118 if (minCpLen == destMax) {
119 strDest[0] = '\0';
120 SECUREC_ERROR_INVALID_RANGE("strncpy_s");
121 return ERANGE_AND_RESET;
122 }
123 }
124 if (SECUREC_STRING_NO_OVERLAP(strDest, strSrc, minCpLen) || strDest == strSrc) {
125 /* Not overlap */
126 SECUREC_MEMCPY_WARP_OPT(strDest, strSrc, minCpLen); /* Copy string without terminator */
127 strDest[minCpLen] = '\0';
128 return EOK;
129 } else {
130 strDest[0] = '\0';
131 SECUREC_ERROR_BUFFER_OVERLAP("strncpy_s");
132 return EOVERLAP_AND_RESET;
133 }
134 }
135 return strncpy_error(strDest, destMax, strSrc, count);
136 }
137
138 #if SECUREC_IN_KERNEL
139 EXPORT_SYMBOL(strncpy_s);
140 #endif
141
142