1
2/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
3 * http://www.digitalmars.com
4 * Distributed under the Boost Software License, Version 1.0.
5 * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
6 * https://github.com/D-Programming-Language/dmd/blob/master/src/root/file.c
7 */
8
9#include "dsystem.h"
10#include "file.h"
11
12#if _WIN32
13#include <windows.h>
14#endif
15
16#if POSIX
17#include <utime.h>
18#endif
19
20#include "filename.h"
21#include "array.h"
22#include "rmem.h"
23
24/****************************** File ********************************/
25
26File::File(const FileName *n)
27{
28    ref = 0;
29    buffer = NULL;
30    len = 0;
31    name = const_cast<FileName *>(n);
32}
33
34File *File::create(const char *n)
35{
36    return new File(n);
37}
38
39File::File(const char *n)
40{
41    ref = 0;
42    buffer = NULL;
43    len = 0;
44    name = new FileName(n);
45}
46
47File::~File()
48{
49    if (buffer)
50    {
51        if (ref == 0)
52            mem.xfree(buffer);
53#if _WIN32
54        if (ref == 2)
55            UnmapViewOfFile(buffer);
56#endif
57    }
58}
59
60/*************************************
61 */
62
63bool File::read()
64{
65    if (len)
66        return false;               // already read the file
67#if POSIX
68    size_t size;
69    struct stat buf;
70    ssize_t numread;
71
72    const char *name = this->name->toChars();
73    //printf("File::read('%s')\n",name);
74    int fd = open(name, O_RDONLY);
75    if (fd == -1)
76    {
77        //printf("\topen error, errno = %d\n",errno);
78        goto err1;
79    }
80
81    if (!ref)
82        ::free(buffer);
83    ref = 0;       // we own the buffer now
84
85    //printf("\tfile opened\n");
86    if (fstat(fd, &buf))
87    {
88        printf("\tfstat error, errno = %d\n",errno);
89        goto err2;
90    }
91    size = (size_t)buf.st_size;
92#ifdef IN_GCC
93    buffer = (unsigned char *) ::xmalloc(size + 2);
94#else
95    buffer = (unsigned char *) ::malloc(size + 2);
96#endif
97    if (!buffer)
98    {
99        printf("\tmalloc error, errno = %d\n",errno);
100        goto err2;
101    }
102
103    numread = ::read(fd, buffer, size);
104    if (numread != (ssize_t)size)
105    {
106        printf("\tread error, errno = %d\n",errno);
107        goto err2;
108    }
109
110    if (close(fd) == -1)
111    {
112        printf("\tclose error, errno = %d\n",errno);
113        goto err;
114    }
115
116    len = size;
117
118    // Always store a wchar ^Z past end of buffer so scanner has a sentinel
119    buffer[size] = 0;           // ^Z is obsolete, use 0
120    buffer[size + 1] = 0;
121    return false;
122
123err2:
124    close(fd);
125err:
126    ::free(buffer);
127    buffer = NULL;
128    len = 0;
129
130err1:
131    return true;
132#elif _WIN32
133    DWORD size;
134    DWORD numread;
135
136    const char *name = this->name->toChars();
137    HANDLE h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
138        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
139    if (h == INVALID_HANDLE_VALUE)
140        goto err1;
141
142    if (!ref)
143        ::free(buffer);
144    ref = 0;
145
146    size = GetFileSize(h,NULL);
147#ifdef IN_GCC
148    buffer = (unsigned char *) ::xmalloc(size + 2);
149#else
150    buffer = (unsigned char *) ::malloc(size + 2);
151#endif
152    if (!buffer)
153        goto err2;
154
155    if (ReadFile(h,buffer,size,&numread,NULL) != TRUE)
156        goto err2;
157
158    if (numread != size)
159        goto err2;
160
161    if (!CloseHandle(h))
162        goto err;
163
164    len = size;
165
166    // Always store a wchar ^Z past end of buffer so scanner has a sentinel
167    buffer[size] = 0;           // ^Z is obsolete, use 0
168    buffer[size + 1] = 0;
169    return 0;
170
171err2:
172    CloseHandle(h);
173err:
174    ::free(buffer);
175    buffer = NULL;
176    len = 0;
177
178err1:
179    return true;
180#else
181    assert(0);
182#endif
183}
184
185/*********************************************
186 * Write a file.
187 * Returns:
188 *      false       success
189 */
190
191bool File::write()
192{
193#if POSIX
194    ssize_t numwritten;
195
196    const char *name = this->name->toChars();
197    int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4);
198    if (fd == -1)
199        goto err;
200
201    numwritten = ::write(fd, buffer, len);
202    if ((ssize_t)len != numwritten)
203        goto err2;
204
205    if (close(fd) == -1)
206        goto err;
207
208    return false;
209
210err2:
211    close(fd);
212    ::remove(name);
213err:
214    return true;
215#elif _WIN32
216    DWORD numwritten;
217
218    const char *name = this->name->toChars();
219    HANDLE h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
220        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
221    if (h == INVALID_HANDLE_VALUE)
222        goto err;
223
224    if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
225        goto err2;
226
227    if (len != numwritten)
228        goto err2;
229
230    if (!CloseHandle(h))
231        goto err;
232    return false;
233
234err2:
235    CloseHandle(h);
236    DeleteFileA(name);
237err:
238    return true;
239#else
240    assert(0);
241#endif
242}
243
244void File::remove()
245{
246#if POSIX
247    ::remove(this->name->toChars());
248#elif _WIN32
249    DeleteFileA(this->name->toChars());
250#else
251    assert(0);
252#endif
253}
254
255const char *File::toChars()
256{
257    return name->toChars();
258}
259