File: FileStream.cpp

package info (click to toggle)
storm-lang 0.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,028 kB
  • sloc: ansic: 261,471; cpp: 140,432; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (154 lines) | stat: -rw-r--r-- 3,831 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include "stdafx.h"
#include "FileStream.h"
#include "Core/Str.h"
#include "Core/StrBuf.h"
#include "OS/IORequest.h"
#include "Core/SystemError.h"
#include "Url.h"

namespace storm {

#if defined(WINDOWS)

	static void openFileRaw(Str *name, bool input, os::Handle &out, Str *&error) {
		// TODO: Allow duplicating this handle so that we can clone duplicate it later?

		out = CreateFile(name->c_str(),
						input ? GENERIC_READ : GENERIC_WRITE,
						FILE_SHARE_READ | FILE_SHARE_WRITE,
						NULL,
						input ? OPEN_EXISTING : CREATE_ALWAYS,
						FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
						NULL);
		if (!out) {
			error = systemErrorMessage(name->engine(), GetLastError());
		}
	}

	static void copyFilePtr(os::Handle to, os::Handle from) {
		LARGE_INTEGER pos;
		pos.QuadPart = 0;
		SetFilePointerEx(from.v(), pos, &pos, FILE_CURRENT);
		SetFilePointerEx(to.v(), pos, NULL, FILE_BEGIN);
	}

	static os::Handle copyFile(os::Handle h, Str *name, bool input) {
		if (h) {
			os::Handle r;
			Str *error = null;
			openFileRaw(name, input, r, error);
			if (error)
				throw OpenError(error, name, input);
			copyFilePtr(r, h);
			return r;
		} else {
			return os::Handle();
		}
	}

#elif defined(LINUX_IO_URING)

	static void openFileRaw(Str *name, bool input, os::Handle &out, Str *&error) {
		int flags = O_CLOEXEC | O_NONBLOCK;
		if (input)
			flags |= O_RDONLY;
		else
			flags |= O_CREAT | O_TRUNC | O_WRONLY;

		int mode = 0666;

		// We specify the handle AT_FDCWD to get the regular 'open' semantics for relative paths.
		os::IORequest r(os::Handle(AT_FDCWD), os::Thread::current());
		r.request.opcode = IORING_OP_OPENAT;
		r.request.addr = reinterpret_cast<size_t>(name->utf8_str());
		r.request.open_flags = flags;
		r.request.len = mode;

		out = r.submit();

		// Interestingly enough, we can open (but not read from) directories on Linux. Detect that.
		if (out) {
			struct stat info;
			if (fstatat(out.v(), "", &info, AT_EMPTY_PATH) == 0 && S_ISDIR(info.st_mode)) {
				::close(out.v());
				out = os::Handle();
				r.result = -EACCES;
			}
		}

		if (!out) {
			error = systemErrorMessage(name->engine(), -r.result);
		}
	}

	static os::Handle copyFile(os::Handle h, Str *name, bool input) {
		UNUSED(name);
		UNUSED(input);

		return dup(h.v());
	}

#elif defined(POSIX)

	static void openFileRaw(Str *name, bool input, os::Handle &out, Str *&error) {
		int flags = O_CLOEXEC | O_NONBLOCK;
		if (input)
			flags |= O_RDONLY;
		else
			flags |= O_CREAT | O_TRUNC | O_WRONLY;
		out = ::open(name->utf8_str(), flags, 0666);

		if (out) {
			struct stat info;
			if (fstatat(out.v(), "", &info, AT_EMPTY_PATH) == 0 && S_ISDIR(info.st_mode)) {
				::close(out.v());
				out = os::Handle();
				errno = EACCES;
			}
		}

		if (!out) {
			error = systemErrorMessage(name->engine(), errno);
		}
	}

	static os::Handle copyFile(os::Handle h, Str *name, bool input) {
		UNUSED(name);
		UNUSED(input);

		return dup(h.v());
	}

#else
#error "Please implement file IO for your platform!"
#endif

	static os::Handle openFile(Str *name, bool input) {
		os::Handle handle;
		Str *error = null;
		openFileRaw(name, input, handle, error);

		if (error)
			throw new (name) OpenError(error, name, input);

		return handle;
	}

	FileIStream::FileIStream(Str *name) : HandleRIStream(openFile(name, true)), name(name) {}

	FileIStream::FileIStream(const FileIStream &o) : HandleRIStream(copyFile(o.handle, o.name, true)), name(o.name) {}

	void FileIStream::toS(StrBuf *to) const {
		*to << L"File input from " << name;
	}


	FileOStream::FileOStream(Str *name) : HandleOStream(openFile(name, false)), name(name) {}

	FileOStream::FileOStream(const FileOStream &o) : HandleOStream(copyFile(o.handle, o.name, false)), name(o.name) {}

	void FileOStream::toS(StrBuf *to) const {
		*to << L"File output to " << name;
	}

}