This repository has been archived by the owner on Jun 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
fallocate.cpp
158 lines (132 loc) · 4.02 KB
/
fallocate.cpp
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
155
156
157
#ifdef WIN32
#include <Windows.h>
#include "fallocate.h"
bool prepare_fallocate_wrapper()
{
HANDLE cur_token;
TOKEN_PRIVILEGES new_tp;
LUID luid;
if (!OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&cur_token))
return false;
if (!LookupPrivilegeValue (NULL, SE_MANAGE_VOLUME_NAME, &luid))
{
CloseHandle(cur_token); //I'd have used ON_BLOCK_EXIT, but want to keep dependency count down :)
return false;
}
memset(&new_tp, 0, sizeof(TOKEN_PRIVILEGES));
new_tp.PrivilegeCount = 1;
new_tp.Privileges[0].Luid = luid;
new_tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges (cur_token, FALSE, &new_tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
{
CloseHandle (cur_token);
return false;
}
return true;
}
int fallocate_wrapper(handle_t hndl, long long int size_to_reserve)
{
if (size_to_reserve <= 0)
return 0;
LARGE_INTEGER minus_one = {0}, zero = {0};
minus_one.QuadPart = -1;
//Get the current file position
LARGE_INTEGER old_pos = {0};
if (!SetFilePointerEx(hndl, zero, &old_pos, FILE_CURRENT))
return -1;
//Movie file position to the new end. These calls do NOT result in the actual allocation of
//new blocks, but they must succeed.
LARGE_INTEGER new_pos={0};
new_pos.QuadPart=size_to_reserve;
if (!SetFilePointerEx(hndl, new_pos, NULL, FILE_END))
return -1;
if (!SetEndOfFile(hndl))
return -1;
//Try to use the SetFileValidData call
if (SetFileValidData(hndl, size_to_reserve)!=0)
return 0; //Success!
//Bummer. Can't expand the file this way - now try sparse files
DWORD temp=0;
//Mark the file as sparse.
if (DeviceIoControl(hndl, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &temp, NULL)!=0)
{
FILE_ZERO_DATA_INFORMATION range;
range.FileOffset = old_pos;
range.BeyondFinalZero.QuadPart = old_pos.QuadPart+size_to_reserve;
//Actually set the sparse range.
if (DeviceIoControl(hndl, FSCTL_SET_ZERO_DATA, &range, sizeof(range), NULL, 0, &temp, NULL))
return 0; //Done
}
//Everything failed. Cry :( Write one byte at the end to force the actual
//allocation.
if (!SetFilePointerEx(hndl, minus_one, NULL, FILE_END))
return -1;
char initializer_buf [1] = {1};
DWORD written=0;
if (!WriteFile(hndl, initializer_buf, 1, &written, NULL))
return -1;
return 0;
}
#endif //WIN32
#ifdef __gnu_linux__
#include <unistd.h>
#include <sys/syscall.h>
#include "fallocate.h"
bool prepare_fallocate_wrapper()
{
return true; //no-op on linux
}
//Linux is fscked up a little bit differently - there's no exported fallocate64
//call in some old glibc versions. So just make a small syscall wrapper that
//can call the syscall directly.
#define fallocate_syscall_num 285
static int fallocate64_raw(int fd, int mode, __off64_t offset, __off64_t len)
{
return syscall(fallocate_syscall_num, fd, mode, offset, len);
}
int fallocate_wrapper(handle_t hndl, long long int size_to_reserve)
{
if (size_to_reserve <= 0)
return 0;
long long int cur_pos = lseek64(hndl, 0, seek_end);
if (cur_pos==-1)
return -1;
if (fallocate64_raw(hndl, 0, cur_pos, size_to_reserve)==0)
return 0;
//No such luck :( Use good old lseek64.
if (lseek64(hndl, cur_pos+size_to_reserve-1, SEEK_SET)==-1)
return -1;
//Really force the file write.
const char *one="O";
if (write(hndl, one, 1)==-1)
return -1;
return 0;
}
#endif //__gnu_linux__
#ifdef __MACH__
#include <unistd.h>
#include <fcntl.h>
#include "fallocate.h"
bool prepare_fallocate_wrapper()
{
return true; //no-op on Mac
}
int fallocate_wrapper(handle_t hndl, long long int size_to_reserve)
{
if (size_to_reserve <= 0)
return 0;
long long int cur_pos = lseek(hndl, 0, SEEK_END);
if (cur_pos==-1)
return -1;
//Allocate any type of blocks, including non-continuous
fstore_t store={0};
store.fst_flags = F_ALLOCATEALL;
store.fst_posmode = F_PEOFPOSMODE;
store.fst_offset = cur_pos;
store.fst_length = size_to_reserve;
fcntl(hndl, F_PREALLOCATE, &store);
//Hopefully, fcntl should have allocated our file and we won't block here.
return ftruncate(hndl, size_to_reserve+cur_pos);
}
#endif //__MACH__