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