ldc/ddmd/root/file.d
David Nadlinger 9f998a398d Initial merge of upstream v2.071.0-b2
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.
2016-04-03 15:15:14 +01:00

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);
}
}
}