Mercurial > illumos > illumos-gate
comparison usr/src/lib/libkmsagent/common/SYSCommon.c @ 12720:3db6e0082404
PSARC 2010/195 PKCS11 KMS Provider
6944296 Solaris needs a PKCS#11 provider to allow access to KMS keystore functionality
author | Wyllys Ingersoll <Wyllys.Ingersoll@Sun.COM> |
---|---|
date | Mon, 28 Jun 2010 16:04:11 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
12719:bd9fb35d09c2 | 12720:3db6e0082404 |
---|---|
1 /* | |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
5 * Common Development and Distribution License (the "License"). | |
6 * You may not use this file except in compliance with the License. | |
7 * | |
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 * or http://www.opensolaris.org/os/licensing. | |
10 * See the License for the specific language governing permissions | |
11 * and limitations under the License. | |
12 * | |
13 * When distributing Covered Code, include this CDDL HEADER in each | |
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
15 * If applicable, add the following below this CDDL HEADER, with the | |
16 * fields enclosed by brackets "[]" replaced with your own identifying | |
17 * information: Portions Copyright [yyyy] [name of copyright owner] | |
18 * | |
19 * CDDL HEADER END | |
20 */ | |
21 | |
22 /* | |
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. | |
24 */ | |
25 | |
26 /*--------------------------------------------------------------------------- | |
27 * Module: SYSCommon.c | |
28 *-------------------------------------------------------------------------*/ | |
29 | |
30 #include <stdio.h> | |
31 #include "SYSCommon.h" | |
32 #include <time.h> | |
33 #include <errno.h> | |
34 #include <sys/stat.h> | |
35 #include <sys/types.h> | |
36 #include <signal.h> | |
37 | |
38 #ifndef WIN32 | |
39 #include <unistd.h> | |
40 #endif | |
41 | |
42 #ifdef WIN32 | |
43 #include <io.h> | |
44 #include <stdlib.h> /* for malloc, calloc, and free */ | |
45 #elif defined K_LINUX_PLATFORM | |
46 #include <unistd.h> /* it includes usleep(us) */ | |
47 #include <sys/time.h> | |
48 #include <fts.h> | |
49 #else | |
50 /* | |
51 * Directory traversal code is not yet available for Solaris. | |
52 * If such code will need to be written, then it will probably use ftw.h. | |
53 */ | |
54 #endif | |
55 | |
56 #ifdef K_SOLARIS_PLATFORM | |
57 /* For K_AdjustLocalClock */ | |
58 #include <unistd.h> | |
59 /* For K_SetRootPassword */ | |
60 #define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */ | |
61 #include <errno.h> | |
62 #include <libgen.h> | |
63 #include <malloc.h> | |
64 #include <signal.h> | |
65 #include <stdio.h> | |
66 #include <stdlib.h> | |
67 #include <strings.h> | |
68 #include <stropts.h> | |
69 #include <unistd.h> | |
70 #include <termio.h> | |
71 #include <security/pam_appl.h> | |
72 #include <widec.h> | |
73 #endif | |
74 | |
75 #ifdef K_LINUX_PLATFORM | |
76 extern int pthread_mutexattr_settype __P ((pthread_mutexattr_t *__attr, | |
77 int __kind)); | |
78 #endif | |
79 | |
80 #ifdef K_HPUX_PLATFORM | |
81 int64 atoll(const char *str) | |
82 { | |
83 int64 tmp = 0; | |
84 sscanf(str, "%lld", &tmp); | |
85 return tmp; | |
86 } | |
87 | |
88 #endif | |
89 | |
90 | |
91 /*--------------------------------------------------------------------------- | |
92 * Function: K_CreateThread | |
93 * | |
94 * Description: | |
95 * Thread creation function "CreateThread" takes a thread function | |
96 * and its parameter to create a thread. It also has a Boolean | |
97 * parameter to indicate if the thread is detached or joinable. | |
98 * A new thread's handle is returned through the output parameter. | |
99 * | |
100 * Input | |
101 * ----- | |
102 * i_pFunc Function pointer of the thread function | |
103 * i_pvData The point of the parameter passed to the thread function | |
104 * i_bIsDetached The thread is detached or not | |
105 * (Note: It is not supported on Win32) | |
106 * | |
107 * Output | |
108 * ------ | |
109 * o_pNewThread The Thread handle | |
110 * | |
111 * Return value Error code | |
112 * | |
113 *--------------------------------------------------------------------------*/ | |
114 | |
115 int K_CreateThread(K_ThreadFunc i_pFunc, | |
116 void *i_pvData, | |
117 int i_bIsDetached, | |
118 K_THREAD_HANDLE *o_pNewThread) | |
119 { | |
120 int iOK = K_SYS_OK; | |
121 int iReturn = 0; | |
122 | |
123 #ifdef WIN32 | |
124 | |
125 { | |
126 unsigned id; | |
127 | |
128 *o_pNewThread = (HANDLE)_beginthreadex(NULL, | |
129 0, | |
130 (int (_stdcall *) (void *vpData))i_pFunc, | |
131 i_pvData, | |
132 0, | |
133 &id); | |
134 | |
135 | |
136 if(*o_pNewThread == 0) | |
137 { | |
138 #ifdef SYS_DEBUG | |
139 printf(" (%s, %d): error creating pthread, error = %d\n", | |
140 __FILE__, __LINE__, iReturn); | |
141 #endif | |
142 return K_SYS_ERR_CREATE_THREAD; | |
143 } | |
144 | |
145 return K_SYS_OK; | |
146 } | |
147 | |
148 #else | |
149 pthread_attr_t attr; | |
150 | |
151 iReturn = pthread_attr_init(&attr); | |
152 | |
153 if ( iReturn == 0 ) | |
154 { | |
155 iReturn = pthread_attr_setdetachstate(&attr, (i_bIsDetached) ? | |
156 PTHREAD_CREATE_DETACHED : | |
157 PTHREAD_CREATE_JOINABLE); | |
158 } | |
159 | |
160 #ifdef UNIX | |
161 if ( iReturn == 0 ) | |
162 { | |
163 iReturn = pthread_attr_setstacksize(&attr, 1024*1024); | |
164 } | |
165 #endif | |
166 | |
167 if ( iReturn == 0 ) | |
168 { | |
169 iReturn = pthread_create(o_pNewThread, &attr, (void *(*)(void *)) i_pFunc, i_pvData); | |
170 } | |
171 | |
172 if ( iReturn == 0 ) | |
173 { | |
174 iReturn = pthread_attr_destroy(&attr); | |
175 } | |
176 | |
177 // TODO: Log error? | |
178 if ( iReturn ) | |
179 { | |
180 #ifdef SYS_DEBUG | |
181 printf(" (%s, %d): error creating pthread, error = %d\n", | |
182 __FILE__, __LINE__, iReturn); | |
183 #endif | |
184 | |
185 iOK = K_SYS_ERR_CREATE_THREAD; | |
186 } | |
187 | |
188 return iOK; | |
189 #endif | |
190 } | |
191 | |
192 | |
193 /*--------------------------------------------------------------------------- | |
194 * Function: K_JoinThread | |
195 * | |
196 * Description: | |
197 * Thread joining function is called when the current thread | |
198 * waits another thread to terminate. | |
199 * | |
200 * Input | |
201 * ----- | |
202 * i_hThread The thread handle of the to-be-joined thread | |
203 * | |
204 * Output | |
205 * ------ | |
206 * (none) | |
207 * | |
208 * Return value Error code | |
209 * | |
210 *--------------------------------------------------------------------------*/ | |
211 | |
212 int K_JoinThread(K_THREAD_HANDLE i_hThread) | |
213 { | |
214 int iOK = K_SYS_OK; | |
215 #ifdef WIN32 | |
216 | |
217 WaitForSingleObject(i_hThread, INFINITE); | |
218 | |
219 #else | |
220 { | |
221 int iReturn; | |
222 iReturn = pthread_join(i_hThread, NULL); | |
223 | |
224 if ( iReturn ) | |
225 { | |
226 | |
227 #ifdef SYS_DEBUG | |
228 printf(" (%s, %d): error creating pthread, error = %d\n", | |
229 __FILE__, __LINE__, iReturn); | |
230 #endif | |
231 iOK = K_SYS_ERR_JOIN_THREAD; | |
232 } | |
233 } | |
234 | |
235 #endif | |
236 return iOK; | |
237 } | |
238 | |
239 | |
240 /*--------------------------------------------------------------------------- | |
241 * Function: K_GetCurrentThreadId | |
242 * | |
243 * Description: | |
244 * Returns the thread ID of the current thread. | |
245 * | |
246 * Input | |
247 * ----- | |
248 * (none) | |
249 * | |
250 * Output | |
251 * ------ | |
252 * (none) | |
253 * | |
254 * Return value The thread ID | |
255 * | |
256 *--------------------------------------------------------------------------*/ | |
257 | |
258 int K_GetCurrentThreadId() | |
259 { | |
260 #ifdef WIN32 | |
261 return GetCurrentThreadId(); | |
262 #else | |
263 return pthread_self(); | |
264 #endif | |
265 | |
266 } | |
267 | |
268 | |
269 /*--------------------------------------------------------------------------- | |
270 * Function: K_CreateMutex | |
271 * | |
272 * Description: | |
273 * The mutex creation function creates a mutex according to the given | |
274 * mutex type, and returns the mutex handle to the output parameter. | |
275 * | |
276 * Input | |
277 * ----- | |
278 * i_bIsRecursive Indication whether the mutex can be entered recursively | |
279 * | |
280 * Output | |
281 * ------ | |
282 * o_phandle the handle pointer to the mutex | |
283 * | |
284 * Return value Error Code | |
285 * | |
286 *--------------------------------------------------------------------------*/ | |
287 | |
288 int K_CreateMutex( K_MUTEX_HANDLE *o_phandle ) | |
289 { | |
290 int iOK = K_SYS_OK; | |
291 BOOL bIsRecursive = 1; // this used to be an input -- but why do we want this to be optional? | |
292 | |
293 #ifdef WIN32 | |
294 { | |
295 *o_phandle = (WIN32Mutex *)malloc(sizeof(WIN32Mutex)); | |
296 if(*o_phandle == NULL) | |
297 { | |
298 return K_SYS_ERR_NO_MEMORY; | |
299 } | |
300 (*o_phandle)->m_bIsRecursive = bIsRecursive; | |
301 if(bIsRecursive) | |
302 { | |
303 InitializeCriticalSection(&((*o_phandle)->m_stCriticalSection)); | |
304 } | |
305 else | |
306 { | |
307 (*o_phandle)->m_handle = CreateMutex(NULL, FALSE, NULL); | |
308 } | |
309 | |
310 } | |
311 #else | |
312 { | |
313 int iType; | |
314 pthread_mutexattr_t attr; | |
315 | |
316 if ( pthread_mutexattr_init(&attr) ) | |
317 { | |
318 return K_SYS_ERR_COND; | |
319 } | |
320 | |
321 if(bIsRecursive) | |
322 { | |
323 iType = | |
324 #ifdef K_LINUX_PLATFORM | |
325 PTHREAD_MUTEX_RECURSIVE_NP; | |
326 #else | |
327 PTHREAD_MUTEX_RECURSIVE; | |
328 #endif | |
329 | |
330 if ( pthread_mutexattr_settype(&attr, iType) ) | |
331 { | |
332 return K_SYS_ERR_COND; | |
333 } | |
334 } | |
335 | |
336 *o_phandle = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); | |
337 if(*o_phandle == NULL) | |
338 { | |
339 return K_SYS_ERR_NO_MEMORY; | |
340 } | |
341 | |
342 if ( pthread_mutex_init(*o_phandle, &attr) ) | |
343 { | |
344 return K_SYS_ERR_COND; | |
345 } | |
346 | |
347 if ( pthread_mutexattr_destroy(&attr) ) | |
348 { | |
349 return K_SYS_ERR_COND; | |
350 } | |
351 } | |
352 #endif | |
353 | |
354 return iOK; | |
355 } | |
356 | |
357 | |
358 /*--------------------------------------------------------------------------- | |
359 * Function: K_LockMutex | |
360 * | |
361 * Description: | |
362 * K_LockMutex is used to lock the mutex, and K_UnlockMutex is | |
363 * used to unlock it. | |
364 * | |
365 * Input | |
366 * ----- | |
367 * i_handle the mutex handle | |
368 * | |
369 * Output | |
370 * ------ | |
371 * (none) | |
372 * | |
373 * Return value Error Code | |
374 * | |
375 *--------------------------------------------------------------------------*/ | |
376 | |
377 int K_LockMutex(K_MUTEX_HANDLE i_handle) | |
378 { | |
379 int iOK = K_SYS_OK; | |
380 #ifdef WIN32 | |
381 | |
382 if(i_handle->m_bIsRecursive) | |
383 { | |
384 EnterCriticalSection(&(i_handle->m_stCriticalSection)); | |
385 } | |
386 else | |
387 { | |
388 WaitForSingleObject(i_handle->m_handle, INFINITE); | |
389 } | |
390 | |
391 #else | |
392 | |
393 if ( pthread_mutex_lock(i_handle) ) | |
394 { | |
395 return K_SYS_ERR_COND; | |
396 } | |
397 | |
398 #endif | |
399 return iOK; // TODO: better error handling | |
400 } | |
401 | |
402 | |
403 /*--------------------------------------------------------------------------- | |
404 * Function: K_UnlockMutex | |
405 * | |
406 * Description: | |
407 * K_UnlockMutex is used to unlock the lock. | |
408 * | |
409 * Input | |
410 * ----- | |
411 * i_handle the mutex handle | |
412 * | |
413 * Output | |
414 * ------ | |
415 * (none) | |
416 * | |
417 * Return value Error Code | |
418 * | |
419 *--------------------------------------------------------------------------*/ | |
420 | |
421 int K_UnlockMutex(K_MUTEX_HANDLE i_handle) | |
422 { | |
423 int iOK = K_SYS_OK; | |
424 | |
425 #ifdef WIN32 | |
426 if(i_handle->m_bIsRecursive) | |
427 { | |
428 LeaveCriticalSection(&(i_handle->m_stCriticalSection)); | |
429 } | |
430 else | |
431 { | |
432 ReleaseMutex(i_handle->m_handle); | |
433 } | |
434 | |
435 #else | |
436 | |
437 if ( pthread_mutex_unlock(i_handle) ) | |
438 { | |
439 return K_SYS_ERR_COND; | |
440 } | |
441 #endif | |
442 | |
443 return iOK; // TODO: better error handling | |
444 } | |
445 | |
446 | |
447 /*--------------------------------------------------------------------------- | |
448 * Function: K_DestroyMutex | |
449 * | |
450 * Description: | |
451 * When a mutex is no longer needed, K_DestroyMutex must be called | |
452 * to destroy it. | |
453 * | |
454 * Input | |
455 * ----- | |
456 * i_handle the mutex handle | |
457 * Output | |
458 * ------ | |
459 * (none) | |
460 * | |
461 * Return value Error Code | |
462 * | |
463 *--------------------------------------------------------------------------*/ | |
464 | |
465 int K_DestroyMutex(K_MUTEX_HANDLE i_handle) | |
466 { | |
467 | |
468 int iOK = K_SYS_OK; | |
469 | |
470 #ifdef WIN32 | |
471 | |
472 if(i_handle->m_bIsRecursive) | |
473 { | |
474 DeleteCriticalSection(&(i_handle->m_stCriticalSection)); | |
475 } | |
476 else | |
477 { | |
478 CloseHandle(i_handle->m_handle); | |
479 } | |
480 free(i_handle); | |
481 | |
482 #else | |
483 pthread_mutex_destroy(i_handle); | |
484 free(i_handle); | |
485 #endif | |
486 return iOK; // TODO: better error handling | |
487 } | |
488 | |
489 | |
490 /*--------------------------------------------------------------------------- | |
491 * Function: K_InitConditionalVariable | |
492 * | |
493 * Description: | |
494 * This function initializes a conditional variable. Upon successful | |
495 * completion, the new condition variable is returned via the condition | |
496 * parameter, and 0 is returned. Otherwise, an error code is returned. | |
497 * | |
498 * Input | |
499 * ----- | |
500 * i_pCond the pointer to the conditional variable which is to be | |
501 * initialized | |
502 * | |
503 * Output | |
504 * ------ | |
505 * (none) | |
506 * | |
507 * Return value Error Code | |
508 * | |
509 *--------------------------------------------------------------------------*/ | |
510 | |
511 int K_InitConditionalVariable (K_ConditionalVariable * i_pCond) | |
512 { | |
513 int iOK = K_SYS_OK; | |
514 #ifdef WIN32 | |
515 | |
516 i_pCond->m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); | |
517 i_pCond->m_hMutex = CreateMutex(NULL, FALSE, NULL); | |
518 i_pCond->m_iSignalAll = 0; | |
519 i_pCond->m_iNumWaiting = 0; | |
520 | |
521 #else | |
522 | |
523 if ( pthread_cond_init(i_pCond, NULL) ) | |
524 { | |
525 return K_SYS_ERR_COND; | |
526 } | |
527 | |
528 #endif | |
529 | |
530 return iOK; | |
531 } | |
532 | |
533 | |
534 /*--------------------------------------------------------------------------- | |
535 * Function: K_DestroyConditionalVariable | |
536 * | |
537 * Description: | |
538 * This function destroys a conditional variable. Upon successful | |
539 * completion, the condition variable is destroyed, and 0 is returned. | |
540 * Otherwise, an error code is returned. | |
541 * After deletion of the condition variable, the condition parameter | |
542 * is not valid until it is initialized again by a call to the | |
543 * K_InitConditionalVariable subroutine. | |
544 * | |
545 * Input | |
546 * ----- | |
547 * i_pCond the pointer to the conditional variable which is to be | |
548 * destroyed | |
549 * Output | |
550 * ------ | |
551 * (none) | |
552 * | |
553 * Return value Error Code | |
554 * | |
555 *--------------------------------------------------------------------------*/ | |
556 | |
557 int K_DestroyConditionalVariable(K_ConditionalVariable * i_pCond) | |
558 { | |
559 int iOK = K_SYS_OK; | |
560 #ifdef WIN32 | |
561 CloseHandle(i_pCond->m_hMutex); | |
562 CloseHandle(i_pCond->m_hEvent); | |
563 #else | |
564 | |
565 if ( pthread_cond_destroy(i_pCond) ) | |
566 { | |
567 return K_SYS_ERR_COND; | |
568 } | |
569 | |
570 #endif | |
571 return iOK; | |
572 | |
573 } | |
574 | |
575 | |
576 /*--------------------------------------------------------------------------- | |
577 * Function: K_WaitConditionalVariable | |
578 * | |
579 * Description: | |
580 * This function is used to block on a condition variable. | |
581 * They are called with mutex locked by the calling thread or undefined | |
582 * behaviour will result. | |
583 * | |
584 * Input | |
585 * ----- | |
586 * i_pCond the pointer to the conditional variable | |
587 * i_handle the companion mutex handle | |
588 * | |
589 * Output | |
590 * ------ | |
591 * (none) | |
592 * | |
593 * Return value Error Code | |
594 * | |
595 *--------------------------------------------------------------------------*/ | |
596 | |
597 int K_WaitConditionalVariable(K_ConditionalVariable * i_pCond, | |
598 K_MUTEX_HANDLE i_handle) | |
599 { | |
600 | |
601 int iOK = K_SYS_OK; | |
602 #ifdef WIN32 | |
603 DWORD res; | |
604 | |
605 while (1) | |
606 { | |
607 iOK = WaitForSingleObject(i_pCond->m_hMutex, INFINITE); | |
608 if (iOK != WAIT_OBJECT_0) | |
609 { | |
610 return K_SYS_ERR_COND; | |
611 } | |
612 i_pCond->m_iNumWaiting++; | |
613 ReleaseMutex(i_pCond->m_hMutex); | |
614 | |
615 K_UnlockMutex(i_handle); | |
616 res = WaitForSingleObject(i_pCond->m_hEvent, INFINITE); | |
617 i_pCond->m_iNumWaiting--; | |
618 | |
619 if (res != WAIT_OBJECT_0) | |
620 { | |
621 ReleaseMutex(i_pCond->m_hMutex); | |
622 return K_SYS_ERR_COND; | |
623 } | |
624 | |
625 if (i_pCond->m_iSignalAll) | |
626 { | |
627 if (i_pCond->m_iNumWaiting == 0) | |
628 { | |
629 ResetEvent(i_pCond->m_hEvent); | |
630 } | |
631 break; | |
632 } | |
633 | |
634 if (i_pCond->m_iSignalled) | |
635 { | |
636 i_pCond->m_iSignalled = 0; | |
637 ResetEvent(i_pCond->m_hEvent); | |
638 break; | |
639 } | |
640 ReleaseMutex(i_pCond->m_hMutex); | |
641 } | |
642 | |
643 K_LockMutex(i_handle); | |
644 | |
645 return K_SYS_OK; | |
646 #else | |
647 | |
648 if ( pthread_cond_wait(i_pCond, i_handle) ) | |
649 { | |
650 return K_SYS_ERR_COND; | |
651 } | |
652 | |
653 #endif | |
654 return iOK; // TODO: better error handling | |
655 } | |
656 | |
657 | |
658 /*--------------------------------------------------------------------------- | |
659 * Function: K_SignalConditionalVariable | |
660 * | |
661 * Description: | |
662 * This function is used to restart one of the threads that are waiting on | |
663 * the condition variable. If no threads are waiting on it, nothing happens. | |
664 * If several threads are waiting on it, exactly one is restarted. | |
665 * | |
666 * Input | |
667 * ----- | |
668 * i_pCond the pointer to the conditional variable | |
669 * | |
670 * Output | |
671 * ------ | |
672 * (none) | |
673 * | |
674 * Return value Error Code | |
675 * | |
676 *--------------------------------------------------------------------------*/ | |
677 | |
678 int K_SignalConditionalVariable(K_ConditionalVariable * i_pCond) | |
679 { | |
680 int iOK = K_SYS_OK; | |
681 #ifdef WIN32 | |
682 | |
683 int iReturn; | |
684 | |
685 iReturn = WaitForSingleObject(i_pCond->m_hMutex, INFINITE); | |
686 if (iReturn != WAIT_OBJECT_0) | |
687 { | |
688 return K_SYS_ERR_COND; | |
689 } | |
690 | |
691 i_pCond->m_iSignalled = 1; | |
692 | |
693 iReturn = SetEvent(i_pCond->m_hEvent); | |
694 if (iReturn == 0) | |
695 { | |
696 iOK = K_SYS_ERR_COND; | |
697 } | |
698 ReleaseMutex(i_pCond->m_hMutex); | |
699 | |
700 return iOK; | |
701 #else | |
702 | |
703 if ( pthread_cond_signal(i_pCond) ) | |
704 { | |
705 return K_SYS_ERR_COND; | |
706 } | |
707 | |
708 #endif | |
709 return iOK; | |
710 } | |
711 | |
712 | |
713 /*--------------------------------------------------------------------------- | |
714 * Function: K_BroadcastConditionalVariable | |
715 * | |
716 * Description: | |
717 * This function is used to restart all threads that are waiting on | |
718 * the condition variable. | |
719 * | |
720 * Input | |
721 * ----- | |
722 * i_pCond the pointer to the conditional variable | |
723 * | |
724 * Output | |
725 * ------ | |
726 * (none) | |
727 * | |
728 * Return value Error Code | |
729 * | |
730 *--------------------------------------------------------------------------*/ | |
731 | |
732 int K_BroadcastConditionalVariable(K_ConditionalVariable * i_pCond) | |
733 { | |
734 | |
735 int iOK = K_SYS_OK; | |
736 | |
737 #ifdef WIN32 | |
738 | |
739 int iReturn; | |
740 | |
741 iReturn = WaitForSingleObject(i_pCond->m_hMutex, INFINITE); | |
742 if (iReturn != WAIT_OBJECT_0) | |
743 { | |
744 return K_SYS_ERR_COND; | |
745 } | |
746 i_pCond->m_iSignalled = 1; | |
747 i_pCond->m_iSignalAll = 1; | |
748 | |
749 iReturn = SetEvent(i_pCond->m_hEvent); | |
750 | |
751 if (iReturn == 0) | |
752 { | |
753 iOK = K_SYS_ERR_COND; | |
754 } | |
755 | |
756 ReleaseMutex(i_pCond->m_hMutex); | |
757 | |
758 return iOK; | |
759 | |
760 #else | |
761 | |
762 if ( pthread_cond_broadcast(i_pCond) ) | |
763 { | |
764 return K_SYS_ERR_COND; | |
765 } | |
766 | |
767 #endif | |
768 return iOK; | |
769 } | |
770 | |
771 | |
772 /*--------------------------------------------------------------------------- | |
773 * Function: K_Sleep | |
774 * | |
775 * Description: | |
776 * Sleep for a given period in given milliseconds. | |
777 * | |
778 * Input | |
779 * ----- | |
780 * i_ms milliseconds | |
781 * | |
782 * Output | |
783 * ------ | |
784 * (none) | |
785 * | |
786 * Return value (none) | |
787 * | |
788 *--------------------------------------------------------------------------*/ | |
789 | |
790 void K_Sleep(int i_ms) | |
791 { | |
792 #ifdef WIN32 | |
793 Sleep(i_ms); | |
794 #else | |
795 usleep(i_ms * 1000); | |
796 #endif | |
797 } | |
798 | |
799 | |
800 /*--------------------------------------------------------------------------- | |
801 * Function: K_GetTickCount | |
802 * | |
803 * Description: | |
804 * The K_GetTickCount function retrieves the number of | |
805 * milliseconds that have elapsed since the system was started. | |
806 * | |
807 * Input | |
808 * ----- | |
809 * (none) | |
810 * | |
811 * Output | |
812 * ------ | |
813 * (none) | |
814 * | |
815 * Return value the elasped milliseconds since the system was started | |
816 * | |
817 *--------------------------------------------------------------------------*/ | |
818 | |
819 unsigned int K_GetTickCount() | |
820 { | |
821 #ifdef WIN32 | |
822 return (unsigned int)GetTickCount(); | |
823 #else | |
824 { | |
825 struct timeval tv; | |
826 gettimeofday( &tv, NULL ); | |
827 /* this will rollover ~ every 49.7 days | |
828 dont surprise when it returns negative values, since we are only interested | |
829 in using sth like "tickCount2 - tickCount1" to get the time interval | |
830 */ | |
831 return ( tv.tv_sec * 1000 ) + ( tv.tv_usec / 1000 ); | |
832 } | |
833 #endif | |
834 } | |
835 | |
836 | |
837 /*--------------------------------------------------------------------------- | |
838 * Function: K_AdjustClock | |
839 * | |
840 * Description: | |
841 * The K_AdjustClock function immediately adjusts the system clock by | |
842 * the given number of seconds. A positive number adjusts the system | |
843 * clock forward; a negative number adjusts the system clock backward. | |
844 * | |
845 * Input | |
846 * ----- | |
847 * i_iAdjustmentInSeconds Number of seconds by which to adjust the | |
848 * system clock | |
849 * Output | |
850 * ------ | |
851 * (none) | |
852 * | |
853 * Return value 1 if successful, 0 on error | |
854 * | |
855 *--------------------------------------------------------------------------*/ | |
856 | |
857 int K_AdjustClock( long i_iAdjustmentInSeconds ) | |
858 { | |
859 #ifndef WIN32 | |
860 struct timeval stDateTime; | |
861 if ( 0 != gettimeofday(&stDateTime, NULL) ) | |
862 { | |
863 return FALSE; | |
864 } | |
865 | |
866 stDateTime.tv_sec += i_iAdjustmentInSeconds; | |
867 | |
868 if ( 0 != settimeofday(&stDateTime, NULL) ) | |
869 { | |
870 return FALSE; | |
871 } | |
872 #else | |
873 // TODO: implement for Windows | |
874 return FALSE; | |
875 #endif | |
876 | |
877 return TRUE; | |
878 } | |
879 | |
880 | |
881 /*--------------------------------------------------------------------------- | |
882 * Function: K_IsLittleEndian | |
883 * | |
884 * Description: | |
885 * Checks to see whether this platform uses little endian integer | |
886 * representation. | |
887 * | |
888 * Input | |
889 * ----- | |
890 * (none) | |
891 * | |
892 * Output | |
893 * ------ | |
894 * (none) | |
895 * | |
896 * Return value 1 for little endian | |
897 * | |
898 *--------------------------------------------------------------------------*/ | |
899 | |
900 int K_IsLittleEndian() | |
901 { | |
902 short iWord = 0x4321; | |
903 return ((*(unsigned char*)&iWord) == 0x21); | |
904 } | |
905 | |
906 | |
907 /*--------------------------------------------------------------------------- | |
908 * Function: K_FileLength32 | |
909 * | |
910 * Description: | |
911 * Gets the size in bytes of the file associated with the given FILE pointer. | |
912 * | |
913 * Input | |
914 * ----- | |
915 * i_fpFile File handle | |
916 * | |
917 * Output | |
918 * ------ | |
919 * (none) | |
920 * | |
921 * Return value File size in bytes, or -1L on error | |
922 * | |
923 *--------------------------------------------------------------------------*/ | |
924 | |
925 long K_FileLength32( FILE* i_fpFile ) | |
926 { | |
927 #ifdef WIN32 | |
928 int iFileDescriptor = _fileno( i_fpFile ); | |
929 struct _stat stStat; | |
930 | |
931 if ( _fstat(iFileDescriptor, &stStat) != 0) | |
932 { | |
933 // error | |
934 return -1L; | |
935 } | |
936 | |
937 #else | |
938 int iFileDescriptor = fileno( i_fpFile ); | |
939 struct stat stStat; | |
940 | |
941 if ( fstat(iFileDescriptor, &stStat) != 0) | |
942 { | |
943 // error | |
944 return -1L; | |
945 } | |
946 | |
947 #endif | |
948 | |
949 return stStat.st_size; | |
950 } | |
951 | |
952 | |
953 /*--------------------------------------------------------------------------- | |
954 * Function: K_StringCompareNoCase | |
955 * | |
956 * Description: | |
957 * Compares the two given strings insensitive to case. | |
958 * | |
959 * Input | |
960 * ----- | |
961 * i_sString1 First string | |
962 * i_sString2 Second string | |
963 * | |
964 * Output | |
965 * ------ | |
966 * (none) | |
967 * | |
968 * Return value 0 if identical, -1 if first string is less than second | |
969 * string, or 1 if first string is greater than second | |
970 * | |
971 *--------------------------------------------------------------------------*/ | |
972 | |
973 int K_StringCompareNoCase( const char* i_sString1, const char* i_sString2 ) | |
974 { | |
975 #ifdef WIN32 | |
976 return _stricmp( i_sString1, i_sString2 ); | |
977 #else | |
978 return strcasecmp( i_sString1, i_sString2 ); | |
979 #endif | |
980 } | |
981 | |
982 | |
983 /*--------------------------------------------------------------------------- | |
984 * Function: K_StringCompareNoCaseWide | |
985 * | |
986 * Description: | |
987 * Compares the two given wide strings insensitive to case. | |
988 * | |
989 * Input | |
990 * ----- | |
991 * i_wsString1 First wide string | |
992 * i_wsString2 Second wide string | |
993 * | |
994 * Output | |
995 * ------ | |
996 * (none) | |
997 * | |
998 * Return value 0 if identical, -1 if first string is less than second | |
999 * string, or 1 if first string is greater than second | |
1000 * | |
1001 *--------------------------------------------------------------------------*/ | |
1002 | |
1003 int K_StringCompareNoCaseWide( const wchar_t* i_wsString1, const wchar_t* i_wsString2 ) | |
1004 { | |
1005 #ifdef WIN32 | |
1006 return _wcsicmp( i_wsString1, i_wsString2 ); | |
1007 #elif defined K_SOLARIS_PLATFORM | |
1008 return wscasecmp( i_wsString1, i_wsString2 ); | |
1009 #else | |
1010 return wcscasecmp( i_wsString1, i_wsString2 ); | |
1011 #endif | |
1012 } | |
1013 | |
1014 | |
1015 /*--------------------------------------------------------------------------- | |
1016 * Function: K_CreateDirectory | |
1017 * | |
1018 * Description: | |
1019 * Creates a directory with the given path name. | |
1020 * | |
1021 * Input | |
1022 * ----- | |
1023 * i_sDirectoryName Directory name | |
1024 * | |
1025 * Output | |
1026 * ------ | |
1027 * (none) | |
1028 * | |
1029 * Return value 0 on success, -1 on failure | |
1030 * | |
1031 *--------------------------------------------------------------------------*/ | |
1032 | |
1033 int K_CreateDirectory( const char* i_sDirectoryName ) | |
1034 { | |
1035 // TODO: make this build all parent directories as well. | |
1036 | |
1037 #ifdef WIN32 | |
1038 if ( CreateDirectoryA( i_sDirectoryName, NULL ) ) | |
1039 { | |
1040 return 0; | |
1041 } | |
1042 else | |
1043 { | |
1044 DWORD dwError = GetLastError(); | |
1045 return ( dwError == ERROR_ALREADY_EXISTS ) ? 0 : (dwError ? dwError : -1); | |
1046 } | |
1047 #else | |
1048 if ( mkdir( i_sDirectoryName, S_IRWXU ) == 0 ) | |
1049 { | |
1050 return 0; | |
1051 } | |
1052 else | |
1053 { | |
1054 return ( errno == EEXIST ) ? 0 : (errno ? errno : -1); | |
1055 } | |
1056 #endif | |
1057 } | |
1058 | |
1059 | |
1060 /*--------------------------------------------------------------------------- | |
1061 * Function: K_DeleteFile | |
1062 * | |
1063 * Description: | |
1064 * Deletes the given file. | |
1065 * | |
1066 * Input | |
1067 * ----- | |
1068 * i_sFilename Name of file to delete | |
1069 * | |
1070 * Output | |
1071 * ------ | |
1072 * (none) | |
1073 * | |
1074 * Return value 0 on success, errno on failure | |
1075 * | |
1076 *--------------------------------------------------------------------------*/ | |
1077 | |
1078 int K_DeleteFile( const char* i_sFilename ) | |
1079 { | |
1080 int bSuccess = 0; | |
1081 | |
1082 bSuccess = | |
1083 #ifdef WIN32 | |
1084 _unlink( | |
1085 #else | |
1086 unlink( | |
1087 #endif | |
1088 i_sFilename ) == 0; | |
1089 | |
1090 return bSuccess ? 0 : errno; | |
1091 } | |
1092 | |
1093 | |
1094 /*--------------------------------------------------------------------------- | |
1095 * Function: K_ReadFile | |
1096 * | |
1097 * Description: | |
1098 * Reads from the given file and passes the bytes read back to the output | |
1099 * parameter. The caller must deallocate o_ppFileData using free(). | |
1100 * | |
1101 * Input | |
1102 * ----- | |
1103 * i_sFilename Name of file from which to read | |
1104 * | |
1105 * Output | |
1106 * ------ | |
1107 * o_ppFileData Pointer to bytes read | |
1108 * | |
1109 * Return value Number of bytes read on success, -1 on failure | |
1110 * | |
1111 *--------------------------------------------------------------------------*/ | |
1112 | |
1113 int K_ReadFile( const char* i_sFilename, unsigned char** o_ppFileData ) | |
1114 { | |
1115 FILE* pFile = 0; | |
1116 long iFileSize = 0; | |
1117 | |
1118 if ( !i_sFilename || (strlen(i_sFilename) <= 0) || !o_ppFileData ) | |
1119 { | |
1120 return -1; | |
1121 } | |
1122 | |
1123 *o_ppFileData = 0; | |
1124 | |
1125 // Open the file | |
1126 | |
1127 pFile = fopen( i_sFilename, "rb" ); | |
1128 if ( !pFile ) | |
1129 { | |
1130 return -1; | |
1131 } | |
1132 | |
1133 // Determine the file size | |
1134 | |
1135 if ( fseek( pFile, 0, SEEK_END ) ) | |
1136 { | |
1137 (void) fclose( pFile ); | |
1138 return -1; | |
1139 } | |
1140 | |
1141 iFileSize = ftell( pFile ); | |
1142 if ( iFileSize < 0 ) | |
1143 { | |
1144 (void) fclose( pFile ); | |
1145 return -1; | |
1146 } | |
1147 else if ( iFileSize == 0 ) | |
1148 { | |
1149 (void) fclose( pFile ); | |
1150 return 0; | |
1151 } | |
1152 | |
1153 if ( fseek( pFile, 0, SEEK_SET ) ) | |
1154 { | |
1155 (void) fclose( pFile ); | |
1156 return -1; | |
1157 } | |
1158 | |
1159 *o_ppFileData = (unsigned char*)malloc( iFileSize ); | |
1160 if ( !*o_ppFileData ) | |
1161 { | |
1162 // Out of memory. | |
1163 (void) fclose( pFile ); | |
1164 return -1; | |
1165 } | |
1166 | |
1167 if ( iFileSize != (long)fread( *o_ppFileData, 1, iFileSize, pFile ) ) | |
1168 { | |
1169 free( *o_ppFileData ); | |
1170 *o_ppFileData = 0; | |
1171 (void) fclose( pFile ); | |
1172 return -1; | |
1173 } | |
1174 | |
1175 (void) fclose( pFile ); | |
1176 | |
1177 return iFileSize; | |
1178 } | |
1179 | |
1180 | |
1181 /*--------------------------------------------------------------------------- | |
1182 * Function: K_ReadFileString | |
1183 * | |
1184 * Description: | |
1185 * Reads from the given file and passes the bytes read back to the output | |
1186 * parameter, appending these bytes with a null terminator. There is no | |
1187 * guarantee that there are no non-text characters in the returned "string". | |
1188 * The caller must deallocate o_ppFileData using free(). | |
1189 * | |
1190 * Input | |
1191 * ----- | |
1192 * i_sFilename Name of file from which to read | |
1193 * | |
1194 * Output | |
1195 * ------ | |
1196 * o_psFileDataString Pointer to bytes read | |
1197 * | |
1198 * Return value Number of bytes read (including null terminator) on | |
1199 * success (0 if file is empty), -1 on failure | |
1200 * | |
1201 *--------------------------------------------------------------------------*/ | |
1202 | |
1203 int K_ReadFileString( const char* i_sFilename, char** o_psFileDataString ) | |
1204 { | |
1205 unsigned char* pFileData = 0; | |
1206 int iFileSize = 0; | |
1207 | |
1208 *o_psFileDataString = 0; | |
1209 | |
1210 iFileSize = K_ReadFile( i_sFilename, &pFileData ); | |
1211 | |
1212 if ( iFileSize <= 0 ) | |
1213 { | |
1214 return iFileSize; | |
1215 } | |
1216 | |
1217 *o_psFileDataString = (char*)malloc( iFileSize+1 ); | |
1218 | |
1219 if ( !*o_psFileDataString ) | |
1220 { | |
1221 // Out of memory. | |
1222 if ( pFileData ) | |
1223 { | |
1224 free( pFileData ); | |
1225 } | |
1226 return -1; | |
1227 } | |
1228 | |
1229 memcpy( *o_psFileDataString, pFileData, iFileSize ); | |
1230 | |
1231 (*o_psFileDataString)[iFileSize] = '\0'; | |
1232 | |
1233 if ( pFileData ) | |
1234 { | |
1235 free( pFileData ); | |
1236 } | |
1237 | |
1238 return iFileSize+1; | |
1239 } | |
1240 | |
1241 | |
1242 /*--------------------------------------------------------------------------- | |
1243 * Function: K_WriteFile | |
1244 * | |
1245 * Description: | |
1246 * Writes the given bytes to the given file. | |
1247 * | |
1248 * Input | |
1249 * ----- | |
1250 * i_sFilename Name of file to which to write | |
1251 * i_pFileData Bytes to write | |
1252 * i_iFileDataSize Number of bytes to write | |
1253 * | |
1254 * Output | |
1255 * ------ | |
1256 * (none) | |
1257 * | |
1258 * Return value 0 on success, errno or -1 (generic error) on failure | |
1259 * | |
1260 *--------------------------------------------------------------------------*/ | |
1261 | |
1262 int K_WriteFile( const char* i_sFilename, const unsigned char* i_pFileData, int i_iFileDataSize ) | |
1263 { | |
1264 FILE* pFile = 0; | |
1265 | |
1266 if ( !i_sFilename || (strlen(i_sFilename) <= 0) || (!i_pFileData && (i_iFileDataSize > 0)) || (i_iFileDataSize < 0) ) | |
1267 { | |
1268 return -1; | |
1269 } | |
1270 | |
1271 pFile = fopen( i_sFilename, "wb" ); | |
1272 if ( !pFile ) | |
1273 { | |
1274 int iError = errno; | |
1275 return (iError != 0) ? iError : -1; | |
1276 } | |
1277 | |
1278 if ( i_iFileDataSize > 0 ) | |
1279 { | |
1280 if ( i_iFileDataSize != (int)fwrite( i_pFileData, 1, i_iFileDataSize, pFile ) ) | |
1281 { | |
1282 int iError = ferror( pFile ); | |
1283 (void) fclose( pFile ); | |
1284 return (iError != 0) ? iError : -1; | |
1285 } | |
1286 } | |
1287 | |
1288 (void) fclose( pFile ); | |
1289 | |
1290 return 0; | |
1291 } | |
1292 | |
1293 | |
1294 /*--------------------------------------------------------------------------- | |
1295 * Function: K_WriteFileString | |
1296 * | |
1297 * Description: | |
1298 * Writes the given null-terminated bytes to the given file. The null | |
1299 * terminator itself is not written to the file. | |
1300 * | |
1301 * Input | |
1302 * ----- | |
1303 * i_sFilename Name of file to which to write | |
1304 * i_sFileData Bytes to write | |
1305 * | |
1306 * Output | |
1307 * ------ | |
1308 * (none) | |
1309 * | |
1310 * Return value 0 on success, errno or -1 (generic error) on failure | |
1311 * | |
1312 *--------------------------------------------------------------------------*/ | |
1313 | |
1314 int K_WriteFileString( const char* i_sFilename, const char* i_sFileData ) | |
1315 { | |
1316 if ( !i_sFilename || (strlen(i_sFilename) <= 0) || !i_sFileData || (strlen(i_sFileData) <= 0) ) | |
1317 { | |
1318 return -1; | |
1319 } | |
1320 | |
1321 return K_WriteFile( i_sFilename, (const unsigned char*)i_sFileData, strlen(i_sFileData) ); | |
1322 } | |
1323 | |
1324 | |
1325 /*--------------------------------------------------------------------------- | |
1326 * Function: K_FileExists | |
1327 * | |
1328 * Description: | |
1329 * Checks to see whehter the given file exists. | |
1330 * | |
1331 * Input | |
1332 * ----- | |
1333 * i_sFilename Name of file to check | |
1334 * | |
1335 * Output | |
1336 * ------ | |
1337 * (none) | |
1338 * | |
1339 * Return value 1 if file exists, 0 if not, -1 on failure | |
1340 * | |
1341 *--------------------------------------------------------------------------*/ | |
1342 | |
1343 int K_FileExists( const char* i_sFilename ) | |
1344 { | |
1345 FILE* pFile = 0; | |
1346 | |
1347 if ( !i_sFilename || (strlen(i_sFilename) <= 0) ) | |
1348 { | |
1349 return -1; | |
1350 } | |
1351 | |
1352 pFile = fopen( i_sFilename, "r+" ); | |
1353 | |
1354 if ( !pFile ) | |
1355 { | |
1356 if ( errno == ENOENT ) | |
1357 { | |
1358 return 0; | |
1359 } | |
1360 | |
1361 return -1; | |
1362 } | |
1363 | |
1364 (void) fclose( pFile ); | |
1365 | |
1366 return 1; | |
1367 } | |
1368 | |
1369 | |
1370 /*--------------------------------------------------------------------------- | |
1371 * Function: K_CopyFile | |
1372 * | |
1373 * Description: | |
1374 * Reads from the given source file and writes these bytes to the given | |
1375 * destination file. | |
1376 * | |
1377 * Input | |
1378 * ----- | |
1379 * i_sSrcFilename Name of file from which to read | |
1380 * i_sDestFilename Name of file to which to write | |
1381 * | |
1382 * Output | |
1383 * ------ | |
1384 * o_pbFileExists Non-zero if the destination file already exists | |
1385 * | |
1386 * Return value 0 on success, errno or -1 (generic error) on failure | |
1387 * | |
1388 *--------------------------------------------------------------------------*/ | |
1389 | |
1390 int K_CopyFile( const char* i_sSrcFilename, const char* i_sDestFilename, int* o_pbFileExists ) | |
1391 { | |
1392 unsigned char* pFileData = 0; | |
1393 int iFileSize = 0; | |
1394 int iError, iFileExists; | |
1395 | |
1396 if ( !i_sSrcFilename || (strlen(i_sSrcFilename) <= 0) | |
1397 || !i_sDestFilename || (strlen(i_sDestFilename) <= 0) | |
1398 || !o_pbFileExists ) | |
1399 { | |
1400 return -1; | |
1401 } | |
1402 | |
1403 *o_pbFileExists = 0; | |
1404 | |
1405 iFileExists = K_FileExists( i_sDestFilename ); | |
1406 | |
1407 if ( iFileExists < 0 ) | |
1408 { | |
1409 iError = errno; | |
1410 return (iError == 0) ? -1 : iError; | |
1411 } | |
1412 else if ( iFileExists > 0 ) | |
1413 { | |
1414 *o_pbFileExists = 1; | |
1415 return -1; | |
1416 } | |
1417 | |
1418 iFileSize = K_ReadFile( i_sSrcFilename, &pFileData ); | |
1419 if ( iFileSize < 0 ) | |
1420 { | |
1421 iError = errno; | |
1422 return (iError == 0) ? -1 : iError; | |
1423 } | |
1424 | |
1425 iError = K_WriteFile( i_sDestFilename, pFileData, iFileSize ); | |
1426 | |
1427 if ( pFileData ) | |
1428 { | |
1429 free( pFileData ); | |
1430 } | |
1431 | |
1432 return iError; | |
1433 } | |
1434 | |
1435 | |
1436 #ifdef K_LINUX_PLATFORM | |
1437 static int fts_compare( const FTSENT** i_ppF1, const FTSENT** i_ppF2 ) | |
1438 { | |
1439 return strcmp( (*i_ppF1)->fts_name, (*i_ppF2)->fts_name ); | |
1440 } | |
1441 #else | |
1442 /* | |
1443 * Directory traversal code is not yet available for Solaris. | |
1444 * If such code will need to be written, then it will probably use ftw.h. | |
1445 */ | |
1446 #endif | |
1447 | |
1448 | |
1449 /* | |
1450 * TODO: Set up functions for platform-specific find-file operations to | |
1451 * help clean up the code below. | |
1452 */ | |
1453 | |
1454 typedef struct K_FindInfo | |
1455 { | |
1456 #ifdef WIN32 | |
1457 struct _finddata_t m_stFindData; | |
1458 long m_hFile; | |
1459 #elif defined K_LINUX_PLATFORM | |
1460 FTS* m_pFTS; | |
1461 FTSENT* m_pFTSENT; | |
1462 #else | |
1463 /* | |
1464 * Directory traversal code is not yet available for Solaris. | |
1465 * If such code will need to be written, then it will probably use ftw.h. | |
1466 */ | |
1467 int unused; | |
1468 #endif | |
1469 } K_FindInfo; | |
1470 | |
1471 // Memory for filename is held in i_pFindInfo. | |
1472 const char* K_GetFilenameFromInfo( const K_FindInfo* i_pFindInfo ) | |
1473 { | |
1474 if( !i_pFindInfo ) | |
1475 { | |
1476 return 0; | |
1477 } | |
1478 | |
1479 #ifdef WIN32 | |
1480 return i_pFindInfo->m_stFindData.name; | |
1481 #elif defined K_LINUX_PLATFORM | |
1482 return i_pFindInfo->m_pFTSENT->fts_name; | |
1483 #else | |
1484 /* | |
1485 * Directory traversal code is not yet available for Solaris. | |
1486 * If such code will need to be written, then it will probably use ftw.h. | |
1487 */ | |
1488 FATAL_ASSERT( 0 ); | |
1489 return 0; | |
1490 #endif | |
1491 } | |
1492 | |
1493 // Forward declarations | |
1494 int K_FindFileNext( K_FindInfo* io_pFindInfo ); | |
1495 void K_FindFileClose( K_FindInfo* io_pFindInfo ); | |
1496 | |
1497 // Returns 0 if successful, 1 if not found, -1 if error. | |
1498 // If not error, K_FindFileClose must be called. | |
1499 // o_pFindInfo must not be null. | |
1500 int K_FindFileFirst( const char* i_sDirectoryName, K_FindInfo* o_pFindInfo ) | |
1501 { | |
1502 #ifdef WIN32 | |
1503 char* sSearchString = 0; | |
1504 int iSearchStringIndex = 0; | |
1505 #endif | |
1506 | |
1507 if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) || !o_pFindInfo ) | |
1508 { | |
1509 return -1; | |
1510 } | |
1511 | |
1512 #ifdef WIN32 | |
1513 memset( o_pFindInfo, 0, sizeof(K_FindInfo) ); | |
1514 | |
1515 iSearchStringIndex = strlen(i_sDirectoryName); | |
1516 if ( i_sDirectoryName[iSearchStringIndex-1] == PATH_SEPARATOR ) | |
1517 { | |
1518 iSearchStringIndex += 2; | |
1519 } | |
1520 else | |
1521 { | |
1522 iSearchStringIndex += 3; | |
1523 } | |
1524 | |
1525 sSearchString = (char*)calloc( iSearchStringIndex, 1 ); | |
1526 if ( !sSearchString ) | |
1527 { | |
1528 return -1; | |
1529 } | |
1530 | |
1531 strcpy( sSearchString, i_sDirectoryName ); | |
1532 iSearchStringIndex--; | |
1533 sSearchString[iSearchStringIndex] = '\0'; | |
1534 iSearchStringIndex--; | |
1535 sSearchString[iSearchStringIndex] = '*'; | |
1536 iSearchStringIndex--; | |
1537 sSearchString[iSearchStringIndex] = PATH_SEPARATOR; | |
1538 | |
1539 o_pFindInfo->m_hFile = _findfirst( sSearchString, &o_pFindInfo->m_stFindData ); | |
1540 free( sSearchString ); | |
1541 if ( o_pFindInfo->m_hFile == -1 ) | |
1542 { | |
1543 if ( errno == ENOENT ) | |
1544 { | |
1545 return 1; | |
1546 } | |
1547 else | |
1548 { | |
1549 return -1; | |
1550 } | |
1551 } | |
1552 #elif defined K_LINUX_PLATFORM | |
1553 memset( o_pFindInfo, 0, sizeof(K_FindInfo) ); | |
1554 | |
1555 o_pFindInfo->m_pFTS = fts_open( aPath, FTS_PHYSICAL | FTS_NOSTAT, fts_compare ); | |
1556 if ( !o_pFindInfo->m_pFTS ) | |
1557 { | |
1558 return -1; | |
1559 } | |
1560 | |
1561 o_pFindInfo->m_pFTSENT = fts_read( o_pFindInfo->m_pFTS ); | |
1562 if ( !o_pFindInfo->m_pFTSENT ) | |
1563 { | |
1564 if ( errno == 0 ) | |
1565 { | |
1566 return 1; | |
1567 } | |
1568 else | |
1569 { | |
1570 fts_close( o_pFindInfo->m_pFTS ); | |
1571 return -1; | |
1572 } | |
1573 } | |
1574 #else | |
1575 /* | |
1576 * Directory traversal code is not yet available for Solaris. | |
1577 * If such code will need to be written, then it will probably use ftw.h. | |
1578 */ | |
1579 #endif | |
1580 | |
1581 // If what we found is not actually a file, get the next hit. | |
1582 #ifdef WIN32 | |
1583 if ( (o_pFindInfo->m_stFindData.attrib & _A_SUBDIR) ) | |
1584 #elif defined K_LINUX_PLATFORM | |
1585 if ( !(o_pFindInfo->m_pFTSENT->fts_info & FTS_F) ) | |
1586 #else | |
1587 /* | |
1588 * Directory traversal code is not yet available for Solaris. | |
1589 * If such code will need to be written, then it will probably use ftw.h. | |
1590 */ | |
1591 #endif | |
1592 { | |
1593 int iNextReturn = K_FindFileNext( o_pFindInfo ); | |
1594 if ( iNextReturn < 0 ) | |
1595 { | |
1596 K_FindFileClose( o_pFindInfo ); | |
1597 return -1; | |
1598 } | |
1599 else | |
1600 { | |
1601 return iNextReturn; | |
1602 } | |
1603 } | |
1604 | |
1605 #if defined(WIN32) || defined(K_LINUX_PLATFORM) | |
1606 return 0; | |
1607 #endif | |
1608 } | |
1609 | |
1610 // Returns 0 if successful, 1 if not found, -1 if error. | |
1611 int K_FindFileNext( K_FindInfo* io_pFindInfo ) | |
1612 { | |
1613 if ( !io_pFindInfo ) | |
1614 { | |
1615 return -1; | |
1616 } | |
1617 | |
1618 #ifdef WIN32 | |
1619 if ( _findnext( io_pFindInfo->m_hFile, &io_pFindInfo->m_stFindData ) != 0 ) | |
1620 { | |
1621 return (errno == ENOENT) ? 1 : -1; | |
1622 } | |
1623 #elif defined K_LINUX_PLATFORM | |
1624 io_pFindInfo->m_pFTSENT = fts_read( io_pFindInfo->m_pFTS ); | |
1625 if ( !io_pFindInfo->m_pFTSENT ) | |
1626 { | |
1627 return (errno == 0) ? 1 : -1; | |
1628 } | |
1629 #else | |
1630 /* | |
1631 * Directory traversal code is not yet available for Solaris. | |
1632 * If such code will need to be written, then it will probably use ftw.h. | |
1633 */ | |
1634 #endif | |
1635 | |
1636 // If what we found is not actually a file, get the next hit. | |
1637 #ifdef WIN32 | |
1638 if ( (io_pFindInfo->m_stFindData.attrib & _A_SUBDIR) ) | |
1639 #elif defined K_LINUX_PLATFORM | |
1640 if ( !(io_pFindInfo->m_pFTSENT->fts_info & FTS_F) ) | |
1641 #else | |
1642 /* | |
1643 * Directory traversal code is not yet available for Solaris. | |
1644 * If such code will need to be written, then it will probably use ftw.h. | |
1645 */ | |
1646 #endif | |
1647 { | |
1648 return K_FindFileNext( io_pFindInfo ); | |
1649 } | |
1650 | |
1651 #if defined(WIN32) || defined(K_LINUX_PLATFORM) | |
1652 return 0; | |
1653 #endif | |
1654 } | |
1655 | |
1656 void K_FindFileClose( K_FindInfo* io_pFindInfo ) | |
1657 { | |
1658 if ( !io_pFindInfo ) | |
1659 { | |
1660 return; | |
1661 } | |
1662 | |
1663 #ifdef WIN32 | |
1664 _findclose( io_pFindInfo->m_hFile ); | |
1665 #elif defined K_LINUX_PLATFORM | |
1666 fts_close( io_pFindInfo->m_pFTS ); | |
1667 #else | |
1668 /* | |
1669 * Directory traversal code is not yet available for Solaris. | |
1670 * If such code will need to be written, then it will probably use ftw.h. | |
1671 */ | |
1672 #endif | |
1673 } | |
1674 | |
1675 | |
1676 /*--------------------------------------------------------------------------- | |
1677 * Function: K_GetFilenamesInDirectoryCount | |
1678 * | |
1679 * Description: | |
1680 * Reads the given directory and returns the number of files that it contains. | |
1681 * | |
1682 * Input | |
1683 * ----- | |
1684 * i_sDirectoryName Name of directory | |
1685 * | |
1686 * Output | |
1687 * ------ | |
1688 * (none) | |
1689 * | |
1690 * Return value Number of files on success, -1 on failure | |
1691 * | |
1692 *--------------------------------------------------------------------------*/ | |
1693 | |
1694 int K_GetFilenamesInDirectoryCount( const char* i_sDirectoryName ) | |
1695 { | |
1696 K_FindInfo stFindInfo; | |
1697 int iCurrentFile = 0; | |
1698 int iError = 0; | |
1699 | |
1700 if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) ) | |
1701 { | |
1702 return -1; | |
1703 } | |
1704 | |
1705 iError = K_FindFileFirst( i_sDirectoryName, &stFindInfo ); | |
1706 if ( iError < 0 ) | |
1707 { | |
1708 // error | |
1709 return -1; | |
1710 } | |
1711 else if ( iError > 0 ) | |
1712 { | |
1713 // no files found | |
1714 K_FindFileClose( &stFindInfo ); | |
1715 return 0; | |
1716 } | |
1717 | |
1718 while ( 1 ) | |
1719 { | |
1720 iCurrentFile++; | |
1721 | |
1722 iError = K_FindFileNext( &stFindInfo ); | |
1723 if ( iError < 0 ) | |
1724 { | |
1725 // error | |
1726 K_FindFileClose( &stFindInfo ); | |
1727 return -1; | |
1728 } | |
1729 else if ( iError > 0 ) | |
1730 { | |
1731 // no more files found | |
1732 break; | |
1733 } | |
1734 } | |
1735 | |
1736 K_FindFileClose( &stFindInfo ); | |
1737 | |
1738 return iCurrentFile; | |
1739 } | |
1740 | |
1741 | |
1742 /*--------------------------------------------------------------------------- | |
1743 * Function: K_GetFilenamesInDirectory | |
1744 * | |
1745 * Description: | |
1746 * Reads the given directory and returns an array of names of files that it | |
1747 * contains. A null pointer appears at the last item in the array. The | |
1748 * caller must deallocate o_pasFilenames by using K_FreeFilenames or by | |
1749 * calling free() for each file name and then calling free() on the array | |
1750 * itself. | |
1751 * | |
1752 * Input | |
1753 * ----- | |
1754 * i_sDirectoryName Name of directory | |
1755 * | |
1756 * Output | |
1757 * ------ | |
1758 * o_pasFilenames Array of names of files found in this directory | |
1759 * | |
1760 * Return value Number of files on success, -1 on failure | |
1761 * | |
1762 *--------------------------------------------------------------------------*/ | |
1763 | |
1764 int K_GetFilenamesInDirectory( | |
1765 const char* i_sDirectoryName, | |
1766 char*** o_pasFilenames ) | |
1767 { | |
1768 // Note that we iterate through the filenames twice -- once to get the count | |
1769 // (K_GetFilenamesInDirectoryCount) and then once to get all the names. But | |
1770 // it may happen that the count changes between these calls. So we'll retrieve | |
1771 // at most the number of files that's returned in the first pass. | |
1772 | |
1773 K_FindInfo stFindInfo; | |
1774 int iFilenameCount = 0, iCurrentFile = 0; | |
1775 int iError = 0; | |
1776 | |
1777 if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) || !o_pasFilenames ) | |
1778 { | |
1779 return -1; | |
1780 } | |
1781 | |
1782 *o_pasFilenames = 0; | |
1783 | |
1784 iFilenameCount = K_GetFilenamesInDirectoryCount( i_sDirectoryName ); | |
1785 | |
1786 if ( iFilenameCount < 0 ) | |
1787 { | |
1788 return -1; | |
1789 } | |
1790 | |
1791 iError = K_FindFileFirst( i_sDirectoryName, &stFindInfo ); | |
1792 if ( iError < 0 ) | |
1793 { | |
1794 // error | |
1795 return -1; | |
1796 } | |
1797 else if ( iError > 0 ) | |
1798 { | |
1799 // No files found | |
1800 K_FindFileClose( &stFindInfo ); | |
1801 return 0; | |
1802 } | |
1803 | |
1804 *o_pasFilenames = (char**)calloc( (iFilenameCount+1), sizeof(char*) ); // +1 for the null last one | |
1805 if ( !*o_pasFilenames ) | |
1806 { | |
1807 // Out of memory | |
1808 K_FindFileClose( &stFindInfo ); | |
1809 return -1; | |
1810 } | |
1811 | |
1812 while ( 1 ) | |
1813 { | |
1814 const char* sFilename = K_GetFilenameFromInfo( &stFindInfo ); | |
1815 | |
1816 size_t iFilenameLength = sFilename ? strlen( sFilename ) : 0; | |
1817 | |
1818 if ( iFilenameLength <= 0 ) | |
1819 { | |
1820 K_FreeFilenames( *o_pasFilenames ); | |
1821 K_FindFileClose( &stFindInfo ); | |
1822 return -1; | |
1823 } | |
1824 | |
1825 (*o_pasFilenames)[iCurrentFile] = (char*)calloc( (iFilenameLength+1), sizeof(char) ); | |
1826 if ( !(*o_pasFilenames)[iCurrentFile] ) | |
1827 { | |
1828 K_FreeFilenames( *o_pasFilenames ); | |
1829 K_FindFileClose( &stFindInfo ); | |
1830 return -1; | |
1831 } | |
1832 | |
1833 strncpy( (*o_pasFilenames)[iCurrentFile], sFilename, iFilenameLength ); | |
1834 (*o_pasFilenames)[iCurrentFile][iFilenameLength] = '\0'; | |
1835 | |
1836 iCurrentFile++; | |
1837 | |
1838 if ( iCurrentFile >= iFilenameCount ) | |
1839 { | |
1840 break; | |
1841 } | |
1842 | |
1843 iError = K_FindFileNext( &stFindInfo ); | |
1844 if ( iError < 0 ) | |
1845 { | |
1846 // error | |
1847 K_FindFileClose( &stFindInfo ); | |
1848 return -1; | |
1849 } | |
1850 else if ( iError > 0 ) | |
1851 { | |
1852 // no more files found | |
1853 break; | |
1854 } | |
1855 } | |
1856 | |
1857 K_FindFileClose( &stFindInfo ); | |
1858 | |
1859 return iCurrentFile; | |
1860 } | |
1861 | |
1862 | |
1863 /*--------------------------------------------------------------------------- | |
1864 * Function: K_FreeFilenames | |
1865 * | |
1866 * Description: | |
1867 * Deallocates the memory allocated in a successful call to | |
1868 * K_GetFilenamesInDirectory. | |
1869 * | |
1870 * Input | |
1871 * ----- | |
1872 * i_asFilenames Array of names of files | |
1873 * | |
1874 * Output | |
1875 * ------ | |
1876 * (none) | |
1877 * | |
1878 * Return value (none) | |
1879 * | |
1880 *--------------------------------------------------------------------------*/ | |
1881 | |
1882 void K_FreeFilenames( char** i_asFilenames ) | |
1883 { | |
1884 int i; | |
1885 | |
1886 if ( !i_asFilenames ) | |
1887 { | |
1888 return; | |
1889 } | |
1890 | |
1891 for ( i = 0; (i_asFilenames[i] != 0); i++ ) | |
1892 { | |
1893 free( i_asFilenames[i] ); | |
1894 i_asFilenames[i] = 0; | |
1895 } | |
1896 | |
1897 free( i_asFilenames ); | |
1898 } | |
1899 | |
1900 | |
1901 /*--------------------------------------------------------------------------- | |
1902 * Function: K_AdjustLocalClock | |
1903 * | |
1904 * Description: | |
1905 * The K_AdjustLocalClock function gradually adjusts the system clock by | |
1906 * the given number of seconds. A positive number adjusts the system | |
1907 * clock forward; a negative number adjusts the system clock backward. | |
1908 * | |
1909 * Input | |
1910 * ----- | |
1911 * i_iAdjustmentInSeconds Number of seconds by which to adjust the | |
1912 * system clock | |
1913 * Output | |
1914 * ------ | |
1915 * (none) | |
1916 * | |
1917 * Return value 1 if successful, 0 on error | |
1918 * | |
1919 *--------------------------------------------------------------------------*/ | |
1920 | |
1921 int K_AdjustLocalClock( int i_iNumberOfSeconds ) | |
1922 { | |
1923 struct timeval delta, lastchange; | |
1924 | |
1925 #ifndef K_SOLARIS_PLATFORM | |
1926 /* Only supported/tested on Solaris at the moment */ | |
1927 | |
1928 return -1; | |
1929 #else | |
1930 /* WARNING: uses standard C time functions with Year 2038 limitations */ | |
1931 time_t now; | |
1932 | |
1933 if ( (now = time(NULL)) == ((time_t)-1) ) | |
1934 { | |
1935 return -1; | |
1936 } | |
1937 | |
1938 delta.tv_sec = i_iNumberOfSeconds; | |
1939 delta.tv_usec = 0; | |
1940 | |
1941 return adjtime(&delta, &lastchange); | |
1942 #endif | |
1943 } | |
1944 | |
1945 | |
1946 #ifdef K_SOLARIS_PLATFORM | |
1947 static int pam_tty_conv( | |
1948 int num_msg, | |
1949 struct pam_message** mess, | |
1950 struct pam_response** resp, | |
1951 void* my_data) | |
1952 { | |
1953 // Following code implements a console-based PAM "conversation" function | |
1954 // (based sample code from Solaris 10 Software Developer Collection >> | |
1955 // Solaris Security for Developers Guide >> | |
1956 // 3. Writing PAM Applications and Services) | |
1957 | |
1958 struct pam_message* m = *mess; | |
1959 struct pam_response* r; | |
1960 int i, j; | |
1961 const char* sPassword = (const char*)my_data; | |
1962 int error = PAM_CONV_ERR; | |
1963 | |
1964 if (num_msg <= 0 || num_msg >= PAM_MAX_NUM_MSG) | |
1965 { | |
1966 (void) fprintf(stderr, "PAM error: bad number of messages"); | |
1967 *resp = NULL; | |
1968 return (PAM_CONV_ERR); | |
1969 } | |
1970 | |
1971 if ((*resp = r = calloc(num_msg, sizeof (struct pam_response))) == NULL) | |
1972 { | |
1973 return (PAM_BUF_ERR); | |
1974 } | |
1975 | |
1976 // Loop through messages | |
1977 for (i = 0; i < num_msg; i++) { | |
1978 | |
1979 // bad message from service module | |
1980 if (m->msg == NULL) | |
1981 { | |
1982 (void) fprintf(stderr, "PAM error: bad message"); | |
1983 goto err; | |
1984 } | |
1985 | |
1986 // fix up final newline: removed for prompts, added back for messages | |
1987 if (m->msg[strlen(m->msg)] == '\n') | |
1988 { | |
1989 m->msg[strlen(m->msg)] = '\0'; | |
1990 } | |
1991 | |
1992 // Since the KMA has its own password prompts and enforces its own rule checks, we already have the | |
1993 // new password in memory. So instead of displaying PAM prompts and collecting user responses, we | |
1994 // "automate" by assuming that the prompts correspond to the standard sequence of "New password:" | |
1995 // followed by "Confirm password:" and so in each case we immediately return the password we already | |
1996 // have in memory. This violates the PAM "conversation" function instructions (which say, basically, | |
1997 // not to assume any particular sequence of prompts since there could be any number of underlying | |
1998 // password managers), but since the KMA is running on an appliance with a fixed password manager, | |
1999 // our assumptions should hold. | |
2000 | |
2001 r->resp = NULL; | |
2002 r->resp_retcode = 0; | |
2003 switch (m->msg_style) | |
2004 { | |
2005 case PAM_PROMPT_ECHO_OFF: | |
2006 case PAM_PROMPT_ECHO_ON: | |
2007 // Assume the prompt asked for New/Confirm password, so return password. | |
2008 if ( (r->resp = strdup(sPassword)) == NULL ) | |
2009 { | |
2010 error = PAM_BUF_ERR; | |
2011 goto err; | |
2012 } | |
2013 break; | |
2014 | |
2015 case PAM_ERROR_MSG: | |
2016 // Assuming the system is configured properly and the KMA password prompts enforce password strength rules, | |
2017 // there should not be errors because of weak passwords, etc. Still, print errors so users/support can | |
2018 // diagnose problems. | |
2019 (void) fputs(m->msg, stderr); | |
2020 (void) fputc('\n', stderr); | |
2021 break; | |
2022 | |
2023 case PAM_TEXT_INFO: | |
2024 // Supress prompts (again, making assumptions). | |
2025 break; | |
2026 | |
2027 default: | |
2028 (void) fprintf(stderr, "PAM error: unknown message"); | |
2029 goto err; | |
2030 } | |
2031 if (errno == EINTR) | |
2032 { | |
2033 goto err; | |
2034 } | |
2035 | |
2036 // next message/response | |
2037 m++; | |
2038 r++; | |
2039 } | |
2040 return (PAM_SUCCESS); | |
2041 | |
2042 err: | |
2043 // Service modules do not clean up responses if an error is returned. | |
2044 // Free responses here. | |
2045 for (j = 0; j < i; j++, r++) | |
2046 { | |
2047 if (r->resp) | |
2048 { | |
2049 // clear before freeing -- may be a password | |
2050 bzero(r->resp, strlen(r->resp)); | |
2051 free(r->resp); | |
2052 r->resp = NULL; | |
2053 } | |
2054 } | |
2055 free(r); | |
2056 *resp = NULL; | |
2057 return error; | |
2058 } | |
2059 #endif | |
2060 | |
2061 | |
2062 /*--------------------------------------------------------------------------- | |
2063 * Function: K_SetRootPassword | |
2064 * | |
2065 * Description: | |
2066 * The K_SetRootPassword function sets the password for the root user via | |
2067 * Pluggable Authentication Module (PAM). This function is interactive. | |
2068 * | |
2069 * Input | |
2070 * ----- | |
2071 * i_sPassword Password to set | |
2072 * | |
2073 * Output | |
2074 * ------ | |
2075 * (none) | |
2076 * | |
2077 * Return value 0 if successful, -1 on error | |
2078 * | |
2079 *--------------------------------------------------------------------------*/ | |
2080 | |
2081 int K_SetRootPassword( const char* i_sPassword ) | |
2082 { | |
2083 // Only supported/tested on Solaris at the moment | |
2084 #ifndef K_SOLARIS_PLATFORM | |
2085 return -1; | |
2086 #else | |
2087 // Based on sample code from Solaris 10 Software Developer Collection >> | |
2088 // Solaris Security for Developers Guide >> | |
2089 // 3. Writing PAM Applications and Services | |
2090 | |
2091 // TODO: Return PAM error codes (to be logged) instead of emitting | |
2092 // messages to screen? | |
2093 | |
2094 struct pam_conv conv; | |
2095 pam_handle_t *pamh; | |
2096 int err; | |
2097 | |
2098 conv.conv = pam_tty_conv; | |
2099 conv.appdata_ptr = (void*)i_sPassword; | |
2100 | |
2101 // Initialize PAM framework | |
2102 err = pam_start("KeyMgr", "root", &conv, &pamh); | |
2103 if (err != PAM_SUCCESS) | |
2104 { | |
2105 fprintf(stderr, "PAM error: %s\n", pam_strerror(pamh, err)); | |
2106 return -1; | |
2107 } | |
2108 | |
2109 // Change password | |
2110 err = pam_chauthtok(pamh, 0); | |
2111 if (err != PAM_SUCCESS) | |
2112 { | |
2113 fprintf(stderr, "PAM error: %s\n", pam_strerror(pamh, err)); | |
2114 // fall through to cleanup | |
2115 } | |
2116 | |
2117 // Cleanup session | |
2118 pam_end(pamh, 0); | |
2119 | |
2120 return (err == PAM_SUCCESS) ? 0 : -1; | |
2121 #endif | |
2122 } | |
2123 | |
2124 | |
2125 /*--------------------------------------------------------------------------- | |
2126 * Function: K_Alarm | |
2127 * | |
2128 * Description: | |
2129 * Calls alarm(2) on Unix in order to cause the operating system to generate | |
2130 * a SIGALRM signal for this process after the given number of real-time | |
2131 * seconds. Does nothing on Windows. | |
2132 * | |
2133 * Input | |
2134 * ----- | |
2135 * i_iSeconds Number of seconds after which to generate a SIGALRM | |
2136 * signal | |
2137 * | |
2138 * Output | |
2139 * ------ | |
2140 * (none) | |
2141 * | |
2142 * Return value If a previous alarm request is pending, then it returns | |
2143 * the number of seconds until this previous request would | |
2144 * have generated a SIGALRM signal. Otherwise, returns 0. | |
2145 * | |
2146 *--------------------------------------------------------------------------*/ | |
2147 | |
2148 unsigned int K_Alarm( unsigned int i_iSeconds ) | |
2149 { | |
2150 #ifndef WIN32 | |
2151 return alarm( i_iSeconds ); | |
2152 #else | |
2153 return 0; | |
2154 #endif | |
2155 } | |
2156 | |
2157 | |
2158 /*--------------------------------------------------------------------------- | |
2159 * Function: K_GetExtendedVersionFromBase | |
2160 * | |
2161 * Description: | |
2162 * This KMS-specific function prepends the timestamp value to the specified | |
2163 * base replication schema version and returns this value as an extended | |
2164 * replication schema version. | |
2165 * | |
2166 * Input | |
2167 * ----- | |
2168 * i_iBaseSchemaVersion Base replication schema version | |
2169 * | |
2170 * Output | |
2171 * ------ | |
2172 * (none) | |
2173 * | |
2174 * Return value Extended replication schema version | |
2175 * | |
2176 *--------------------------------------------------------------------------*/ | |
2177 | |
2178 unsigned int K_GetExtendedVersionFromBase( unsigned int i_iBaseSchemaVersion ) | |
2179 { | |
2180 // seconds since 1970, force to 32-bit | |
2181 #ifdef WIN32 | |
2182 INT32 iTimeStamp = (INT32) time(NULL); | |
2183 #else | |
2184 int32_t iTimeStamp = (int32_t) time(NULL); | |
2185 #endif | |
2186 // minutes since 1970 | |
2187 iTimeStamp = iTimeStamp / 60; | |
2188 // minutes since 2000 (approximately) | |
2189 iTimeStamp -= (30*365*24*60); | |
2190 // shift 8 bits to clear out room for schema version # | |
2191 iTimeStamp = iTimeStamp << 8; | |
2192 // add schema version # to lower end | |
2193 iTimeStamp |= i_iBaseSchemaVersion; | |
2194 | |
2195 return (unsigned int) iTimeStamp; | |
2196 | |
2197 } | |
2198 | |
2199 | |
2200 /*--------------------------------------------------------------------------- | |
2201 * Function: K_ParseTimestampFromExtendedVersion | |
2202 * | |
2203 * Description: | |
2204 * This KMS-specific function parses the timestamp value from the given | |
2205 * extended replication schema version and returns this timestamp value. | |
2206 * | |
2207 * Input | |
2208 * ----- | |
2209 * i_iExtendedSchemaVersion Extended replication schema version | |
2210 * | |
2211 * Output | |
2212 * ------ | |
2213 * (none) | |
2214 * | |
2215 * Return value Timestamp value | |
2216 * | |
2217 *--------------------------------------------------------------------------*/ | |
2218 | |
2219 unsigned int K_ParseTimestampFromExtendedVersion( | |
2220 unsigned int i_iExtendedSchemaVersion ) | |
2221 { | |
2222 unsigned int iTimeStamp = i_iExtendedSchemaVersion >> 8; | |
2223 | |
2224 return iTimeStamp; | |
2225 } | |
2226 | |
2227 | |
2228 /*--------------------------------------------------------------------------- | |
2229 * Function: K_ParseBaseFromExtendedVersion | |
2230 * | |
2231 * Description: | |
2232 * This KMS-specific function parses the base replication schema value from | |
2233 * the given extended replication schema version and returns this base value. | |
2234 * | |
2235 * Input | |
2236 * ----- | |
2237 * i_iExtendedSchemaVersion Extended replication schema version | |
2238 * | |
2239 * Output | |
2240 * ------ | |
2241 * (none) | |
2242 * | |
2243 * Return value Base replication schema value | |
2244 * | |
2245 *--------------------------------------------------------------------------*/ | |
2246 | |
2247 unsigned int K_ParseBaseFromExtendedVersion( | |
2248 unsigned int i_iExtendedSchemaVersion ) | |
2249 { | |
2250 unsigned int iBaseSchemaVersion = i_iExtendedSchemaVersion & 0x000000FF; | |
2251 | |
2252 return iBaseSchemaVersion; | |
2253 } | |
2254 | |
2255 | |
2256 /*--------------------------------------------------------------------------- | |
2257 * Function: K_System | |
2258 * | |
2259 * Description: | |
2260 * This function is a thread-safe replacement for the unsafe system(3C) call. | |
2261 * See the popen(3C) man page for more information. | |
2262 * | |
2263 * Input | |
2264 * ----- | |
2265 * i_sCmd Command to execute | |
2266 * | |
2267 * Output | |
2268 * ------ | |
2269 * (none) | |
2270 * | |
2271 * Return value Termination status of the command language interpreter | |
2272 * if successful, -1 on failure | |
2273 * | |
2274 *--------------------------------------------------------------------------*/ | |
2275 | |
2276 int K_System( const char *i_sCmd ) | |
2277 { | |
2278 #ifndef WIN32 | |
2279 FILE *p; | |
2280 int rc; | |
2281 struct sigaction sOldAction; | |
2282 | |
2283 // Save signal handler | |
2284 sigaction( SIGCHLD, NULL, &sOldAction ); | |
2285 | |
2286 // Use default child signal handler | |
2287 sigset( SIGCHLD, SIG_DFL ); | |
2288 | |
2289 p = popen( i_sCmd, "w" ); | |
2290 if ( p == NULL ) | |
2291 { | |
2292 rc = -1; | |
2293 } | |
2294 else | |
2295 { | |
2296 rc = pclose( p ); | |
2297 } | |
2298 | |
2299 // Reset signal handler | |
2300 sigset( SIGCHLD, sOldAction.sa_handler ); | |
2301 | |
2302 return rc; | |
2303 #else | |
2304 return system( i_sCmd ); | |
2305 #endif | |
2306 } | |
2307 |