]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/umapfile.c
ICU-8.11.tar.gz
[apple/icu.git] / icuSources / common / umapfile.c
CommitLineData
b75a7d8f
A
1/*
2******************************************************************************
3*
73c04bcf 4* Copyright (C) 1999-2006, International Business Machines
b75a7d8f
A
5* Corporation and others. All Rights Reserved.
6*
7******************************************************************************/
8
9
10/*----------------------------------------------------------------------------
11 *
12 * Memory mapped file wrappers for use by the ICU Data Implementation
13 * All of the platform-specific implementation for mapping data files
14 * is here. The rest of the ICU Data implementation uses only the
15 * wrapper functions.
16 *
17 *----------------------------------------------------------------------------*/
374ca955 18#include "unicode/putil.h"
b75a7d8f
A
19
20
21#include "udatamem.h"
22#include "umapfile.h"
23
b75a7d8f
A
24/* memory-mapping base definitions ------------------------------------------ */
25
73c04bcf
A
26/* MAP_NONE: no memory mapping, no file access at all */
27#define MAP_NONE 0
b75a7d8f
A
28#define MAP_WIN32 1
29#define MAP_POSIX 2
73c04bcf 30#define MAP_STDIO 3
b75a7d8f
A
31#define MAP_390DLL 4
32
73c04bcf
A
33#if UCONFIG_NO_FILE_IO
34# define MAP_IMPLEMENTATION MAP_NONE
35#elif defined(U_WINDOWS)
b75a7d8f 36# define WIN32_LEAN_AND_MEAN
374ca955 37# define VC_EXTRALEAN
b75a7d8f
A
38# define NOUSER
39# define NOSERVICE
40# define NOIME
41# define NOMCX
42# include <windows.h>
73c04bcf 43# include "cmemory.h"
b75a7d8f
A
44
45 typedef HANDLE MemoryMap;
46
47# define IS_MAP(map) ((map)!=NULL)
48
49# define MAP_IMPLEMENTATION MAP_WIN32
50
51/* ### Todo: properly auto detect mmap(). Until then, just add your platform here. */
73c04bcf 52#elif U_HAVE_MMAP || defined(U_AIX) || defined(U_HPUX) || defined(OS390)
b75a7d8f
A
53 typedef size_t MemoryMap;
54
55# define IS_MAP(map) ((map)!=0)
56
57 /* Needed by OSF to get the correct mmap version */
58# ifndef _XOPEN_SOURCE_EXTENDED
59# define _XOPEN_SOURCE_EXTENDED
60# endif
61
62# include <unistd.h>
63# include <sys/mman.h>
64# include <sys/stat.h>
65# include <fcntl.h>
66
67# ifndef MAP_FAILED
68# define MAP_FAILED ((void*)-1)
69# endif
70
71# if defined(OS390) && defined (OS390_STUBDATA)
72 /* No memory mapping for 390 batch mode. Fake it using dll loading. */
73# include <dll.h>
74# include "cstring.h"
75# include "cmemory.h"
76# include "unicode/udata.h"
77# define LIB_PREFIX "lib"
78# define LIB_SUFFIX ".dll"
79# define MAP_IMPLEMENTATION MAP_390DLL
80
81/* This is inconvienient until we figure out what to do with U_ICUDATA_NAME in utypes.h */
82# define U_ICUDATA_ENTRY_NAME "icudt" U_ICU_VERSION_SHORT U_LIB_SUFFIX_C_NAME_STRING "_dat"
83# else
84# define MAP_IMPLEMENTATION MAP_POSIX
85# endif
86
73c04bcf 87#else /* unknown platform, no memory map implementation: use stdio.h and uprv_malloc() instead */
b75a7d8f 88
73c04bcf 89# include <stdio.h>
b75a7d8f
A
90# include "cmemory.h"
91
92 typedef void *MemoryMap;
93
94# define IS_MAP(map) ((map)!=NULL)
95
73c04bcf 96# define MAP_IMPLEMENTATION MAP_STDIO
b75a7d8f
A
97
98#endif
99
100
101
102
103/*----------------------------------------------------------------------------*
104 * *
105 * Memory Mapped File support. Platform dependent implementation of *
106 * functions used by the rest of the implementation.*
107 * *
108 *----------------------------------------------------------------------------*/
73c04bcf
A
109#if MAP_IMPLEMENTATION==MAP_NONE
110 UBool
111 uprv_mapFile(UDataMemory *pData, const char *path) {
112 UDataMemory_init(pData); /* Clear the output struct. */
113 return FALSE; /* no file access */
114 }
115
116 void uprv_unmapFile(UDataMemory *pData) {
117 /* nothing to do */
118 }
119#elif MAP_IMPLEMENTATION==MAP_WIN32
b75a7d8f
A
120 UBool
121 uprv_mapFile(
122 UDataMemory *pData, /* Fill in with info on the result doing the mapping. */
123 /* Output only; any original contents are cleared. */
124 const char *path /* File path to be opened/mapped */
125 )
126 {
127 HANDLE map;
128 HANDLE file;
73c04bcf
A
129 SECURITY_ATTRIBUTES mappingAttributes;
130 SECURITY_ATTRIBUTES *mappingAttributesPtr = NULL;
131 SECURITY_DESCRIPTOR securityDesc;
b75a7d8f
A
132
133 UDataMemory_init(pData); /* Clear the output struct. */
134
135 /* open the input file */
136 file=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL,
137 OPEN_EXISTING,
138 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL);
139 if(file==INVALID_HANDLE_VALUE) {
140 return FALSE;
141 }
142
73c04bcf
A
143 /* Declare and initialize a security descriptor.
144 This is required for multiuser systems on Windows 2000 SP4 and beyond */
145 if (InitializeSecurityDescriptor(&securityDesc, SECURITY_DESCRIPTOR_REVISION)) {
146 /* give the security descriptor a Null Dacl done using the "TRUE, (PACL)NULL" here */
147 if (SetSecurityDescriptorDacl(&securityDesc, TRUE, (PACL)NULL, FALSE)) {
148 /* Make the security attributes point to the security descriptor */
149 uprv_memset(&mappingAttributes, 0, sizeof(mappingAttributes));
150 mappingAttributes.nLength = sizeof(mappingAttributes);
151 mappingAttributes.lpSecurityDescriptor = &securityDesc;
152 mappingAttributes.bInheritHandle = FALSE; /* object uninheritable */
153 mappingAttributesPtr = &mappingAttributes;
154 }
155 }
156 /* else creating security descriptors can fail when we are on Windows 98,
157 and mappingAttributesPtr == NULL for that case. */
158
b75a7d8f 159 /* create an unnamed Windows file-mapping object for the specified file */
73c04bcf 160 map=CreateFileMapping(file, mappingAttributesPtr, PAGE_READONLY, 0, 0, NULL);
b75a7d8f
A
161 CloseHandle(file);
162 if(map==NULL) {
163 return FALSE;
164 }
165
166 /* map a view of the file into our address space */
167 pData->pHeader=(const DataHeader *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
168 if(pData->pHeader==NULL) {
169 CloseHandle(map);
170 return FALSE;
171 }
172 pData->map=map;
173 return TRUE;
174 }
175
176
177 void
178 uprv_unmapFile(UDataMemory *pData) {
179 if(pData!=NULL && pData->map!=NULL) {
180 UnmapViewOfFile(pData->pHeader);
181 CloseHandle(pData->map);
182 pData->pHeader=NULL;
183 pData->map=NULL;
184 }
185 }
186
187
188
189#elif MAP_IMPLEMENTATION==MAP_POSIX
190 UBool
191 uprv_mapFile(UDataMemory *pData, const char *path) {
192 int fd;
193 int length;
194 struct stat mystat;
195 void *data;
196
197 UDataMemory_init(pData); /* Clear the output struct. */
198
199 /* determine the length of the file */
200 if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
201 return FALSE;
202 }
203 length=mystat.st_size;
204
205 /* open the file */
206 fd=open(path, O_RDONLY);
207 if(fd==-1) {
208 return FALSE;
209 }
210
211 /* get a view of the mapping */
374ca955 212#ifndef U_HPUX
b75a7d8f
A
213 data=mmap(0, length, PROT_READ, MAP_SHARED, fd, 0);
214#else
215 data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
216#endif
217 close(fd); /* no longer needed */
218 if(data==MAP_FAILED) {
219 return FALSE;
220 }
221
222 pData->map = (char *)data + length;
223 pData->pHeader=(const DataHeader *)data;
224 pData->mapAddr = data;
225 return TRUE;
226 }
227
228
229
230 void
231 uprv_unmapFile(UDataMemory *pData) {
232 if(pData!=NULL && pData->map!=NULL) {
233 size_t dataLen = (char *)pData->map - (char *)pData->mapAddr;
234 if(munmap(pData->mapAddr, dataLen)==-1) {
235 }
236 pData->pHeader=NULL;
237 pData->map=0;
238 pData->mapAddr=NULL;
239 }
240 }
241
242
243
73c04bcf
A
244#elif MAP_IMPLEMENTATION==MAP_STDIO
245 /* copy of the filestrm.c/T_FileStream_size() implementation */
246 static int32_t
247 umap_fsize(FILE *f) {
248 int32_t savedPos = ftell(f);
249 int32_t size = 0;
250
251 /*Changes by Bertrand A. D. doesn't affect the current position
252 goes to the end of the file before ftell*/
253 fseek(f, 0, SEEK_END);
254 size = (int32_t)ftell(f);
255 fseek(f, savedPos, SEEK_SET);
256 return size;
257 }
258
b75a7d8f
A
259 UBool
260 uprv_mapFile(UDataMemory *pData, const char *path) {
73c04bcf 261 FILE *file;
b75a7d8f
A
262 int32_t fileLength;
263 void *p;
264
265 UDataMemory_init(pData); /* Clear the output struct. */
266 /* open the input file */
73c04bcf 267 file=fopen(path, "rb");
b75a7d8f
A
268 if(file==NULL) {
269 return FALSE;
270 }
271
272 /* get the file length */
73c04bcf
A
273 fileLength=umap_fsize(file);
274 if(ferror(file) || fileLength<=20) {
275 fclose(file);
b75a7d8f
A
276 return FALSE;
277 }
278
279 /* allocate the memory to hold the file data */
280 p=uprv_malloc(fileLength);
281 if(p==NULL) {
73c04bcf 282 fclose(file);
b75a7d8f
A
283 return FALSE;
284 }
285
286 /* read the file */
73c04bcf 287 if(fileLength!=fread(p, 1, fileLength, file)) {
b75a7d8f 288 uprv_free(p);
73c04bcf 289 fclose(file);
b75a7d8f
A
290 return FALSE;
291 }
292
73c04bcf 293 fclose(file);
b75a7d8f
A
294 pData->map=p;
295 pData->pHeader=(const DataHeader *)p;
296 pData->mapAddr=p;
297 return TRUE;
298 }
299
300 void
301 uprv_unmapFile(UDataMemory *pData) {
302 if(pData!=NULL && pData->map!=NULL) {
303 uprv_free(pData->map);
304 pData->map = NULL;
305 pData->mapAddr = NULL;
306 pData->pHeader = NULL;
307 }
308 }
309
310
311#elif MAP_IMPLEMENTATION==MAP_390DLL
312 /* 390 specific Library Loading.
313 * This is the only platform left that dynamically loads an ICU Data Library.
314 * All other platforms use .data files when dynamic loading is required, but
315 * this turn out to be awkward to support in 390 batch mode.
316 *
317 * The idea here is to hide the fact that 390 is using dll loading from the
318 * rest of ICU, and make it look like there is file loading happening.
319 *
320 */
321
322 static char *strcpy_returnEnd(char *dest, const char *src)
323 {
324 while((*dest=*src)!=0) {
325 ++dest;
326 ++src;
327 }
328 return dest;
329 }
330
331 /*------------------------------------------------------------------------------
332 *
333 * computeDirPath given a user-supplied path of an item to be opened,
334 * compute and return
335 * - the full directory path to be used
336 * when opening the file.
337 * - Pointer to null at end of above returned path
338 *
339 * Parameters:
340 * path: input path. Buffer is not altered.
341 * pathBuffer: Output buffer. Any contents are overwritten.
342 *
343 * Returns:
344 * Pointer to null termination in returned pathBuffer.
345 *
346 * TODO: This works the way ICU historically has, but the
347 * whole data fallback search path is so complicated that
348 * proabably almost no one will ever really understand it,
349 * the potential for confusion is large. (It's not just
350 * this one function, but the whole scheme.)
351 *
352 *------------------------------------------------------------------------------*/
353 static char *uprv_computeDirPath(const char *path, char *pathBuffer)
354 {
355 char *finalSlash; /* Ptr to last dir separator in input path, or null if none. */
356 int32_t pathLen; /* Length of the returned directory path */
357
358 finalSlash = 0;
359 if (path != 0) {
360 finalSlash = uprv_strrchr(path, U_FILE_SEP_CHAR);
361 }
362
363 *pathBuffer = 0;
364 if (finalSlash == 0) {
365 /* No user-supplied path.
366 * Copy the ICU_DATA path to the path buffer and return that*/
367 const char *icuDataDir;
368 icuDataDir=u_getDataDirectory();
369 if(icuDataDir!=NULL && *icuDataDir!=0) {
370 return strcpy_returnEnd(pathBuffer, icuDataDir);
371 } else {
372 /* there is no icuDataDir either. Just return the empty pathBuffer. */
373 return pathBuffer;
374 }
375 }
376
377 /* User supplied path did contain a directory portion.
378 * Copy it to the output path buffer */
379 pathLen = (int32_t)(finalSlash - path + 1);
380 uprv_memcpy(pathBuffer, path, pathLen);
381 *(pathBuffer+pathLen) = 0;
382 return pathBuffer+pathLen;
383 }
384
385
386# define DATA_TYPE "dat"
387
388 UBool uprv_mapFile(UDataMemory *pData, const char *path) {
389 const char *inBasename;
390 char *basename;
391 char pathBuffer[1024];
392 const DataHeader *pHeader;
393 dllhandle *handle;
394 void *val=0;
395
396 inBasename=uprv_strrchr(path, U_FILE_SEP_CHAR);
397 if(inBasename==NULL) {
398 inBasename = path;
399 } else {
400 inBasename++;
401 }
402 basename=uprv_computeDirPath(path, pathBuffer);
403 if(uprv_strcmp(inBasename, U_ICUDATA_NAME".dat") != 0) {
404 /* must mmap file... for build */
405 int fd;
406 int length;
407 struct stat mystat;
408 void *data;
409 UDataMemory_init(pData); /* Clear the output struct. */
410
411 /* determine the length of the file */
412 if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
413 return FALSE;
414 }
415 length=mystat.st_size;
416
417 /* open the file */
418 fd=open(path, O_RDONLY);
419 if(fd==-1) {
420 return FALSE;
421 }
422
423 /* get a view of the mapping */
424 data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
425 close(fd); /* no longer needed */
426 if(data==MAP_FAILED) {
427 return FALSE;
428 }
429 pData->map = (char *)data + length;
430 pData->pHeader=(const DataHeader *)data;
431 pData->mapAddr = data;
432 return TRUE;
433 }
434
435# ifdef OS390BATCH
436 /* ### hack: we still need to get u_getDataDirectory() fixed
437 for OS/390 (batch mode - always return "//"? )
438 and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!)
439 This is probably due to the strange file system on OS/390. It's more like
440 a database with short entry names than a typical file system. */
441 /* U_ICUDATA_NAME should always have the correct name */
442 /* BUT FOR BATCH MODE IT IS AN EXCEPTION BECAUSE */
443 /* THE FIRST THREE LETTERS ARE PREASSIGNED TO THE */
444 /* PROJECT!!!!! */
445 uprv_strcpy(pathBuffer, "IXMI" U_ICU_VERSION_SHORT "DA");
446# else
447 /* set up the library name */
448 uprv_strcpy(basename, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX);
449# endif
450
451# ifdef UDATA_DEBUG
452 fprintf(stderr, "dllload: %s ", pathBuffer);
453# endif
454
455 handle=dllload(pathBuffer);
456
457# ifdef UDATA_DEBUG
458 fprintf(stderr, " -> %08X\n", handle );
459# endif
460
461 if(handle != NULL) {
462 /* we have a data DLL - what kind of lookup do we need here? */
463 /* try to find the Table of Contents */
464 UDataMemory_init(pData); /* Clear the output struct. */
465 val=dllqueryvar((dllhandle*)handle, U_ICUDATA_ENTRY_NAME);
466 if(val == 0) {
467 /* failed... so keep looking */
468 return FALSE;
469 }
470# ifdef UDATA_DEBUG
471 fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", handle, U_ICUDATA_ENTRY_NAME, val);
472# endif
473
474 pData->pHeader=(const DataHeader *)val;
475 return TRUE;
476 } else {
477 return FALSE; /* no handle */
478 }
479 }
480
481
482
483 void uprv_unmapFile(UDataMemory *pData) {
484 if(pData!=NULL && pData->map!=NULL) {
485 uprv_free(pData->map);
486 pData->map = NULL;
487 pData->mapAddr = NULL;
488 pData->pHeader = NULL;
489 }
490 }
491
492#else
493# error MAP_IMPLEMENTATION is set incorrectly
494#endif