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