/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) * https://github.com/D-Programming-Language/dmd/blob/master/src/root/file.c */ #include "dsystem.h" #include "file.h" #if _WIN32 #include #endif #if POSIX #include #endif #include "filename.h" #include "array.h" #include "rmem.h" /****************************** File ********************************/ File::File(const FileName *n) { ref = 0; buffer = NULL; len = 0; name = const_cast(n); } File *File::create(const char *n) { return new File(n); } File::File(const char *n) { ref = 0; buffer = NULL; len = 0; name = new FileName(n); } File::~File() { if (buffer) { if (ref == 0) mem.xfree(buffer); #if _WIN32 if (ref == 2) UnmapViewOfFile(buffer); #endif } } /************************************* */ bool File::read() { if (len) return false; // already read the file #if POSIX size_t size; struct stat 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 = (size_t)buf.st_size; #ifdef IN_GCC buffer = (unsigned char *) ::xmalloc(size + 2); #else buffer = (unsigned char *) ::malloc(size + 2); #endif if (!buffer) { printf("\tmalloc error, errno = %d\n",errno); goto err2; } numread = ::read(fd, buffer, size); if (numread != (ssize_t)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; #elif _WIN32 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); #ifdef IN_GCC buffer = (unsigned char *) ::xmalloc(size + 2); #else buffer = (unsigned char *) ::malloc(size + 2); #endif 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); #endif } /********************************************* * Write a file. * Returns: * false success */ bool File::write() { #if 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 ((ssize_t)len != numwritten) goto err2; if (close(fd) == -1) goto err; return false; err2: close(fd); ::remove(name); err: return true; #elif _WIN32 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,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); #endif } void File::remove() { #if POSIX ::remove(this->name->toChars()); #elif _WIN32 DeleteFileA(this->name->toChars()); #else assert(0); #endif } const char *File::toChars() { return name->toChars(); }