1 
2 /* Copyright (C) 1999-2021 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 
File(const FileName * n)26 File::File(const FileName *n)
27 {
28     ref = 0;
29     buffer = NULL;
30     len = 0;
31     name = const_cast<FileName *>(n);
32 }
33 
create(const char * n)34 File *File::create(const char *n)
35 {
36     return new File(n);
37 }
38 
File(const char * n)39 File::File(const char *n)
40 {
41     ref = 0;
42     buffer = NULL;
43     len = 0;
44     name = new FileName(n);
45 }
46 
~File()47 File::~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 
read()63 bool 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 
123 err2:
124     close(fd);
125 err:
126     ::free(buffer);
127     buffer = NULL;
128     len = 0;
129 
130 err1:
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 
171 err2:
172     CloseHandle(h);
173 err:
174     ::free(buffer);
175     buffer = NULL;
176     len = 0;
177 
178 err1:
179     return true;
180 #else
181     assert(0);
182 #endif
183 }
184 
185 /*********************************************
186  * Write a file.
187  * Returns:
188  *      false       success
189  */
190 
write()191 bool 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 
210 err2:
211     close(fd);
212     ::remove(name);
213 err:
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 
234 err2:
235     CloseHandle(h);
236     DeleteFileA(name);
237 err:
238     return true;
239 #else
240     assert(0);
241 #endif
242 }
243 
remove()244 void 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 
toChars()255 const char *File::toChars()
256 {
257     return name->toChars();
258 }
259