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