mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-10 12:59:21 +03:00

Notably, the glue layer side of the changed multiple interface inheritance layout (DMD a54e89d) has not been implemented yet. This corresponds to DMD commit 3f6a763c0589dd03c1c206eafd434b593702564e.
242 lines
6.5 KiB
D
242 lines
6.5 KiB
D
// Compiler implementation of the D programming language
|
|
// Copyright (c) 1999-2015 by Digital Mars
|
|
// All Rights Reserved
|
|
// written by Walter Bright
|
|
// http://www.digitalmars.com
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// http://www.boost.org/LICENSE_1_0.txt
|
|
|
|
module ddmd.root.file;
|
|
|
|
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;
|
|
import ddmd.root.array, ddmd.root.filename, ddmd.root.rmem;
|
|
|
|
version (Windows) alias WIN32_FIND_DATAA = WIN32_FIND_DATA;
|
|
|
|
/***********************************************************
|
|
*/
|
|
struct File
|
|
{
|
|
int _ref; // != 0 if this is a reference to someone else's buffer
|
|
ubyte* buffer; // data for our file
|
|
size_t len; // amount of data in buffer[]
|
|
const(FileName)* name; // name of our file
|
|
|
|
extern (D) this(const(char)* n)
|
|
{
|
|
_ref = 0;
|
|
buffer = null;
|
|
len = 0;
|
|
name = new FileName(n);
|
|
}
|
|
|
|
extern (C++) static File* create(const(char)* n)
|
|
{
|
|
return new File(n);
|
|
}
|
|
|
|
extern (D) this(const(FileName)* n)
|
|
{
|
|
_ref = 0;
|
|
buffer = null;
|
|
len = 0;
|
|
name = n;
|
|
}
|
|
|
|
extern (C++) ~this()
|
|
{
|
|
if (buffer)
|
|
{
|
|
if (_ref == 0)
|
|
mem.xfree(buffer);
|
|
version (Windows)
|
|
{
|
|
if (_ref == 2)
|
|
UnmapViewOfFile(buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern (C++) const(char)* toChars()
|
|
{
|
|
return name.toChars();
|
|
}
|
|
|
|
/*************************************
|
|
*/
|
|
extern (C++) bool read()
|
|
{
|
|
if (len)
|
|
return false; // already read the file
|
|
version (Posix)
|
|
{
|
|
size_t size;
|
|
stat_t buf;
|
|
ssize_t numread;
|
|
const(char)* name = this.name.toChars();
|
|
//printf("File::read('%s')\n",name);
|
|
int fd = open(name, O_RDONLY);
|
|
if (fd == -1)
|
|
{
|
|
//printf("\topen error, errno = %d\n",errno);
|
|
goto err1;
|
|
}
|
|
if (!_ref)
|
|
.free(buffer);
|
|
_ref = 0; // we own the buffer now
|
|
//printf("\tfile opened\n");
|
|
if (fstat(fd, &buf))
|
|
{
|
|
printf("\tfstat error, errno = %d\n", errno);
|
|
goto err2;
|
|
}
|
|
size = cast(size_t)buf.st_size;
|
|
buffer = cast(ubyte*).malloc(size + 2);
|
|
if (!buffer)
|
|
{
|
|
printf("\tmalloc error, errno = %d\n", errno);
|
|
goto err2;
|
|
}
|
|
numread = .read(fd, buffer, size);
|
|
if (numread != size)
|
|
{
|
|
printf("\tread error, errno = %d\n", errno);
|
|
goto err2;
|
|
}
|
|
if (close(fd) == -1)
|
|
{
|
|
printf("\tclose error, errno = %d\n", errno);
|
|
goto err;
|
|
}
|
|
len = size;
|
|
// Always store a wchar ^Z past end of buffer so scanner has a sentinel
|
|
buffer[size] = 0; // ^Z is obsolete, use 0
|
|
buffer[size + 1] = 0;
|
|
return false;
|
|
err2:
|
|
close(fd);
|
|
err:
|
|
.free(buffer);
|
|
buffer = null;
|
|
len = 0;
|
|
err1:
|
|
return true;
|
|
}
|
|
else version (Windows)
|
|
{
|
|
DWORD size;
|
|
DWORD numread;
|
|
const(char)* name = this.name.toChars();
|
|
HANDLE h = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, null);
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
goto err1;
|
|
if (!_ref)
|
|
.free(buffer);
|
|
_ref = 0;
|
|
size = GetFileSize(h, null);
|
|
buffer = cast(ubyte*).malloc(size + 2);
|
|
if (!buffer)
|
|
goto err2;
|
|
if (ReadFile(h, buffer, size, &numread, null) != TRUE)
|
|
goto err2;
|
|
if (numread != size)
|
|
goto err2;
|
|
if (!CloseHandle(h))
|
|
goto err;
|
|
len = size;
|
|
// Always store a wchar ^Z past end of buffer so scanner has a sentinel
|
|
buffer[size] = 0; // ^Z is obsolete, use 0
|
|
buffer[size + 1] = 0;
|
|
return 0;
|
|
err2:
|
|
CloseHandle(h);
|
|
err:
|
|
.free(buffer);
|
|
buffer = null;
|
|
len = 0;
|
|
err1:
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
/*********************************************
|
|
* Write a file.
|
|
* Returns:
|
|
* false success
|
|
*/
|
|
extern (C++) bool write()
|
|
{
|
|
version (Posix)
|
|
{
|
|
ssize_t numwritten;
|
|
const(char)* name = this.name.toChars();
|
|
int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4);
|
|
if (fd == -1)
|
|
goto err;
|
|
numwritten = .write(fd, buffer, len);
|
|
if (len != numwritten)
|
|
goto err2;
|
|
if (close(fd) == -1)
|
|
goto err;
|
|
return false;
|
|
err2:
|
|
close(fd);
|
|
.remove(name);
|
|
err:
|
|
return true;
|
|
}
|
|
else version (Windows)
|
|
{
|
|
DWORD numwritten;
|
|
const(char)* name = this.name.toChars();
|
|
HANDLE h = CreateFileA(name, GENERIC_WRITE, 0, null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, null);
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
goto err;
|
|
if (WriteFile(h, buffer, cast(DWORD)len, &numwritten, null) != TRUE)
|
|
goto err2;
|
|
if (len != numwritten)
|
|
goto err2;
|
|
if (!CloseHandle(h))
|
|
goto err;
|
|
return false;
|
|
err2:
|
|
CloseHandle(h);
|
|
DeleteFileA(name);
|
|
err:
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
/* Set buffer
|
|
*/
|
|
extern (C++) void setbuffer(void* buffer, size_t len)
|
|
{
|
|
this.buffer = cast(ubyte*)buffer;
|
|
this.len = len;
|
|
}
|
|
|
|
// delete file
|
|
extern (C++) void remove()
|
|
{
|
|
version (Posix)
|
|
{
|
|
int dummy = .remove(this.name.toChars());
|
|
}
|
|
else version (Windows)
|
|
{
|
|
DeleteFileA(this.name.toChars());
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
}
|