summaryrefslogtreecommitdiff
path: root/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.cpp
blob: 6bfb73f0e86d1e391d5a92eedde61ec449d02c11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

/*=============================================================
**
** Source: MapViewOfFile.c
**
**
** Purpose: Positive test the MapViewOfFile API.
**          Call MapViewOfFile with access FILE_MAP_READ.
**
**
**============================================================*/
#include <palsuite.h>
#define MAPPINGSIZE 8192

// This test is special - it doesn't work when the file is created on a tmpfs, like the /tmp folder
// that is the default location for running PAL tests. The reason is that on such filesystem,
// it is not possible to create file with FILE_FLAG_NO_BUFFERING.
// So we explicitly use the /var/tmp that cannot be on tmpfs, since it it persistent over reboots.

#ifndef __ANDROID__
#define TEMP_DIRECTORY_PATH "/var/tmp/"
#else
// On Android, "/var/tmp/" doesn't exist; temporary files should go to /data/local/tmp/
#define TEMP_DIRECTORY_PATH "/data/local/tmp/"
#endif

int __cdecl main(int argc, char *argv[])
{

    HANDLE  hFile = INVALID_HANDLE_VALUE;
    LPSTR   buf = NULL;
    CHAR    ch[MAPPINGSIZE];
    CHAR    lpFilePath[MAX_PATH];
    DWORD   dwBytesWritten = 0;
    DWORD   dwInitialSize = 0;
    DWORD   dwFinalSize = 0;
    BOOL    bRetVal = FALSE;

    HANDLE hFileMapping = 0;
    LPVOID lpMapViewAddress = NULL;

    /* Initialize the PAL environment.
     */
    if( 0 != PAL_Initialize(argc, argv))
    {
        return FAIL;
    }

    GetTempFileName(TEMP_DIRECTORY_PATH, "tst", 0, lpFilePath);

    /* Create a file handle with CreateFile.
     */
    hFile = CreateFile( lpFilePath,
                        GENERIC_WRITE|GENERIC_READ,
                        FILE_SHARE_READ|FILE_SHARE_WRITE,
                        NULL,
                        OPEN_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, 
                        NULL);
    
    if (hFile == INVALID_HANDLE_VALUE)
    {
        Fail( "ERROR: %u :unable to create file \"%s\".\n",
              GetLastError(), lpFilePath);
    }

    /* Get the initial size of file, for latter tests.
     */
    dwInitialSize = GetFileSize (hFile, NULL); 
    if ( INVALID_FILE_SIZE == dwInitialSize )
    {
        Fail("ERROR:%u: The created file \"%s\" has an invalid "
             "file size.\n",GetLastError(),lpFilePath);
    }

    /*
     * An application must meet certain requirements when working 
     * with files opened with FILE_FLAG_NO_BUFFERING: 
     *      File access must begin at byte offsets within the file that 
     *      are integer multiples of the volume's sector size. To determine a 
     *      volume's sector size, call the GetDiskFreeSpace function. 
     *
     *      File access must be for numbers of bytes that are integer 
     *      multiples of the volume's sector size. For example, if the
     *      sector size is 512 bytes, an application can request reads and 
     *      writes of 512, 1024, or 2048 bytes, but not of 335, 981, or 7171 bytes. 
     *
     *      Buffer addresses for read and write operations must be sector 
     *      aligned (aligned on addresses in memory that are integer multiples 
     *      of the volume's sector size). One way to sector align buffers is to use the 
     *      VirtualAlloc function to allocate the buffers. This function allocates memory 
     *      that is aligned on addresses that are integer multiples of the system's page size. 
     *      Because both page and volume sector sizes are powers of 2, memory aligned by multiples 
     *      of the system's page size is also aligned by multiples of the volume's sector size. 
     */
    buf = (LPSTR)VirtualAlloc(  NULL,               /* Let the system decide the location. */
                                MAPPINGSIZE / 2,    /* One page, the smallest you can request */
                                MEM_COMMIT,         /* Reserve and commit in one pass */
                                PAGE_READWRITE );   /* Allow reading and writting. */

    if ( NULL == buf )
    {
        Trace( "VirtualAlloc failed! LastError=%d\n", GetLastError() );
        CloseHandle( hFile );
        Fail("");
    }
    

    /* 
     * Write to the File handle.
     * The reminder will be padded with zeros. 
     */ 
    strncpy( buf, 
             "thats not a test string....THIS is a test string", 
             MAPPINGSIZE / 2 );

    bRetVal = WriteFile(hFile,
                        buf,
                        MAPPINGSIZE / 2,
                        &dwBytesWritten,
                        NULL);

    if ( FALSE == bRetVal )
    {
        Trace( "ERROR: %u :unable to write to file handle hFile=0x%lx\n",
              GetLastError(), hFile);
        CloseHandle(hFile);
        VirtualFree( buf, 0, MEM_RELEASE );
        Fail("");
    }

    /* Create a unnamed file-mapping object with file handle FileHandle
     * and with PAGE_READWRITE protection.
    */
    hFileMapping = CreateFileMapping(  hFile,
                                       NULL,            /*not inherited*/
                                       PAGE_READWRITE,  /*read and wite*/
                                       0,               /*high-order of object size*/
                                       MAPPINGSIZE,     /*low-orger of object size*/
                                       NULL);           /*unnamed object*/

    if( NULL == hFileMapping )
    {
        Trace("ERROR:%u: Failed to create File Mapping.\n", GetLastError());
        CloseHandle(hFile);
        VirtualFree( buf, 0, MEM_RELEASE );
        Fail("");
    }

    /* maps a view of a file into the address space of the calling process.
     */
    lpMapViewAddress = MapViewOfFile( hFileMapping,
                                      FILE_MAP_READ,  /* access code */
                                      0,              /*high order offset*/
                                      0,              /*low order offset*/
                                      MAPPINGSIZE);   /* number of bytes for map */

    if( NULL == lpMapViewAddress )
    {
        Trace( "ERROR:%u: Failed to call MapViewOfFile API to map"
              " a view of file!\n", GetLastError());
        CloseHandle(hFile);
        CloseHandle(hFileMapping);
        VirtualFree( buf, 0, MEM_RELEASE );
        Fail("");
    }

    /* Verify that the size of the file has increased to 
     * accomidate the MapView. 
     */
    dwFinalSize = GetFileSize (hFile, NULL); 
    if ( (dwFinalSize <= dwInitialSize) && (dwFinalSize != MAPPINGSIZE))
    {
        
        CloseHandle(hFile);
        CloseHandle(hFileMapping);
        VirtualFree( buf, 0, MEM_RELEASE );
        UnmapViewOfFile(lpMapViewAddress);
        
        Fail( "ERROR: Size of the file was expected to "
              "increase from \"%d\", to \"%d\".\n ",
              dwInitialSize,
              dwFinalSize);
    }

    /* Copy the MapViewOfFile to buffer, so we can
     * compare with value read from file directly.
     */
    memcpy(ch, (LPCSTR)lpMapViewAddress, MAPPINGSIZE);
    if (memcmp(ch, buf, strlen(buf)) != 0)
    {
        CloseHandle(hFile);
        CloseHandle(hFileMapping);
        UnmapViewOfFile(lpMapViewAddress) ;
        VirtualFree( buf, 0, MEM_RELEASE );
        
        Fail( "ERROR: MapViewOfFile not equal to file contents "
              "retrieved \"%s\", expected \"%s\".\n",
              ch,
              buf);
    }

    /* Unmap the view of file.
     */
    if( FALSE == UnmapViewOfFile(lpMapViewAddress) )
    {
        Trace( "\nFailed to call UnmapViewOfFile API to unmap the "
              "view of a file, error code=%u\n", GetLastError());
        CloseHandle(hFile);
        CloseHandle(hFileMapping);
        VirtualFree( buf, 0, MEM_RELEASE );
        Fail("");
    }

    /* Close handle to create file.
     */
    if( FALSE == CloseHandle(hFile) )
    {
        Trace( "ERROR:%u:Failed to call CloseHandle API to close a file handle.",
              GetLastError());
        CloseHandle(hFileMapping);
        VirtualFree( buf, 0, MEM_RELEASE );
        Fail("");
    }

    if( FALSE == CloseHandle(hFileMapping) )
    {
        Trace( "ERROR:%u:Failed to call CloseHandle API to close a "
              "filemapping handle.",GetLastError());
        VirtualFree( buf, 0, MEM_RELEASE );
        Fail("");
    }
    
    VirtualFree( buf, 0, MEM_RELEASE );

    DeleteFile(lpFilePath);

    PAL_Terminate();
    return PASS;
}