1 | /*
|
---|
2 | * Unix SMB/CIFS implementation.
|
---|
3 | * Support for OneFS
|
---|
4 | *
|
---|
5 | * Copyright (C) Tim Prouty, 2008
|
---|
6 | *
|
---|
7 | * This program is free software; you can redistribute it and/or modify
|
---|
8 | * it under the terms of the GNU General Public License as published by
|
---|
9 | * the Free Software Foundation; either version 3 of the License, or
|
---|
10 | * (at your option) any later version.
|
---|
11 | *
|
---|
12 | * This program is distributed in the hope that it will be useful,
|
---|
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
15 | * GNU General Public License for more details.
|
---|
16 | *
|
---|
17 | * You should have received a copy of the GNU General Public License
|
---|
18 | * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
---|
19 | */
|
---|
20 |
|
---|
21 | #include "includes.h"
|
---|
22 | #include "onefs.h"
|
---|
23 | #include "onefs_config.h"
|
---|
24 |
|
---|
25 | #undef DBGC_CLASS
|
---|
26 | #define DBGC_CLASS DBGC_VFS
|
---|
27 |
|
---|
28 | static int onefs_connect(struct vfs_handle_struct *handle, const char *service,
|
---|
29 | const char *user)
|
---|
30 | {
|
---|
31 | int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
|
---|
32 |
|
---|
33 | if (ret < 0) {
|
---|
34 | return ret;
|
---|
35 | }
|
---|
36 |
|
---|
37 | ret = onefs_load_config(handle->conn);
|
---|
38 | if (ret) {
|
---|
39 | SMB_VFS_NEXT_DISCONNECT(handle);
|
---|
40 | DEBUG(3, ("Load config failed: %s\n", strerror(errno)));
|
---|
41 | return ret;
|
---|
42 | }
|
---|
43 |
|
---|
44 | return 0;
|
---|
45 | }
|
---|
46 |
|
---|
47 | static int onefs_mkdir(vfs_handle_struct *handle, const char *path,
|
---|
48 | mode_t mode)
|
---|
49 | {
|
---|
50 | /* SMB_VFS_MKDIR should never be called in vfs_onefs */
|
---|
51 | SMB_ASSERT(false);
|
---|
52 | return SMB_VFS_NEXT_MKDIR(handle, path, mode);
|
---|
53 | }
|
---|
54 |
|
---|
55 | static int onefs_open(vfs_handle_struct *handle,
|
---|
56 | struct smb_filename *smb_fname,
|
---|
57 | files_struct *fsp, int flags, mode_t mode)
|
---|
58 | {
|
---|
59 | /* SMB_VFS_OPEN should never be called in vfs_onefs */
|
---|
60 | SMB_ASSERT(false);
|
---|
61 | return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
|
---|
62 | }
|
---|
63 |
|
---|
64 | static ssize_t onefs_sendfile(vfs_handle_struct *handle, int tofd,
|
---|
65 | files_struct *fromfsp, const DATA_BLOB *header,
|
---|
66 | SMB_OFF_T offset, size_t count)
|
---|
67 | {
|
---|
68 | ssize_t result;
|
---|
69 |
|
---|
70 | START_PROFILE_BYTES(syscall_sendfile, count);
|
---|
71 | result = onefs_sys_sendfile(handle->conn, tofd, fromfsp->fh->fd,
|
---|
72 | header, offset, count);
|
---|
73 | END_PROFILE(syscall_sendfile);
|
---|
74 | return result;
|
---|
75 | }
|
---|
76 |
|
---|
77 | static ssize_t onefs_recvfile(vfs_handle_struct *handle, int fromfd,
|
---|
78 | files_struct *tofsp, SMB_OFF_T offset,
|
---|
79 | size_t count)
|
---|
80 | {
|
---|
81 | ssize_t result;
|
---|
82 |
|
---|
83 | START_PROFILE_BYTES(syscall_recvfile, count);
|
---|
84 | result = onefs_sys_recvfile(fromfd, tofsp->fh->fd, offset, count);
|
---|
85 | END_PROFILE(syscall_recvfile);
|
---|
86 | return result;
|
---|
87 | }
|
---|
88 |
|
---|
89 | static uint64_t onefs_get_alloc_size(struct vfs_handle_struct *handle,
|
---|
90 | files_struct *fsp,
|
---|
91 | const SMB_STRUCT_STAT *sbuf)
|
---|
92 | {
|
---|
93 | uint64_t result;
|
---|
94 |
|
---|
95 | START_PROFILE(syscall_get_alloc_size);
|
---|
96 |
|
---|
97 | if(S_ISDIR(sbuf->st_ex_mode)) {
|
---|
98 | result = 0;
|
---|
99 | goto out;
|
---|
100 | }
|
---|
101 |
|
---|
102 | /* Just use the file size since st_blocks is unreliable on OneFS. */
|
---|
103 | result = get_file_size_stat(sbuf);
|
---|
104 |
|
---|
105 | if (fsp && fsp->initial_allocation_size)
|
---|
106 | result = MAX(result,fsp->initial_allocation_size);
|
---|
107 |
|
---|
108 | result = smb_roundup(handle->conn, result);
|
---|
109 |
|
---|
110 | out:
|
---|
111 | END_PROFILE(syscall_get_alloc_size);
|
---|
112 | return result;
|
---|
113 | }
|
---|
114 |
|
---|
115 | static struct file_id onefs_file_id_create(struct vfs_handle_struct *handle,
|
---|
116 | const SMB_STRUCT_STAT *sbuf)
|
---|
117 | {
|
---|
118 | struct file_id key;
|
---|
119 |
|
---|
120 | /* the ZERO_STRUCT ensures padding doesn't break using the key as a
|
---|
121 | * blob */
|
---|
122 | ZERO_STRUCT(key);
|
---|
123 |
|
---|
124 | key.devid = sbuf->st_ex_dev;
|
---|
125 | key.inode = sbuf->st_ex_ino;
|
---|
126 | key.extid = sbuf->vfs_private;
|
---|
127 |
|
---|
128 | return key;
|
---|
129 | }
|
---|
130 |
|
---|
131 | static int onefs_statvfs(vfs_handle_struct *handle, const char *path,
|
---|
132 | vfs_statvfs_struct *statbuf)
|
---|
133 | {
|
---|
134 | struct statvfs statvfs_buf;
|
---|
135 | int result;
|
---|
136 |
|
---|
137 | DEBUG(5, ("Calling SMB_STAT_VFS \n"));
|
---|
138 | result = statvfs(path, &statvfs_buf);
|
---|
139 | ZERO_STRUCTP(statbuf);
|
---|
140 |
|
---|
141 | if (!result) {
|
---|
142 | statbuf->OptimalTransferSize = statvfs_buf.f_iosize;
|
---|
143 | statbuf->BlockSize = statvfs_buf.f_bsize;
|
---|
144 | statbuf->TotalBlocks = statvfs_buf.f_blocks;
|
---|
145 | statbuf->BlocksAvail = statvfs_buf.f_bfree;
|
---|
146 | statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
|
---|
147 | statbuf->TotalFileNodes = statvfs_buf.f_files;
|
---|
148 | statbuf->FreeFileNodes = statvfs_buf.f_ffree;
|
---|
149 | statbuf->FsIdentifier =
|
---|
150 | (((uint64_t)statvfs_buf.f_fsid.val[0]<<32) &
|
---|
151 | 0xffffffff00000000LL) |
|
---|
152 | (uint64_t)statvfs_buf.f_fsid.val[1];
|
---|
153 | }
|
---|
154 | return result;
|
---|
155 | }
|
---|
156 |
|
---|
157 | static int onefs_get_real_filename(vfs_handle_struct *handle, const char *path,
|
---|
158 | const char *name, TALLOC_CTX *mem_ctx,
|
---|
159 | char **found_name)
|
---|
160 | {
|
---|
161 | struct stat sb;
|
---|
162 | struct connection_struct *conn = handle->conn;
|
---|
163 | struct stat_extra se;
|
---|
164 | int result;
|
---|
165 | char *unmangled_name = NULL;
|
---|
166 | char *full_name = NULL;
|
---|
167 |
|
---|
168 | /* First demangle the name if necessary. */
|
---|
169 | if (!conn->case_sensitive && mangle_is_mangled(name, conn->params) &&
|
---|
170 | mangle_lookup_name_from_8_3(mem_ctx, name, &unmangled_name,
|
---|
171 | conn->params)) {
|
---|
172 | /* Name is now unmangled. */
|
---|
173 | name = unmangled_name;
|
---|
174 | }
|
---|
175 |
|
---|
176 | /* Do the case insensitive stat. */
|
---|
177 | ZERO_STRUCT(se);
|
---|
178 | se.se_version = ESTAT_CURRENT_VERSION;
|
---|
179 | se.se_flags = ESTAT_CASE_INSENSITIVE | ESTAT_SYMLINK_NOFOLLOW;
|
---|
180 |
|
---|
181 | if (*path != '\0') {
|
---|
182 | if (!(full_name = talloc_asprintf(mem_ctx, "%s/%s", path, name))) {
|
---|
183 | errno = ENOMEM;
|
---|
184 | DEBUG(2, ("talloc_asprintf failed\n"));
|
---|
185 | result = -1;
|
---|
186 | goto done;
|
---|
187 | }
|
---|
188 | }
|
---|
189 |
|
---|
190 | if ((result = estat(full_name ? full_name : name, &sb, &se)) != 0) {
|
---|
191 | DEBUG(2, ("error calling estat: %s\n", strerror(errno)));
|
---|
192 | goto done;
|
---|
193 | }
|
---|
194 |
|
---|
195 | *found_name = talloc_strdup(mem_ctx, se.se_realname);
|
---|
196 | if (*found_name == NULL) {
|
---|
197 | errno = ENOMEM;
|
---|
198 | result = -1;
|
---|
199 | goto done;
|
---|
200 | }
|
---|
201 |
|
---|
202 | done:
|
---|
203 | TALLOC_FREE(full_name);
|
---|
204 | TALLOC_FREE(unmangled_name);
|
---|
205 | return result;
|
---|
206 | }
|
---|
207 |
|
---|
208 | static int onefs_ntimes(vfs_handle_struct *handle,
|
---|
209 | const struct smb_filename *smb_fname,
|
---|
210 | struct smb_file_time *ft)
|
---|
211 | {
|
---|
212 | int flags = 0;
|
---|
213 | struct timespec times[3];
|
---|
214 |
|
---|
215 | if (!null_timespec(ft->atime)) {
|
---|
216 | flags |= VT_ATIME;
|
---|
217 | times[0] = ft->atime;
|
---|
218 | DEBUG(6,("**** onefs_ntimes: actime: %s.%d\n",
|
---|
219 | time_to_asc(convert_timespec_to_time_t(ft->atime)),
|
---|
220 | ft->atime.tv_nsec));
|
---|
221 | }
|
---|
222 |
|
---|
223 | if (!null_timespec(ft->mtime)) {
|
---|
224 | flags |= VT_MTIME;
|
---|
225 | times[1] = ft->mtime;
|
---|
226 | DEBUG(6,("**** onefs_ntimes: modtime: %s.%d\n",
|
---|
227 | time_to_asc(convert_timespec_to_time_t(ft->mtime)),
|
---|
228 | ft->mtime.tv_nsec));
|
---|
229 | }
|
---|
230 |
|
---|
231 | if (!null_timespec(ft->create_time)) {
|
---|
232 | flags |= VT_BTIME;
|
---|
233 | times[2] = ft->create_time;
|
---|
234 | DEBUG(6,("**** onefs_ntimes: createtime: %s.%d\n",
|
---|
235 | time_to_asc(convert_timespec_to_time_t(ft->create_time)),
|
---|
236 | ft->create_time.tv_nsec));
|
---|
237 | }
|
---|
238 |
|
---|
239 | return onefs_vtimes_streams(handle, smb_fname, flags, times);
|
---|
240 | }
|
---|
241 |
|
---|
242 | static uint32_t onefs_fs_capabilities(struct vfs_handle_struct *handle, enum timestamp_set_resolution *p_ts_res)
|
---|
243 | {
|
---|
244 | uint32_t result = 0;
|
---|
245 |
|
---|
246 | if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
|
---|
247 | PARM_IGNORE_STREAMS, PARM_IGNORE_STREAMS_DEFAULT)) {
|
---|
248 | result |= FILE_NAMED_STREAMS;
|
---|
249 | }
|
---|
250 |
|
---|
251 | result |= SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res);
|
---|
252 | *p_ts_res = TIMESTAMP_SET_MSEC;
|
---|
253 | return result;
|
---|
254 | }
|
---|
255 |
|
---|
256 | static struct vfs_fn_pointers onefs_fns = {
|
---|
257 | .connect_fn = onefs_connect,
|
---|
258 | .fs_capabilities = onefs_fs_capabilities,
|
---|
259 | .opendir = onefs_opendir,
|
---|
260 | .readdir = onefs_readdir,
|
---|
261 | .seekdir = onefs_seekdir,
|
---|
262 | .telldir = onefs_telldir,
|
---|
263 | .rewind_dir = onefs_rewinddir,
|
---|
264 | .mkdir = onefs_mkdir,
|
---|
265 | .closedir = onefs_closedir,
|
---|
266 | .init_search_op = onefs_init_search_op,
|
---|
267 | .open = onefs_open,
|
---|
268 | .create_file = onefs_create_file,
|
---|
269 | .close_fn = onefs_close,
|
---|
270 | .sendfile = onefs_sendfile,
|
---|
271 | .recvfile = onefs_recvfile,
|
---|
272 | .rename = onefs_rename,
|
---|
273 | .stat = onefs_stat,
|
---|
274 | .fstat = onefs_fstat,
|
---|
275 | .lstat = onefs_lstat,
|
---|
276 | .get_alloc_size = onefs_get_alloc_size,
|
---|
277 | .unlink = onefs_unlink,
|
---|
278 | .ntimes = onefs_ntimes,
|
---|
279 | .file_id_create = onefs_file_id_create,
|
---|
280 | .streaminfo = onefs_streaminfo,
|
---|
281 | .brl_lock_windows = onefs_brl_lock_windows,
|
---|
282 | .brl_unlock_windows = onefs_brl_unlock_windows,
|
---|
283 | .brl_cancel_windows = onefs_brl_cancel_windows,
|
---|
284 | .strict_lock = onefs_strict_lock,
|
---|
285 | .strict_unlock = onefs_strict_unlock,
|
---|
286 | .notify_watch = onefs_notify_watch,
|
---|
287 | .fget_nt_acl = onefs_fget_nt_acl,
|
---|
288 | .get_nt_acl = onefs_get_nt_acl,
|
---|
289 | .fset_nt_acl = onefs_fset_nt_acl,
|
---|
290 | .statvfs = onefs_statvfs,
|
---|
291 | .get_real_filename = onefs_get_real_filename,
|
---|
292 | };
|
---|
293 |
|
---|
294 | NTSTATUS vfs_onefs_init(void)
|
---|
295 | {
|
---|
296 | return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "onefs",
|
---|
297 | &onefs_fns);
|
---|
298 | }
|
---|