blob: 25940c3dc6c59472458997f4c0d6649e5eb17fb9
1 | /** |
2 | * ntfs-3g - Third Generation NTFS Driver |
3 | * |
4 | * Copyright (c) 2005-2007 Yura Pakhuchiy |
5 | * Copyright (c) 2005 Yuval Fledel |
6 | * Copyright (c) 2006-2009 Szabolcs Szakacsits |
7 | * Copyright (c) 2007-2013 Jean-Pierre Andre |
8 | * Copyright (c) 2009 Erik Larsson |
9 | * |
10 | * This file is originated from the Linux-NTFS project. |
11 | * |
12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by |
14 | * the Free Software Foundation; either version 2 of the License, or |
15 | * (at your option) any later version. |
16 | * |
17 | * This program is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | * GNU General Public License for more details. |
21 | * |
22 | * You should have received a copy of the GNU General Public License |
23 | * along with this program (in the main directory of the NTFS-3G |
24 | * distribution in the file COPYING); if not, write to the Free Software |
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
26 | */ |
27 | |
28 | #include "config.h" |
29 | |
30 | #include <fuse.h> |
31 | #include <fuse_lowlevel.h> |
32 | |
33 | #if !defined(FUSE_VERSION) || (FUSE_VERSION < 26) |
34 | #error "***********************************************************" |
35 | #error "* *" |
36 | #error "* Compilation requires at least FUSE version 2.6.0! *" |
37 | #error "* *" |
38 | #error "***********************************************************" |
39 | #endif |
40 | |
41 | #ifdef HAVE_STDIO_H |
42 | #include <stdio.h> |
43 | #endif |
44 | #ifdef HAVE_STRING_H |
45 | #include <string.h> |
46 | #endif |
47 | #ifdef HAVE_ERRNO_H |
48 | #include <errno.h> |
49 | #endif |
50 | #ifdef HAVE_FCNTL_H |
51 | #include <fcntl.h> |
52 | #endif |
53 | #ifdef HAVE_UNISTD_H |
54 | #include <unistd.h> |
55 | #endif |
56 | #ifdef HAVE_STDLIB_H |
57 | #include <stdlib.h> |
58 | #endif |
59 | #ifdef HAVE_LOCALE_H |
60 | #include <locale.h> |
61 | #endif |
62 | #include <signal.h> |
63 | #ifdef HAVE_LIMITS_H |
64 | #include <limits.h> |
65 | #endif |
66 | #include <syslog.h> |
67 | #include <sys/wait.h> |
68 | |
69 | #ifdef HAVE_SETXATTR |
70 | #include <sys/xattr.h> |
71 | #endif |
72 | |
73 | #ifdef HAVE_SYS_TYPES_H |
74 | #include <sys/types.h> |
75 | #endif |
76 | #ifdef HAVE_SYS_MKDEV_H |
77 | #include <sys/mkdev.h> |
78 | #endif |
79 | |
80 | #if defined(__APPLE__) || defined(__DARWIN__) |
81 | #include <sys/dirent.h> |
82 | #endif /* defined(__APPLE__) || defined(__DARWIN__) */ |
83 | |
84 | #include "compat.h" |
85 | #include "attrib.h" |
86 | #include "inode.h" |
87 | #include "volume.h" |
88 | #include "dir.h" |
89 | #include "unistr.h" |
90 | #include "layout.h" |
91 | #include "index.h" |
92 | #include "ntfstime.h" |
93 | #include "security.h" |
94 | #include "reparse.h" |
95 | #include "object_id.h" |
96 | #include "efs.h" |
97 | #include "logging.h" |
98 | #include "xattrs.h" |
99 | #include "misc.h" |
100 | |
101 | #include "ntfs-3g_common.h" |
102 | |
103 | /* |
104 | * The following permission checking modes are governed by |
105 | * the LPERMSCONFIG value in param.h |
106 | */ |
107 | |
108 | /* ACLS may be checked by kernel (requires a fuse patch) or here */ |
109 | #define KERNELACLS ((LPERMSCONFIG > 6) & (LPERMSCONFIG < 10)) |
110 | /* basic permissions may be checked by kernel or here */ |
111 | #define KERNELPERMS (((LPERMSCONFIG - 1) % 6) < 3) |
112 | /* may want to use fuse/kernel cacheing */ |
113 | #define CACHEING (!(LPERMSCONFIG % 3)) |
114 | |
115 | #if KERNELACLS & !KERNELPERMS |
116 | #error "Incompatible options KERNELACLS and KERNELPERMS" |
117 | #endif |
118 | |
119 | #if CACHEING & (KERNELACLS | !KERNELPERMS) |
120 | #warning "Fuse cacheing is only usable with basic permissions checked by kernel" |
121 | #endif |
122 | |
123 | #if !CACHEING |
124 | #define ATTR_TIMEOUT 0.0 |
125 | #define ENTRY_TIMEOUT 0.0 |
126 | #else |
127 | /* |
128 | * FUSE cacheing is only usable with basic permissions |
129 | * checked by the kernel with external fuse >= 2.8 |
130 | */ |
131 | #define ATTR_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0) |
132 | #define ENTRY_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0) |
133 | #endif |
134 | #define GHOSTLTH 40 /* max length of a ghost file name - see ghostformat */ |
135 | |
136 | /* sometimes the kernel cannot check access */ |
137 | #define ntfs_real_allowed_access(scx, ni, type) ntfs_allowed_access(scx, ni, type) |
138 | #if POSIXACLS & KERNELPERMS & !KERNELACLS |
139 | /* short-circuit if PERMS checked by kernel and ACLs by fs */ |
140 | #define ntfs_allowed_access(scx, ni, type) \ |
141 | ((scx)->vol->secure_flags & (1 << SECURITY_DEFAULT) \ |
142 | ? 1 : ntfs_allowed_access(scx, ni, type)) |
143 | #endif |
144 | |
145 | #define set_archive(ni) (ni)->flags |= FILE_ATTR_ARCHIVE |
146 | #define INODE(ino) ((ino) == 1 ? (MFT_REF)FILE_root : (MFT_REF)(ino)) |
147 | |
148 | typedef enum { |
149 | FSTYPE_NONE, |
150 | FSTYPE_UNKNOWN, |
151 | FSTYPE_FUSE, |
152 | FSTYPE_FUSEBLK |
153 | } fuse_fstype; |
154 | |
155 | typedef struct fill_item { |
156 | struct fill_item *next; |
157 | size_t bufsize; |
158 | size_t off; |
159 | char buf[0]; |
160 | } ntfs_fuse_fill_item_t; |
161 | |
162 | typedef struct fill_context { |
163 | struct fill_item *first; |
164 | struct fill_item *last; |
165 | fuse_req_t req; |
166 | fuse_ino_t ino; |
167 | BOOL filled; |
168 | } ntfs_fuse_fill_context_t; |
169 | |
170 | struct open_file { |
171 | struct open_file *next; |
172 | struct open_file *previous; |
173 | long long ghost; |
174 | fuse_ino_t ino; |
175 | fuse_ino_t parent; |
176 | int state; |
177 | } ; |
178 | |
179 | enum { |
180 | CLOSE_GHOST = 1, |
181 | CLOSE_COMPRESSED = 2, |
182 | CLOSE_ENCRYPTED = 4, |
183 | CLOSE_DMTIME = 8 |
184 | }; |
185 | |
186 | enum RM_TYPES { |
187 | RM_LINK, |
188 | RM_DIR, |
189 | RM_ANY, |
190 | } ; |
191 | |
192 | static struct ntfs_options opts; |
193 | |
194 | const char *EXEC_NAME = "lowntfs-3g"; |
195 | |
196 | static ntfs_fuse_context_t *ctx; |
197 | static u32 ntfs_sequence; |
198 | static const char ghostformat[] = ".ghost-ntfs-3g-%020llu"; |
199 | |
200 | static const char *usage_msg = |
201 | "\n" |
202 | "%s %s %s %d - Third Generation NTFS Driver\n" |
203 | "\t\tConfiguration type %d, " |
204 | #ifdef HAVE_SETXATTR |
205 | "XATTRS are on, " |
206 | #else |
207 | "XATTRS are off, " |
208 | #endif |
209 | #if POSIXACLS |
210 | "POSIX ACLS are on\n" |
211 | #else |
212 | "POSIX ACLS are off\n" |
213 | #endif |
214 | "\n" |
215 | "Copyright (C) 2005-2007 Yura Pakhuchiy\n" |
216 | "Copyright (C) 2006-2009 Szabolcs Szakacsits\n" |
217 | "Copyright (C) 2007-2013 Jean-Pierre Andre\n" |
218 | "Copyright (C) 2009 Erik Larsson\n" |
219 | "\n" |
220 | "Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n" |
221 | "\n" |
222 | "Options: ro (read-only mount), windows_names, uid=, gid=,\n" |
223 | " umask=, fmask=, dmask=, streams_interface=.\n" |
224 | " Please see the details in the manual (type: man ntfs-3g).\n" |
225 | "\n" |
226 | "Example: ntfs-3g /dev/sda1 /mnt/windows\n" |
227 | "\n" |
228 | "%s"; |
229 | |
230 | static const char ntfs_bad_reparse[] = "unsupported reparse point"; |
231 | |
232 | #ifdef FUSE_INTERNAL |
233 | int drop_privs(void); |
234 | int restore_privs(void); |
235 | #else |
236 | /* |
237 | * setuid and setgid root ntfs-3g denies to start with external FUSE, |
238 | * therefore the below functions are no-op in such case. |
239 | */ |
240 | static int drop_privs(void) { return 0; } |
241 | #if defined(linux) || defined(__uClinux__) |
242 | static int restore_privs(void) { return 0; } |
243 | #endif |
244 | |
245 | static const char *setuid_msg = |
246 | "Mount is denied because setuid and setgid root ntfs-3g is insecure with the\n" |
247 | "external FUSE library. Either remove the setuid/setgid bit from the binary\n" |
248 | "or rebuild NTFS-3G with integrated FUSE support and make it setuid root.\n" |
249 | "Please see more information at\n" |
250 | "http://tuxera.com/community/ntfs-3g-faq/#unprivileged\n"; |
251 | |
252 | static const char *unpriv_fuseblk_msg = |
253 | "Unprivileged user can not mount NTFS block devices using the external FUSE\n" |
254 | "library. Either mount the volume as root, or rebuild NTFS-3G with integrated\n" |
255 | "FUSE support and make it setuid root. Please see more information at\n" |
256 | "http://tuxera.com/community/ntfs-3g-faq/#unprivileged\n"; |
257 | #endif |
258 | |
259 | |
260 | static void ntfs_fuse_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) |
261 | { |
262 | if (ctx->atime == ATIME_DISABLED) |
263 | mask &= ~NTFS_UPDATE_ATIME; |
264 | else if (ctx->atime == ATIME_RELATIVE && mask == NTFS_UPDATE_ATIME && |
265 | (le64_to_cpu(ni->last_access_time) |
266 | >= le64_to_cpu(ni->last_data_change_time)) && |
267 | (le64_to_cpu(ni->last_access_time) |
268 | >= le64_to_cpu(ni->last_mft_change_time))) |
269 | return; |
270 | ntfs_inode_update_times(ni, mask); |
271 | } |
272 | |
273 | static s64 ntfs_get_nr_free_mft_records(ntfs_volume *vol) |
274 | { |
275 | ntfs_attr *na = vol->mftbmp_na; |
276 | s64 nr_free = ntfs_attr_get_free_bits(na); |
277 | |
278 | if (nr_free >= 0) |
279 | nr_free += (na->allocated_size - na->data_size) << 3; |
280 | return nr_free; |
281 | } |
282 | |
283 | /* |
284 | * Fill a security context as needed by security functions |
285 | * returns TRUE if there is a user mapping, |
286 | * FALSE if there is none |
287 | * This is not an error and the context is filled anyway, |
288 | * it is used for implicit Windows-like inheritance |
289 | */ |
290 | |
291 | static BOOL ntfs_fuse_fill_security_context(fuse_req_t req, |
292 | struct SECURITY_CONTEXT *scx) |
293 | { |
294 | const struct fuse_ctx *fusecontext; |
295 | |
296 | scx->vol = ctx->vol; |
297 | scx->mapping[MAPUSERS] = ctx->security.mapping[MAPUSERS]; |
298 | scx->mapping[MAPGROUPS] = ctx->security.mapping[MAPGROUPS]; |
299 | scx->pseccache = &ctx->seccache; |
300 | if (req) { |
301 | fusecontext = fuse_req_ctx(req); |
302 | scx->uid = fusecontext->uid; |
303 | scx->gid = fusecontext->gid; |
304 | scx->tid = fusecontext->pid; |
305 | #ifdef FUSE_CAP_DONT_MASK |
306 | /* the umask can be processed by the file system */ |
307 | scx->umask = fusecontext->umask; |
308 | #else |
309 | /* the umask if forced by fuse on creation */ |
310 | scx->umask = 0; |
311 | #endif |
312 | |
313 | } else { |
314 | scx->uid = 0; |
315 | scx->gid = 0; |
316 | scx->tid = 0; |
317 | scx->umask = 0; |
318 | } |
319 | return (ctx->security.mapping[MAPUSERS] != (struct MAPPING*)NULL); |
320 | } |
321 | |
322 | static u64 ntfs_fuse_inode_lookup(fuse_ino_t parent, const char *name) |
323 | { |
324 | u64 ino = (u64)-1; |
325 | u64 inum; |
326 | ntfs_inode *dir_ni; |
327 | |
328 | /* Open target directory. */ |
329 | dir_ni = ntfs_inode_open(ctx->vol, INODE(parent)); |
330 | if (dir_ni) { |
331 | /* Lookup file */ |
332 | inum = ntfs_inode_lookup_by_mbsname(dir_ni, name); |
333 | /* never return inodes 0 and 1 */ |
334 | if (MREF(inum) <= 1) { |
335 | inum = (u64)-1; |
336 | errno = ENOENT; |
337 | } |
338 | if (ntfs_inode_close(dir_ni) |
339 | || (inum == (u64)-1)) |
340 | ino = (u64)-1; |
341 | else |
342 | ino = MREF(inum); |
343 | } |
344 | return (ino); |
345 | } |
346 | |
347 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
348 | |
349 | /* |
350 | * Check access to parent directory |
351 | * |
352 | * file inode is only opened when not fed in and S_ISVTX is requested, |
353 | * when already open and S_ISVTX, it *HAS TO* be fed in. |
354 | * |
355 | * returns 1 if allowed, |
356 | * 0 if not allowed or some error occurred (errno tells why) |
357 | */ |
358 | |
359 | static int ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, |
360 | ntfs_inode *dir_ni, fuse_ino_t ino, |
361 | ntfs_inode *ni, mode_t accesstype) |
362 | { |
363 | int allowed; |
364 | ntfs_inode *ni2; |
365 | struct stat stbuf; |
366 | |
367 | allowed = ntfs_allowed_access(scx, dir_ni, accesstype); |
368 | /* |
369 | * for an not-owned sticky directory, have to |
370 | * check whether file itself is owned |
371 | */ |
372 | if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX)) |
373 | && (allowed == 2)) { |
374 | if (ni) |
375 | ni2 = ni; |
376 | else |
377 | ni2 = ntfs_inode_open(ctx->vol, INODE(ino)); |
378 | allowed = 0; |
379 | if (ni2) { |
380 | allowed = (ntfs_get_owner_mode(scx,ni2,&stbuf) >= 0) |
381 | && (stbuf.st_uid == scx->uid); |
382 | if (!ni) |
383 | ntfs_inode_close(ni2); |
384 | } |
385 | } |
386 | return (allowed); |
387 | } |
388 | |
389 | #endif /* !KERNELPERMS | (POSIXACLS & !KERNELACLS) */ |
390 | |
391 | /** |
392 | * ntfs_fuse_statfs - return information about mounted NTFS volume |
393 | * @path: ignored (but fuse requires it) |
394 | * @sfs: statfs structure in which to return the information |
395 | * |
396 | * Return information about the mounted NTFS volume @sb in the statfs structure |
397 | * pointed to by @sfs (this is initialized with zeros before ntfs_statfs is |
398 | * called). We interpret the values to be correct of the moment in time at |
399 | * which we are called. Most values are variable otherwise and this isn't just |
400 | * the free values but the totals as well. For example we can increase the |
401 | * total number of file nodes if we run out and we can keep doing this until |
402 | * there is no more space on the volume left at all. |
403 | * |
404 | * This code based on ntfs_statfs from ntfs kernel driver. |
405 | * |
406 | * Returns 0 on success or -errno on error. |
407 | */ |
408 | #if HAVE_SYS_STATVFS_H |
409 | static void ntfs_fuse_statfs(fuse_req_t req, |
410 | fuse_ino_t ino __attribute__((unused))) |
411 | { |
412 | struct statvfs sfs; |
413 | s64 size; |
414 | int delta_bits; |
415 | ntfs_volume *vol; |
416 | |
417 | vol = ctx->vol; |
418 | if (vol) { |
419 | /* |
420 | * File system block size. Used to calculate used/free space by df. |
421 | * Incorrectly documented as "optimal transfer block size". |
422 | */ |
423 | sfs.f_bsize = vol->cluster_size; |
424 | |
425 | /* Fundamental file system block size, used as the unit. */ |
426 | sfs.f_frsize = vol->cluster_size; |
427 | |
428 | /* |
429 | * Total number of blocks on file system in units of f_frsize. |
430 | * Since inodes are also stored in blocks ($MFT is a file) hence |
431 | * this is the number of clusters on the volume. |
432 | */ |
433 | sfs.f_blocks = vol->nr_clusters; |
434 | |
435 | /* Free blocks available for all and for non-privileged processes. */ |
436 | size = vol->free_clusters; |
437 | if (size < 0) |
438 | size = 0; |
439 | sfs.f_bavail = sfs.f_bfree = size; |
440 | |
441 | /* Free inodes on the free space */ |
442 | delta_bits = vol->cluster_size_bits - vol->mft_record_size_bits; |
443 | if (delta_bits >= 0) |
444 | size <<= delta_bits; |
445 | else |
446 | size >>= -delta_bits; |
447 | |
448 | /* Number of inodes at this point in time. */ |
449 | sfs.f_files = (vol->mftbmp_na->allocated_size << 3) + size; |
450 | |
451 | /* Free inodes available for all and for non-privileged processes. */ |
452 | size += vol->free_mft_records; |
453 | if (size < 0) |
454 | size = 0; |
455 | sfs.f_ffree = sfs.f_favail = size; |
456 | |
457 | /* Maximum length of filenames. */ |
458 | sfs.f_namemax = NTFS_MAX_NAME_LEN; |
459 | fuse_reply_statfs(req, &sfs); |
460 | } else |
461 | fuse_reply_err(req, ENODEV); |
462 | |
463 | } |
464 | #endif |
465 | |
466 | static void set_fuse_error(int *err) |
467 | { |
468 | if (!*err) |
469 | *err = -errno; |
470 | } |
471 | |
472 | #if 0 && (defined(__APPLE__) || defined(__DARWIN__)) /* Unfinished. */ |
473 | static int ntfs_macfuse_getxtimes(const char *org_path, |
474 | struct timespec *bkuptime, struct timespec *crtime) |
475 | { |
476 | int res = 0; |
477 | ntfs_inode *ni; |
478 | char *path = NULL; |
479 | ntfschar *stream_name; |
480 | int stream_name_len; |
481 | |
482 | stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); |
483 | if (stream_name_len < 0) |
484 | return stream_name_len; |
485 | memset(bkuptime, 0, sizeof(struct timespec)); |
486 | memset(crtime, 0, sizeof(struct timespec)); |
487 | ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); |
488 | if (!ni) { |
489 | res = -errno; |
490 | goto exit; |
491 | } |
492 | |
493 | /* We have no backup timestamp in NTFS. */ |
494 | crtime->tv_sec = ni->creation_time; |
495 | exit: |
496 | if (ntfs_inode_close(ni)) |
497 | set_fuse_error(&res); |
498 | free(path); |
499 | if (stream_name_len) |
500 | free(stream_name); |
501 | return res; |
502 | } |
503 | |
504 | int ntfs_macfuse_setcrtime(const char *path, const struct timespec *tv) |
505 | { |
506 | ntfs_inode *ni; |
507 | int res = 0; |
508 | |
509 | if (ntfs_fuse_is_named_data_stream(path)) |
510 | return -EINVAL; /* n/a for named data streams. */ |
511 | ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); |
512 | if (!ni) |
513 | return -errno; |
514 | |
515 | if (tv) { |
516 | ni->creation_time = tv->tv_sec; |
517 | ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); |
518 | } |
519 | |
520 | if (ntfs_inode_close(ni)) |
521 | set_fuse_error(&res); |
522 | return res; |
523 | } |
524 | |
525 | int ntfs_macfuse_setbkuptime(const char *path, const struct timespec *tv) |
526 | { |
527 | ntfs_inode *ni; |
528 | int res = 0; |
529 | |
530 | if (ntfs_fuse_is_named_data_stream(path)) |
531 | return -EINVAL; /* n/a for named data streams. */ |
532 | ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); |
533 | if (!ni) |
534 | return -errno; |
535 | |
536 | /* |
537 | * Only pretending to set backup time successfully to please the APIs of |
538 | * Mac OS X. In reality, NTFS has no backup time. |
539 | */ |
540 | |
541 | if (ntfs_inode_close(ni)) |
542 | set_fuse_error(&res); |
543 | return res; |
544 | } |
545 | |
546 | int ntfs_macfuse_setchgtime(const char *path, const struct timespec *tv) |
547 | { |
548 | ntfs_inode *ni; |
549 | int res = 0; |
550 | |
551 | if (ntfs_fuse_is_named_data_stream(path)) |
552 | return -EINVAL; /* n/a for named data streams. */ |
553 | ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); |
554 | if (!ni) |
555 | return -errno; |
556 | |
557 | if (tv) { |
558 | ni->last_mft_change_time = tv->tv_sec; |
559 | ntfs_fuse_update_times(ni, 0); |
560 | } |
561 | |
562 | if (ntfs_inode_close(ni)) |
563 | set_fuse_error(&res); |
564 | return res; |
565 | } |
566 | #endif /* defined(__APPLE__) || defined(__DARWIN__) */ |
567 | |
568 | #if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \ |
569 | || (defined(__APPLE__) || defined(__DARWIN__)) |
570 | static void ntfs_init(void *userdata __attribute__((unused)), |
571 | struct fuse_conn_info *conn) |
572 | { |
573 | #if defined(__APPLE__) || defined(__DARWIN__) |
574 | FUSE_ENABLE_XTIMES(conn); |
575 | #endif |
576 | #ifdef FUSE_CAP_DONT_MASK |
577 | /* request umask not to be enforced by fuse */ |
578 | conn->want |= FUSE_CAP_DONT_MASK; |
579 | #endif /* defined FUSE_CAP_DONT_MASK */ |
580 | #ifdef FUSE_CAP_BIG_WRITES |
581 | if (ctx->big_writes |
582 | && ((ctx->vol->nr_clusters << ctx->vol->cluster_size_bits) |
583 | >= SAFE_CAPACITY_FOR_BIG_WRITES)) |
584 | conn->want |= FUSE_CAP_BIG_WRITES; |
585 | #endif |
586 | } |
587 | #endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */ |
588 | |
589 | static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx, |
590 | ntfs_inode *ni, struct stat *stbuf) |
591 | { |
592 | int res = 0; |
593 | ntfs_attr *na; |
594 | BOOL withusermapping; |
595 | |
596 | memset(stbuf, 0, sizeof(struct stat)); |
597 | withusermapping = (scx->mapping[MAPUSERS] != (struct MAPPING*)NULL); |
598 | if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) |
599 | || (ni->flags & FILE_ATTR_REPARSE_POINT)) { |
600 | if (ni->flags & FILE_ATTR_REPARSE_POINT) { |
601 | char *target; |
602 | int attr_size; |
603 | |
604 | errno = 0; |
605 | target = ntfs_make_symlink(ni, ctx->abs_mnt_point, |
606 | &attr_size); |
607 | /* |
608 | * If the reparse point is not a valid |
609 | * directory junction, and there is no error |
610 | * we still display as a symlink |
611 | */ |
612 | if (target || (errno == EOPNOTSUPP)) { |
613 | /* returning attribute size */ |
614 | if (target) |
615 | stbuf->st_size = attr_size; |
616 | else |
617 | stbuf->st_size = |
618 | sizeof(ntfs_bad_reparse); |
619 | stbuf->st_blocks = |
620 | (ni->allocated_size + 511) >> 9; |
621 | stbuf->st_nlink = |
622 | le16_to_cpu(ni->mrec->link_count); |
623 | stbuf->st_mode = S_IFLNK; |
624 | free(target); |
625 | } else { |
626 | res = -errno; |
627 | goto exit; |
628 | } |
629 | } else { |
630 | /* Directory. */ |
631 | stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask); |
632 | /* get index size, if not known */ |
633 | if (!test_nino_flag(ni, KnownSize)) { |
634 | na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, |
635 | NTFS_INDEX_I30, 4); |
636 | if (na) { |
637 | ni->data_size = na->data_size; |
638 | ni->allocated_size = na->allocated_size; |
639 | set_nino_flag(ni, KnownSize); |
640 | ntfs_attr_close(na); |
641 | } |
642 | } |
643 | stbuf->st_size = ni->data_size; |
644 | stbuf->st_blocks = ni->allocated_size >> 9; |
645 | stbuf->st_nlink = 1; /* Make find(1) work */ |
646 | } |
647 | } else { |
648 | /* Regular or Interix (INTX) file. */ |
649 | stbuf->st_mode = S_IFREG; |
650 | stbuf->st_size = ni->data_size; |
651 | #ifdef HAVE_SETXATTR /* extended attributes interface required */ |
652 | /* |
653 | * return data size rounded to next 512 byte boundary for |
654 | * encrypted files to include padding required for decryption |
655 | * also include 2 bytes for padding info |
656 | */ |
657 | if (ctx->efs_raw |
658 | && (ni->flags & FILE_ATTR_ENCRYPTED) |
659 | && ni->data_size) |
660 | stbuf->st_size = ((ni->data_size + 511) & ~511) + 2; |
661 | #endif /* HAVE_SETXATTR */ |
662 | /* |
663 | * Temporary fix to make ActiveSync work via Samba 3.0. |
664 | * See more on the ntfs-3g-devel list. |
665 | */ |
666 | stbuf->st_blocks = (ni->allocated_size + 511) >> 9; |
667 | stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); |
668 | if (ni->flags & FILE_ATTR_SYSTEM) { |
669 | na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); |
670 | if (!na) { |
671 | stbuf->st_ino = ni->mft_no; |
672 | goto nodata; |
673 | } |
674 | /* Check whether it's Interix FIFO or socket. */ |
675 | if (!(ni->flags & FILE_ATTR_HIDDEN)) { |
676 | /* FIFO. */ |
677 | if (na->data_size == 0) |
678 | stbuf->st_mode = S_IFIFO; |
679 | /* Socket link. */ |
680 | if (na->data_size == 1) |
681 | stbuf->st_mode = S_IFSOCK; |
682 | } |
683 | /* |
684 | * Check whether it's Interix symbolic link, block or |
685 | * character device. |
686 | */ |
687 | if ((u64)na->data_size <= sizeof(INTX_FILE_TYPES) |
688 | + sizeof(ntfschar) * PATH_MAX |
689 | && (u64)na->data_size > |
690 | sizeof(INTX_FILE_TYPES)) { |
691 | INTX_FILE *intx_file; |
692 | |
693 | intx_file = |
694 | (INTX_FILE*)ntfs_malloc(na->data_size); |
695 | if (!intx_file) { |
696 | res = -errno; |
697 | ntfs_attr_close(na); |
698 | goto exit; |
699 | } |
700 | if (ntfs_attr_pread(na, 0, na->data_size, |
701 | intx_file) != na->data_size) { |
702 | res = -errno; |
703 | free(intx_file); |
704 | ntfs_attr_close(na); |
705 | goto exit; |
706 | } |
707 | if (intx_file->magic == INTX_BLOCK_DEVICE && |
708 | na->data_size == (s64)offsetof( |
709 | INTX_FILE, device_end)) { |
710 | stbuf->st_mode = S_IFBLK; |
711 | stbuf->st_rdev = makedev(le64_to_cpu( |
712 | intx_file->major), |
713 | le64_to_cpu( |
714 | intx_file->minor)); |
715 | } |
716 | if (intx_file->magic == INTX_CHARACTER_DEVICE && |
717 | na->data_size == (s64)offsetof( |
718 | INTX_FILE, device_end)) { |
719 | stbuf->st_mode = S_IFCHR; |
720 | stbuf->st_rdev = makedev(le64_to_cpu( |
721 | intx_file->major), |
722 | le64_to_cpu( |
723 | intx_file->minor)); |
724 | } |
725 | if (intx_file->magic == INTX_SYMBOLIC_LINK) |
726 | stbuf->st_mode = S_IFLNK; |
727 | free(intx_file); |
728 | } |
729 | ntfs_attr_close(na); |
730 | } |
731 | stbuf->st_mode |= (0777 & ~ctx->fmask); |
732 | } |
733 | if (withusermapping) { |
734 | if (ntfs_get_owner_mode(scx,ni,stbuf) < 0) |
735 | set_fuse_error(&res); |
736 | } else { |
737 | stbuf->st_uid = ctx->uid; |
738 | stbuf->st_gid = ctx->gid; |
739 | } |
740 | if (S_ISLNK(stbuf->st_mode)) |
741 | stbuf->st_mode |= 0777; |
742 | nodata : |
743 | stbuf->st_ino = ni->mft_no; |
744 | #ifdef HAVE_STRUCT_STAT_ST_ATIMESPEC |
745 | stbuf->st_atimespec = ntfs2timespec(ni->last_access_time); |
746 | stbuf->st_ctimespec = ntfs2timespec(ni->last_mft_change_time); |
747 | stbuf->st_mtimespec = ntfs2timespec(ni->last_data_change_time); |
748 | #elif defined(HAVE_STRUCT_STAT_ST_ATIM) |
749 | stbuf->st_atim = ntfs2timespec(ni->last_access_time); |
750 | stbuf->st_ctim = ntfs2timespec(ni->last_mft_change_time); |
751 | stbuf->st_mtim = ntfs2timespec(ni->last_data_change_time); |
752 | #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC) |
753 | { |
754 | struct timespec ts; |
755 | |
756 | ts = ntfs2timespec(ni->last_access_time); |
757 | stbuf->st_atime = ts.tv_sec; |
758 | stbuf->st_atimensec = ts.tv_nsec; |
759 | ts = ntfs2timespec(ni->last_mft_change_time); |
760 | stbuf->st_ctime = ts.tv_sec; |
761 | stbuf->st_ctimensec = ts.tv_nsec; |
762 | ts = ntfs2timespec(ni->last_data_change_time); |
763 | stbuf->st_mtime = ts.tv_sec; |
764 | stbuf->st_mtimensec = ts.tv_nsec; |
765 | } |
766 | #else |
767 | #warning "No known way to set nanoseconds in struct stat !" |
768 | { |
769 | struct timespec ts; |
770 | |
771 | ts = ntfs2timespec(ni->last_access_time); |
772 | stbuf->st_atime = ts.tv_sec; |
773 | ts = ntfs2timespec(ni->last_mft_change_time); |
774 | stbuf->st_ctime = ts.tv_sec; |
775 | ts = ntfs2timespec(ni->last_data_change_time); |
776 | stbuf->st_mtime = ts.tv_sec; |
777 | } |
778 | #endif |
779 | exit: |
780 | return (res); |
781 | } |
782 | |
783 | static void ntfs_fuse_getattr(fuse_req_t req, fuse_ino_t ino, |
784 | struct fuse_file_info *fi __attribute__((unused))) |
785 | { |
786 | int res; |
787 | ntfs_inode *ni; |
788 | struct stat stbuf; |
789 | struct SECURITY_CONTEXT security; |
790 | |
791 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
792 | if (!ni) |
793 | res = -errno; |
794 | else { |
795 | ntfs_fuse_fill_security_context(req, &security); |
796 | res = ntfs_fuse_getstat(&security, ni, &stbuf); |
797 | if (ntfs_inode_close(ni)) |
798 | set_fuse_error(&res); |
799 | } |
800 | if (!res) |
801 | fuse_reply_attr(req, &stbuf, ATTR_TIMEOUT); |
802 | else |
803 | fuse_reply_err(req, -res); |
804 | } |
805 | |
806 | static __inline__ BOOL ntfs_fuse_fillstat(struct SECURITY_CONTEXT *scx, |
807 | struct fuse_entry_param *pentry, u64 iref) |
808 | { |
809 | ntfs_inode *ni; |
810 | BOOL ok = FALSE; |
811 | |
812 | pentry->ino = MREF(iref); |
813 | ni = ntfs_inode_open(ctx->vol, pentry->ino); |
814 | if (ni) { |
815 | if (!ntfs_fuse_getstat(scx, ni, &pentry->attr)) { |
816 | pentry->generation = 1; |
817 | pentry->attr_timeout = ATTR_TIMEOUT; |
818 | pentry->entry_timeout = ENTRY_TIMEOUT; |
819 | ok = TRUE; |
820 | } |
821 | if (ntfs_inode_close(ni)) |
822 | ok = FALSE; |
823 | } |
824 | return (ok); |
825 | } |
826 | |
827 | |
828 | static void ntfs_fuse_lookup(fuse_req_t req, fuse_ino_t parent, |
829 | const char *name) |
830 | { |
831 | struct SECURITY_CONTEXT security; |
832 | struct fuse_entry_param entry; |
833 | ntfs_inode *dir_ni; |
834 | u64 iref; |
835 | BOOL ok = FALSE; |
836 | |
837 | if (strlen(name) < 256) { |
838 | dir_ni = ntfs_inode_open(ctx->vol, INODE(parent)); |
839 | if (dir_ni) { |
840 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
841 | /* |
842 | * make sure the parent directory is searchable |
843 | */ |
844 | if (ntfs_fuse_fill_security_context(req, &security) |
845 | && !ntfs_allowed_access(&security,dir_ni,S_IEXEC)) { |
846 | ntfs_inode_close(dir_ni); |
847 | errno = EACCES; |
848 | } else { |
849 | #else |
850 | ntfs_fuse_fill_security_context(req, &security); |
851 | #endif |
852 | iref = ntfs_inode_lookup_by_mbsname(dir_ni, |
853 | name); |
854 | /* never return inodes 0 and 1 */ |
855 | if (MREF(iref) <= 1) { |
856 | iref = (u64)-1; |
857 | errno = ENOENT; |
858 | } |
859 | ok = !ntfs_inode_close(dir_ni) |
860 | && (iref != (u64)-1) |
861 | && ntfs_fuse_fillstat( |
862 | &security,&entry,iref); |
863 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
864 | } |
865 | #endif |
866 | } |
867 | } else |
868 | errno = ENAMETOOLONG; |
869 | if (!ok) |
870 | fuse_reply_err(req, errno); |
871 | else |
872 | fuse_reply_entry(req, &entry); |
873 | } |
874 | |
875 | static void ntfs_fuse_readlink(fuse_req_t req, fuse_ino_t ino) |
876 | { |
877 | ntfs_inode *ni = NULL; |
878 | ntfs_attr *na = NULL; |
879 | INTX_FILE *intx_file = NULL; |
880 | char *buf = (char*)NULL; |
881 | int res = 0; |
882 | |
883 | /* Get inode. */ |
884 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
885 | if (!ni) { |
886 | res = -errno; |
887 | goto exit; |
888 | } |
889 | /* |
890 | * Reparse point : analyze as a junction point |
891 | */ |
892 | if (ni->flags & FILE_ATTR_REPARSE_POINT) { |
893 | int attr_size; |
894 | |
895 | errno = 0; |
896 | res = 0; |
897 | buf = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size); |
898 | if (!buf) { |
899 | if (errno == EOPNOTSUPP) |
900 | buf = strdup(ntfs_bad_reparse); |
901 | if (!buf) |
902 | res = -errno; |
903 | } |
904 | goto exit; |
905 | } |
906 | /* Sanity checks. */ |
907 | if (!(ni->flags & FILE_ATTR_SYSTEM)) { |
908 | res = -EINVAL; |
909 | goto exit; |
910 | } |
911 | na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); |
912 | if (!na) { |
913 | res = -errno; |
914 | goto exit; |
915 | } |
916 | if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)) { |
917 | res = -EINVAL; |
918 | goto exit; |
919 | } |
920 | if ((size_t)na->data_size > sizeof(INTX_FILE_TYPES) + |
921 | sizeof(ntfschar) * PATH_MAX) { |
922 | res = -ENAMETOOLONG; |
923 | goto exit; |
924 | } |
925 | /* Receive file content. */ |
926 | intx_file = (INTX_FILE*)ntfs_malloc(na->data_size); |
927 | if (!intx_file) { |
928 | res = -errno; |
929 | goto exit; |
930 | } |
931 | if (ntfs_attr_pread(na, 0, na->data_size, intx_file) != na->data_size) { |
932 | res = -errno; |
933 | goto exit; |
934 | } |
935 | /* Sanity check. */ |
936 | if (intx_file->magic != INTX_SYMBOLIC_LINK) { |
937 | res = -EINVAL; |
938 | goto exit; |
939 | } |
940 | /* Convert link from unicode to local encoding. */ |
941 | if (ntfs_ucstombs(intx_file->target, (na->data_size - |
942 | offsetof(INTX_FILE, target)) / sizeof(ntfschar), |
943 | &buf, 0) < 0) { |
944 | res = -errno; |
945 | goto exit; |
946 | } |
947 | exit: |
948 | if (intx_file) |
949 | free(intx_file); |
950 | if (na) |
951 | ntfs_attr_close(na); |
952 | if (ntfs_inode_close(ni)) |
953 | set_fuse_error(&res); |
954 | |
955 | if (res < 0) |
956 | fuse_reply_err(req, -res); |
957 | else |
958 | fuse_reply_readlink(req, buf); |
959 | if (buf != ntfs_bad_reparse) |
960 | free(buf); |
961 | } |
962 | |
963 | static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, |
964 | const ntfschar *name, const int name_len, const int name_type, |
965 | const s64 pos __attribute__((unused)), const MFT_REF mref, |
966 | const unsigned dt_type __attribute__((unused))) |
967 | { |
968 | char *filename = NULL; |
969 | int ret = 0; |
970 | int filenamelen = -1; |
971 | size_t sz; |
972 | ntfs_fuse_fill_item_t *current; |
973 | ntfs_fuse_fill_item_t *newone; |
974 | |
975 | if (name_type == FILE_NAME_DOS) |
976 | return 0; |
977 | |
978 | if ((filenamelen = ntfs_ucstombs(name, name_len, &filename, 0)) < 0) { |
979 | ntfs_log_perror("Filename decoding failed (inode %llu)", |
980 | (unsigned long long)MREF(mref)); |
981 | return -1; |
982 | } |
983 | /* never return inodes 0 and 1 */ |
984 | if (MREF(mref) > 1) { |
985 | struct stat st = { .st_ino = MREF(mref) }; |
986 | |
987 | switch (dt_type) { |
988 | case NTFS_DT_DIR : |
989 | st.st_mode = S_IFDIR | (0777 & ~ctx->dmask); |
990 | break; |
991 | case NTFS_DT_LNK : |
992 | st.st_mode = S_IFLNK | 0777; |
993 | break; |
994 | case NTFS_DT_FIFO : |
995 | st.st_mode = S_IFIFO; |
996 | break; |
997 | case NTFS_DT_SOCK : |
998 | st.st_mode = S_IFSOCK; |
999 | break; |
1000 | case NTFS_DT_BLK : |
1001 | st.st_mode = S_IFBLK; |
1002 | break; |
1003 | case NTFS_DT_CHR : |
1004 | st.st_mode = S_IFCHR; |
1005 | break; |
1006 | default : /* unexpected types shown as plain files */ |
1007 | case NTFS_DT_REG : |
1008 | st.st_mode = S_IFREG | (0777 & ~ctx->fmask); |
1009 | break; |
1010 | } |
1011 | |
1012 | #if defined(__APPLE__) || defined(__DARWIN__) |
1013 | /* |
1014 | * Returning file names larger than MAXNAMLEN (255) bytes |
1015 | * causes Darwin/Mac OS X to bug out and skip the entry. |
1016 | */ |
1017 | if (filenamelen > MAXNAMLEN) { |
1018 | ntfs_log_debug("Truncating %d byte filename to " |
1019 | "%d bytes.\n", filenamelen, MAXNAMLEN); |
1020 | ntfs_log_debug(" before: '%s'\n", filename); |
1021 | memset(filename + MAXNAMLEN, 0, filenamelen - MAXNAMLEN); |
1022 | ntfs_log_debug(" after: '%s'\n", filename); |
1023 | } |
1024 | #endif /* defined(__APPLE__) || defined(__DARWIN__) */ |
1025 | |
1026 | current = fill_ctx->last; |
1027 | sz = fuse_add_direntry(fill_ctx->req, |
1028 | ¤t->buf[current->off], |
1029 | current->bufsize - current->off, |
1030 | filename, &st, current->off); |
1031 | if (!sz || ((current->off + sz) > current->bufsize)) { |
1032 | newone = (ntfs_fuse_fill_item_t*)ntfs_malloc |
1033 | (sizeof(ntfs_fuse_fill_item_t) |
1034 | + current->bufsize); |
1035 | if (newone) { |
1036 | newone->off = 0; |
1037 | newone->bufsize = current->bufsize; |
1038 | newone->next = (ntfs_fuse_fill_item_t*)NULL; |
1039 | current->next = newone; |
1040 | fill_ctx->last = newone; |
1041 | current = newone; |
1042 | sz = fuse_add_direntry(fill_ctx->req, |
1043 | current->buf, |
1044 | current->bufsize - current->off, |
1045 | filename, &st, current->off); |
1046 | if (!sz) { |
1047 | errno = EIO; |
1048 | ntfs_log_error("Could not add a" |
1049 | " directory entry (inode %lld)\n", |
1050 | (unsigned long long)MREF(mref)); |
1051 | } |
1052 | } else { |
1053 | sz = 0; |
1054 | errno = ENOMEM; |
1055 | } |
1056 | } |
1057 | if (sz) { |
1058 | current->off += sz; |
1059 | } else { |
1060 | ret = -1; |
1061 | } |
1062 | } |
1063 | |
1064 | free(filename); |
1065 | return ret; |
1066 | } |
1067 | |
1068 | static void ntfs_fuse_opendir(fuse_req_t req, fuse_ino_t ino, |
1069 | struct fuse_file_info *fi) |
1070 | { |
1071 | int res = 0; |
1072 | ntfs_inode *ni; |
1073 | int accesstype; |
1074 | ntfs_fuse_fill_context_t *fill; |
1075 | struct SECURITY_CONTEXT security; |
1076 | |
1077 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1078 | if (ni) { |
1079 | if (ntfs_fuse_fill_security_context(req, &security)) { |
1080 | if (fi->flags & O_WRONLY) |
1081 | accesstype = S_IWRITE; |
1082 | else |
1083 | if (fi->flags & O_RDWR) |
1084 | accesstype = S_IWRITE | S_IREAD; |
1085 | else |
1086 | accesstype = S_IREAD; |
1087 | if (!ntfs_allowed_access(&security,ni,accesstype)) |
1088 | res = -EACCES; |
1089 | } |
1090 | if (ntfs_inode_close(ni)) |
1091 | set_fuse_error(&res); |
1092 | if (!res) { |
1093 | fill = (ntfs_fuse_fill_context_t*) |
1094 | ntfs_malloc(sizeof(ntfs_fuse_fill_context_t)); |
1095 | if (!fill) |
1096 | res = -errno; |
1097 | else { |
1098 | fill->first = fill->last |
1099 | = (ntfs_fuse_fill_item_t*)NULL; |
1100 | fill->filled = FALSE; |
1101 | fill->ino = ino; |
1102 | } |
1103 | fi->fh = (long)fill; |
1104 | } |
1105 | } else |
1106 | res = -errno; |
1107 | if (!res) |
1108 | fuse_reply_open(req, fi); |
1109 | else |
1110 | fuse_reply_err(req, -res); |
1111 | } |
1112 | |
1113 | |
1114 | static void ntfs_fuse_releasedir(fuse_req_t req, |
1115 | fuse_ino_t ino __attribute__((unused)), |
1116 | struct fuse_file_info *fi) |
1117 | { |
1118 | ntfs_fuse_fill_context_t *fill; |
1119 | ntfs_fuse_fill_item_t *current; |
1120 | |
1121 | fill = (ntfs_fuse_fill_context_t*)(long)fi->fh; |
1122 | if (fill && (fill->ino == ino)) { |
1123 | /* make sure to clear results */ |
1124 | current = fill->first; |
1125 | while (current) { |
1126 | current = current->next; |
1127 | free(fill->first); |
1128 | fill->first = current; |
1129 | } |
1130 | fill->ino = 0; |
1131 | free(fill); |
1132 | } |
1133 | fuse_reply_err(req, 0); |
1134 | } |
1135 | |
1136 | static void ntfs_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, |
1137 | off_t off __attribute__((unused)), |
1138 | struct fuse_file_info *fi __attribute__((unused))) |
1139 | { |
1140 | ntfs_fuse_fill_item_t *first; |
1141 | ntfs_fuse_fill_item_t *current; |
1142 | ntfs_fuse_fill_context_t *fill; |
1143 | ntfs_inode *ni; |
1144 | s64 pos = 0; |
1145 | int err = 0; |
1146 | |
1147 | fill = (ntfs_fuse_fill_context_t*)(long)fi->fh; |
1148 | if (fill && (fill->ino == ino)) { |
1149 | if (!fill->filled) { |
1150 | /* initial call : build the full list */ |
1151 | first = (ntfs_fuse_fill_item_t*)ntfs_malloc |
1152 | (sizeof(ntfs_fuse_fill_item_t) + size); |
1153 | if (first) { |
1154 | first->bufsize = size; |
1155 | first->off = 0; |
1156 | first->next = (ntfs_fuse_fill_item_t*)NULL; |
1157 | fill->req = req; |
1158 | fill->first = first; |
1159 | fill->last = first; |
1160 | ni = ntfs_inode_open(ctx->vol,INODE(ino)); |
1161 | if (!ni) |
1162 | err = -errno; |
1163 | else { |
1164 | if (ntfs_readdir(ni, &pos, fill, |
1165 | (ntfs_filldir_t) |
1166 | ntfs_fuse_filler)) |
1167 | err = -errno; |
1168 | fill->filled = TRUE; |
1169 | ntfs_fuse_update_times(ni, |
1170 | NTFS_UPDATE_ATIME); |
1171 | if (ntfs_inode_close(ni)) |
1172 | set_fuse_error(&err); |
1173 | } |
1174 | if (!err) |
1175 | fuse_reply_buf(req, first->buf, |
1176 | first->off); |
1177 | /* reply sent, now must exit with no error */ |
1178 | fill->first = first->next; |
1179 | free(first); |
1180 | } else |
1181 | err = -errno; |
1182 | } else { |
1183 | /* subsequent call : return next non-empty buffer */ |
1184 | current = fill->first; |
1185 | while (current && !current->off) { |
1186 | current = current->next; |
1187 | free(fill->first); |
1188 | fill->first = current; |
1189 | } |
1190 | if (current) { |
1191 | fuse_reply_buf(req, current->buf, current->off); |
1192 | fill->first = current->next; |
1193 | free(current); |
1194 | } else { |
1195 | fuse_reply_buf(req, (char*)NULL, 0); |
1196 | /* reply sent, now must exit with no error */ |
1197 | } |
1198 | } |
1199 | } else { |
1200 | errno = EIO; |
1201 | err = -errno; |
1202 | ntfs_log_error("Uninitialized fuse_readdir()\n"); |
1203 | } |
1204 | if (err) |
1205 | fuse_reply_err(req, -err); |
1206 | } |
1207 | |
1208 | static void ntfs_fuse_open(fuse_req_t req, fuse_ino_t ino, |
1209 | struct fuse_file_info *fi) |
1210 | { |
1211 | ntfs_inode *ni; |
1212 | ntfs_attr *na; |
1213 | struct open_file *of; |
1214 | int state = 0; |
1215 | char *path = NULL; |
1216 | int res = 0; |
1217 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1218 | int accesstype; |
1219 | struct SECURITY_CONTEXT security; |
1220 | #endif |
1221 | |
1222 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1223 | if (ni) { |
1224 | na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); |
1225 | if (na) { |
1226 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1227 | if (ntfs_fuse_fill_security_context(req, &security)) { |
1228 | if (fi->flags & O_WRONLY) |
1229 | accesstype = S_IWRITE; |
1230 | else |
1231 | if (fi->flags & O_RDWR) |
1232 | accesstype = S_IWRITE | S_IREAD; |
1233 | else |
1234 | accesstype = S_IREAD; |
1235 | /* check whether requested access is allowed */ |
1236 | if (!ntfs_allowed_access(&security, |
1237 | ni,accesstype)) |
1238 | res = -EACCES; |
1239 | } |
1240 | #endif |
1241 | if ((res >= 0) |
1242 | && (fi->flags & (O_WRONLY | O_RDWR))) { |
1243 | /* mark a future need to compress the last chunk */ |
1244 | if (na->data_flags & ATTR_COMPRESSION_MASK) |
1245 | state |= CLOSE_COMPRESSED; |
1246 | #ifdef HAVE_SETXATTR /* extended attributes interface required */ |
1247 | /* mark a future need to fixup encrypted inode */ |
1248 | if (ctx->efs_raw |
1249 | && !(na->data_flags & ATTR_IS_ENCRYPTED) |
1250 | && (ni->flags & FILE_ATTR_ENCRYPTED)) |
1251 | state |= CLOSE_ENCRYPTED; |
1252 | #endif /* HAVE_SETXATTR */ |
1253 | /* mark a future need to update the mtime */ |
1254 | if (ctx->dmtime) |
1255 | state |= CLOSE_DMTIME; |
1256 | /* deny opening metadata files for writing */ |
1257 | if (ino < FILE_first_user) |
1258 | res = -EPERM; |
1259 | } |
1260 | ntfs_attr_close(na); |
1261 | } else |
1262 | res = -errno; |
1263 | if (ntfs_inode_close(ni)) |
1264 | set_fuse_error(&res); |
1265 | } else |
1266 | res = -errno; |
1267 | free(path); |
1268 | if (res >= 0) { |
1269 | of = (struct open_file*)malloc(sizeof(struct open_file)); |
1270 | if (of) { |
1271 | of->parent = 0; |
1272 | of->ino = ino; |
1273 | of->state = state; |
1274 | of->next = ctx->open_files; |
1275 | of->previous = (struct open_file*)NULL; |
1276 | if (ctx->open_files) |
1277 | ctx->open_files->previous = of; |
1278 | ctx->open_files = of; |
1279 | fi->fh = (long)of; |
1280 | } |
1281 | } |
1282 | if (res) |
1283 | fuse_reply_err(req, -res); |
1284 | else |
1285 | fuse_reply_open(req, fi); |
1286 | } |
1287 | |
1288 | static void ntfs_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, |
1289 | off_t offset, |
1290 | struct fuse_file_info *fi __attribute__((unused))) |
1291 | { |
1292 | ntfs_inode *ni = NULL; |
1293 | ntfs_attr *na = NULL; |
1294 | int res; |
1295 | char *buf = (char*)NULL; |
1296 | s64 total = 0; |
1297 | s64 max_read; |
1298 | |
1299 | if (!size) { |
1300 | res = 0; |
1301 | goto exit; |
1302 | } |
1303 | buf = (char*)ntfs_malloc(size); |
1304 | if (!buf) { |
1305 | res = -errno; |
1306 | goto exit; |
1307 | } |
1308 | |
1309 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1310 | if (!ni) { |
1311 | res = -errno; |
1312 | goto exit; |
1313 | } |
1314 | na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); |
1315 | if (!na) { |
1316 | res = -errno; |
1317 | goto exit; |
1318 | } |
1319 | max_read = na->data_size; |
1320 | #ifdef HAVE_SETXATTR /* extended attributes interface required */ |
1321 | /* limit reads at next 512 byte boundary for encrypted attributes */ |
1322 | if (ctx->efs_raw |
1323 | && max_read |
1324 | && (na->data_flags & ATTR_IS_ENCRYPTED) |
1325 | && NAttrNonResident(na)) { |
1326 | max_read = ((na->data_size+511) & ~511) + 2; |
1327 | } |
1328 | #endif /* HAVE_SETXATTR */ |
1329 | if (offset + (off_t)size > max_read) { |
1330 | if (max_read < offset) |
1331 | goto ok; |
1332 | size = max_read - offset; |
1333 | } |
1334 | while (size > 0) { |
1335 | s64 ret = ntfs_attr_pread(na, offset, size, buf + total); |
1336 | if (ret != (s64)size) |
1337 | ntfs_log_perror("ntfs_attr_pread error reading inode %lld at " |
1338 | "offset %lld: %lld <> %lld", (long long)ni->mft_no, |
1339 | (long long)offset, (long long)size, (long long)ret); |
1340 | if (ret <= 0 || ret > (s64)size) { |
1341 | res = (ret < 0) ? -errno : -EIO; |
1342 | goto exit; |
1343 | } |
1344 | size -= ret; |
1345 | offset += ret; |
1346 | total += ret; |
1347 | } |
1348 | ok: |
1349 | ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME); |
1350 | res = total; |
1351 | exit: |
1352 | if (na) |
1353 | ntfs_attr_close(na); |
1354 | if (ntfs_inode_close(ni)) |
1355 | set_fuse_error(&res); |
1356 | if (res < 0) |
1357 | fuse_reply_err(req, -res); |
1358 | else |
1359 | fuse_reply_buf(req, buf, res); |
1360 | free(buf); |
1361 | } |
1362 | |
1363 | static void ntfs_fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf, |
1364 | size_t size, off_t offset, |
1365 | struct fuse_file_info *fi __attribute__((unused))) |
1366 | { |
1367 | ntfs_inode *ni = NULL; |
1368 | ntfs_attr *na = NULL; |
1369 | int res, total = 0; |
1370 | |
1371 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1372 | if (!ni) { |
1373 | res = -errno; |
1374 | goto exit; |
1375 | } |
1376 | na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); |
1377 | if (!na) { |
1378 | res = -errno; |
1379 | goto exit; |
1380 | } |
1381 | while (size) { |
1382 | s64 ret = ntfs_attr_pwrite(na, offset, size, buf + total); |
1383 | if (ret <= 0) { |
1384 | res = -errno; |
1385 | goto exit; |
1386 | } |
1387 | size -= ret; |
1388 | offset += ret; |
1389 | total += ret; |
1390 | } |
1391 | res = total; |
1392 | if ((res > 0) |
1393 | && (!ctx->dmtime |
1394 | || (le64_to_cpu(ntfs_current_time()) |
1395 | - le64_to_cpu(ni->last_data_change_time)) > ctx->dmtime)) |
1396 | ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); |
1397 | exit: |
1398 | if (na) |
1399 | ntfs_attr_close(na); |
1400 | if (total) |
1401 | set_archive(ni); |
1402 | if (ntfs_inode_close(ni)) |
1403 | set_fuse_error(&res); |
1404 | if (res < 0) |
1405 | fuse_reply_err(req, -res); |
1406 | else |
1407 | fuse_reply_write(req, res); |
1408 | } |
1409 | |
1410 | static int ntfs_fuse_chmod(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, |
1411 | mode_t mode, struct stat *stbuf) |
1412 | { |
1413 | int res = 0; |
1414 | ntfs_inode *ni; |
1415 | |
1416 | /* return unsupported if no user mapping has been defined */ |
1417 | if (!scx->mapping[MAPUSERS] && !ctx->silent) { |
1418 | res = -EOPNOTSUPP; |
1419 | } else { |
1420 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1421 | if (!ni) |
1422 | res = -errno; |
1423 | else { |
1424 | if (scx->mapping[MAPUSERS]) { |
1425 | if (ntfs_set_mode(scx, ni, mode)) |
1426 | res = -errno; |
1427 | else { |
1428 | ntfs_fuse_update_times(ni, |
1429 | NTFS_UPDATE_CTIME); |
1430 | /* |
1431 | * Must return updated times, and |
1432 | * inode has been updated, so hope |
1433 | * we get no further errors |
1434 | */ |
1435 | res = ntfs_fuse_getstat(scx, ni, stbuf); |
1436 | } |
1437 | NInoSetDirty(ni); |
1438 | } else |
1439 | res = ntfs_fuse_getstat(scx, ni, stbuf); |
1440 | if (ntfs_inode_close(ni)) |
1441 | set_fuse_error(&res); |
1442 | } |
1443 | } |
1444 | return res; |
1445 | } |
1446 | |
1447 | static int ntfs_fuse_chown(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, |
1448 | uid_t uid, gid_t gid, struct stat *stbuf) |
1449 | { |
1450 | ntfs_inode *ni; |
1451 | int res; |
1452 | |
1453 | if (!scx->mapping[MAPUSERS] |
1454 | && !ctx->silent |
1455 | && ((uid != ctx->uid) || (gid != ctx->gid))) |
1456 | res = -EOPNOTSUPP; |
1457 | else { |
1458 | res = 0; |
1459 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1460 | if (!ni) |
1461 | res = -errno; |
1462 | else { |
1463 | if (scx->mapping[MAPUSERS] |
1464 | && (((int)uid != -1) || ((int)gid != -1))) { |
1465 | if (ntfs_set_owner(scx, ni, uid, gid)) |
1466 | res = -errno; |
1467 | else { |
1468 | ntfs_fuse_update_times(ni, |
1469 | NTFS_UPDATE_CTIME); |
1470 | /* |
1471 | * Must return updated times, and |
1472 | * inode has been updated, so hope |
1473 | * we get no further errors |
1474 | */ |
1475 | res = ntfs_fuse_getstat(scx, ni, stbuf); |
1476 | } |
1477 | } else |
1478 | res = ntfs_fuse_getstat(scx, ni, stbuf); |
1479 | if (ntfs_inode_close(ni)) |
1480 | set_fuse_error(&res); |
1481 | } |
1482 | } |
1483 | return (res); |
1484 | } |
1485 | |
1486 | static int ntfs_fuse_chownmod(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, |
1487 | uid_t uid, gid_t gid, mode_t mode, struct stat *stbuf) |
1488 | { |
1489 | ntfs_inode *ni; |
1490 | int res; |
1491 | |
1492 | if (!scx->mapping[MAPUSERS] |
1493 | && !ctx->silent |
1494 | && ((uid != ctx->uid) || (gid != ctx->gid))) |
1495 | res = -EOPNOTSUPP; |
1496 | else { |
1497 | res = 0; |
1498 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1499 | if (!ni) |
1500 | res = -errno; |
1501 | else { |
1502 | if (scx->mapping[MAPUSERS]) { |
1503 | if (ntfs_set_ownmod(scx, ni, uid, gid, mode)) |
1504 | res = -errno; |
1505 | else { |
1506 | ntfs_fuse_update_times(ni, |
1507 | NTFS_UPDATE_CTIME); |
1508 | /* |
1509 | * Must return updated times, and |
1510 | * inode has been updated, so hope |
1511 | * we get no further errors |
1512 | */ |
1513 | res = ntfs_fuse_getstat(scx, ni, stbuf); |
1514 | } |
1515 | } else |
1516 | res = ntfs_fuse_getstat(scx, ni, stbuf); |
1517 | if (ntfs_inode_close(ni)) |
1518 | set_fuse_error(&res); |
1519 | } |
1520 | } |
1521 | return (res); |
1522 | } |
1523 | |
1524 | static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, |
1525 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1526 | off_t size, BOOL chkwrite, struct stat *stbuf) |
1527 | #else |
1528 | off_t size, BOOL chkwrite __attribute__((unused)), |
1529 | struct stat *stbuf) |
1530 | #endif |
1531 | { |
1532 | ntfs_inode *ni = NULL; |
1533 | ntfs_attr *na = NULL; |
1534 | int res; |
1535 | s64 oldsize; |
1536 | |
1537 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1538 | if (!ni) |
1539 | goto exit; |
1540 | |
1541 | /* deny truncating metadata files */ |
1542 | if (ino < FILE_first_user) { |
1543 | errno = EPERM; |
1544 | goto exit; |
1545 | } |
1546 | na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); |
1547 | if (!na) |
1548 | goto exit; |
1549 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1550 | /* |
1551 | * deny truncation if cannot write to file |
1552 | * (already checked for ftruncate()) |
1553 | */ |
1554 | if (scx->mapping[MAPUSERS] |
1555 | && chkwrite |
1556 | && !ntfs_allowed_access(scx, ni, S_IWRITE)) { |
1557 | errno = EACCES; |
1558 | goto exit; |
1559 | } |
1560 | #endif |
1561 | /* |
1562 | * for compressed files, upsizing is done by inserting a final |
1563 | * zero, which is optimized as creating a hole when possible. |
1564 | */ |
1565 | oldsize = na->data_size; |
1566 | if ((na->data_flags & ATTR_COMPRESSION_MASK) |
1567 | && (size > na->initialized_size)) { |
1568 | char zero = 0; |
1569 | if (ntfs_attr_pwrite(na, size - 1, 1, &zero) <= 0) |
1570 | goto exit; |
1571 | } else |
1572 | if (ntfs_attr_truncate(na, size)) |
1573 | goto exit; |
1574 | if (oldsize != size) |
1575 | set_archive(ni); |
1576 | |
1577 | ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); |
1578 | res = ntfs_fuse_getstat(scx, ni, stbuf); |
1579 | errno = (res ? -res : 0); |
1580 | exit: |
1581 | res = -errno; |
1582 | ntfs_attr_close(na); |
1583 | if (ntfs_inode_close(ni)) |
1584 | set_fuse_error(&res); |
1585 | return res; |
1586 | } |
1587 | |
1588 | #if defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW) |
1589 | |
1590 | static int ntfs_fuse_utimens(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, |
1591 | struct stat *stin, struct stat *stbuf, int to_set) |
1592 | { |
1593 | ntfs_inode *ni; |
1594 | int res = 0; |
1595 | |
1596 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1597 | if (!ni) |
1598 | return -errno; |
1599 | |
1600 | /* no check or update if both UTIME_OMIT */ |
1601 | if (to_set & (FUSE_SET_ATTR_ATIME + FUSE_SET_ATTR_MTIME)) { |
1602 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1603 | if (ntfs_allowed_as_owner(scx, ni) |
1604 | || ((to_set & FUSE_SET_ATTR_ATIME_NOW) |
1605 | && (to_set & FUSE_SET_ATTR_MTIME_NOW) |
1606 | && ntfs_allowed_access(scx, ni, S_IWRITE))) { |
1607 | #endif |
1608 | ntfs_time_update_flags mask = NTFS_UPDATE_CTIME; |
1609 | |
1610 | if (to_set & FUSE_SET_ATTR_ATIME_NOW) |
1611 | mask |= NTFS_UPDATE_ATIME; |
1612 | else |
1613 | if (to_set & FUSE_SET_ATTR_ATIME) |
1614 | ni->last_access_time |
1615 | = timespec2ntfs(stin->st_atim); |
1616 | if (to_set & FUSE_SET_ATTR_MTIME_NOW) |
1617 | mask |= NTFS_UPDATE_MTIME; |
1618 | else |
1619 | if (to_set & FUSE_SET_ATTR_MTIME) |
1620 | ni->last_data_change_time |
1621 | = timespec2ntfs(stin->st_mtim); |
1622 | ntfs_inode_update_times(ni, mask); |
1623 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1624 | } else |
1625 | res = -errno; |
1626 | #endif |
1627 | } |
1628 | if (!res) |
1629 | res = ntfs_fuse_getstat(scx, ni, stbuf); |
1630 | if (ntfs_inode_close(ni)) |
1631 | set_fuse_error(&res); |
1632 | return res; |
1633 | } |
1634 | |
1635 | #else /* defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW) */ |
1636 | |
1637 | static int ntfs_fuse_utime(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, |
1638 | struct stat *stin, struct stat *stbuf) |
1639 | { |
1640 | ntfs_inode *ni; |
1641 | int res = 0; |
1642 | struct timespec actime; |
1643 | struct timespec modtime; |
1644 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1645 | BOOL ownerok; |
1646 | BOOL writeok; |
1647 | #endif |
1648 | |
1649 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1650 | if (!ni) |
1651 | return -errno; |
1652 | |
1653 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1654 | ownerok = ntfs_allowed_as_owner(scx, ni); |
1655 | if (stin) { |
1656 | /* |
1657 | * fuse never calls with a NULL buf and we do not |
1658 | * know whether the specific condition can be applied |
1659 | * So we have to accept updating by a non-owner having |
1660 | * write access. |
1661 | */ |
1662 | writeok = !ownerok |
1663 | && (stin->st_atime == stin->st_mtime) |
1664 | && ntfs_allowed_access(scx, ni, S_IWRITE); |
1665 | /* Must be owner */ |
1666 | if (!ownerok && !writeok) |
1667 | res = (stin->st_atime == stin->st_mtime |
1668 | ? -EACCES : -EPERM); |
1669 | else { |
1670 | actime.tv_sec = stin->st_atime; |
1671 | actime.tv_nsec = 0; |
1672 | modtime.tv_sec = stin->st_mtime; |
1673 | modtime.tv_nsec = 0; |
1674 | ni->last_access_time = timespec2ntfs(actime); |
1675 | ni->last_data_change_time = timespec2ntfs(modtime); |
1676 | ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); |
1677 | } |
1678 | } else { |
1679 | /* Must be owner or have write access */ |
1680 | writeok = !ownerok |
1681 | && ntfs_allowed_access(scx, ni, S_IWRITE); |
1682 | if (!ownerok && !writeok) |
1683 | res = -EACCES; |
1684 | else |
1685 | ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME); |
1686 | } |
1687 | #else |
1688 | if (stin) { |
1689 | actime.tv_sec = stin->st_atime; |
1690 | actime.tv_nsec = 0; |
1691 | modtime.tv_sec = stin->st_mtime; |
1692 | modtime.tv_nsec = 0; |
1693 | ni->last_access_time = timespec2ntfs(actime); |
1694 | ni->last_data_change_time = timespec2ntfs(modtime); |
1695 | ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); |
1696 | } else |
1697 | ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME); |
1698 | #endif |
1699 | |
1700 | res = ntfs_fuse_getstat(scx, ni, stbuf); |
1701 | if (ntfs_inode_close(ni)) |
1702 | set_fuse_error(&res); |
1703 | return res; |
1704 | } |
1705 | |
1706 | #endif /* defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW) */ |
1707 | |
1708 | static void ntfs_fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, |
1709 | int to_set, struct fuse_file_info *fi __attribute__((unused))) |
1710 | { |
1711 | struct stat stbuf; |
1712 | ntfs_inode *ni; |
1713 | int res; |
1714 | struct SECURITY_CONTEXT security; |
1715 | |
1716 | res = 0; |
1717 | ntfs_fuse_fill_security_context(req, &security); |
1718 | /* no flags */ |
1719 | if (!(to_set |
1720 | & (FUSE_SET_ATTR_MODE |
1721 | | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID |
1722 | | FUSE_SET_ATTR_SIZE |
1723 | | FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) { |
1724 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1725 | if (!ni) |
1726 | res = -errno; |
1727 | else { |
1728 | res = ntfs_fuse_getstat(&security, ni, &stbuf); |
1729 | if (ntfs_inode_close(ni)) |
1730 | set_fuse_error(&res); |
1731 | } |
1732 | } |
1733 | /* some set of uid/gid/mode */ |
1734 | if (to_set |
1735 | & (FUSE_SET_ATTR_MODE |
1736 | | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) { |
1737 | switch (to_set |
1738 | & (FUSE_SET_ATTR_MODE |
1739 | | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) { |
1740 | case FUSE_SET_ATTR_MODE : |
1741 | res = ntfs_fuse_chmod(&security, ino, |
1742 | attr->st_mode & 07777, &stbuf); |
1743 | break; |
1744 | case FUSE_SET_ATTR_UID : |
1745 | res = ntfs_fuse_chown(&security, ino, attr->st_uid, |
1746 | (gid_t)-1, &stbuf); |
1747 | break; |
1748 | case FUSE_SET_ATTR_GID : |
1749 | res = ntfs_fuse_chown(&security, ino, (uid_t)-1, |
1750 | attr->st_gid, &stbuf); |
1751 | break; |
1752 | case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_GID : |
1753 | res = ntfs_fuse_chown(&security, ino, attr->st_uid, |
1754 | attr->st_gid, &stbuf); |
1755 | break; |
1756 | case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_MODE: |
1757 | res = ntfs_fuse_chownmod(&security, ino, attr->st_uid, |
1758 | (gid_t)-1,attr->st_mode, |
1759 | &stbuf); |
1760 | break; |
1761 | case FUSE_SET_ATTR_GID + FUSE_SET_ATTR_MODE: |
1762 | res = ntfs_fuse_chownmod(&security, ino, (uid_t)-1, |
1763 | attr->st_gid,attr->st_mode, |
1764 | &stbuf); |
1765 | break; |
1766 | case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_GID + FUSE_SET_ATTR_MODE: |
1767 | res = ntfs_fuse_chownmod(&security, ino, attr->st_uid, |
1768 | attr->st_gid,attr->st_mode, &stbuf); |
1769 | break; |
1770 | default : |
1771 | break; |
1772 | } |
1773 | } |
1774 | /* size */ |
1775 | if (!res && (to_set & FUSE_SET_ATTR_SIZE)) { |
1776 | res = ntfs_fuse_trunc(&security, ino, attr->st_size, |
1777 | !fi, &stbuf); |
1778 | } |
1779 | /* some set of atime/mtime */ |
1780 | if (!res && (to_set & (FUSE_SET_ATTR_ATIME + FUSE_SET_ATTR_MTIME))) { |
1781 | #if defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW) |
1782 | res = ntfs_fuse_utimens(&security, ino, attr, &stbuf, to_set); |
1783 | #else /* defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW) */ |
1784 | res = ntfs_fuse_utime(&security, ino, attr, &stbuf); |
1785 | #endif /* defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW) */ |
1786 | } |
1787 | if (res) |
1788 | fuse_reply_err(req, -res); |
1789 | else |
1790 | fuse_reply_attr(req, &stbuf, ATTR_TIMEOUT); |
1791 | } |
1792 | |
1793 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1794 | |
1795 | static void ntfs_fuse_access(fuse_req_t req, fuse_ino_t ino, int mask) |
1796 | { |
1797 | int res = 0; |
1798 | int mode; |
1799 | ntfs_inode *ni; |
1800 | struct SECURITY_CONTEXT security; |
1801 | |
1802 | /* JPA return unsupported if no user mapping has been defined */ |
1803 | if (!ntfs_fuse_fill_security_context(req, &security)) { |
1804 | if (ctx->silent) |
1805 | res = 0; |
1806 | else |
1807 | res = -EOPNOTSUPP; |
1808 | } else { |
1809 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
1810 | if (!ni) { |
1811 | res = -errno; |
1812 | } else { |
1813 | mode = 0; |
1814 | if (mask & (X_OK | W_OK | R_OK)) { |
1815 | if (mask & X_OK) mode += S_IEXEC; |
1816 | if (mask & W_OK) mode += S_IWRITE; |
1817 | if (mask & R_OK) mode += S_IREAD; |
1818 | if (!ntfs_allowed_access(&security, |
1819 | ni, mode)) |
1820 | res = -errno; |
1821 | } |
1822 | if (ntfs_inode_close(ni)) |
1823 | set_fuse_error(&res); |
1824 | } |
1825 | } |
1826 | if (res < 0) |
1827 | fuse_reply_err(req, -res); |
1828 | else |
1829 | fuse_reply_err(req, 0); |
1830 | } |
1831 | |
1832 | #endif /* !KERNELPERMS | (POSIXACLS & !KERNELACLS) */ |
1833 | |
1834 | static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name, |
1835 | mode_t typemode, dev_t dev, |
1836 | struct fuse_entry_param *e, |
1837 | const char *target, struct fuse_file_info *fi) |
1838 | { |
1839 | ntfschar *uname = NULL, *utarget = NULL; |
1840 | ntfs_inode *dir_ni = NULL, *ni; |
1841 | struct open_file *of; |
1842 | int state = 0; |
1843 | le32 securid; |
1844 | gid_t gid; |
1845 | mode_t dsetgid; |
1846 | mode_t type = typemode & ~07777; |
1847 | mode_t perm; |
1848 | struct SECURITY_CONTEXT security; |
1849 | int res = 0, uname_len, utarget_len; |
1850 | |
1851 | /* Generate unicode filename. */ |
1852 | uname_len = ntfs_mbstoucs(name, &uname); |
1853 | if ((uname_len < 0) |
1854 | || (ctx->windows_names |
1855 | && ntfs_forbidden_chars(uname,uname_len))) { |
1856 | res = -errno; |
1857 | goto exit; |
1858 | } |
1859 | /* Open parent directory. */ |
1860 | dir_ni = ntfs_inode_open(ctx->vol, INODE(parent)); |
1861 | if (!dir_ni) { |
1862 | res = -errno; |
1863 | goto exit; |
1864 | } |
1865 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1866 | /* make sure parent directory is writeable and executable */ |
1867 | if (!ntfs_fuse_fill_security_context(req, &security) |
1868 | || ntfs_allowed_create(&security, |
1869 | dir_ni, &gid, &dsetgid)) { |
1870 | #else |
1871 | ntfs_fuse_fill_security_context(req, &security); |
1872 | ntfs_allowed_create(&security, dir_ni, &gid, &dsetgid); |
1873 | #endif |
1874 | if (S_ISDIR(type)) |
1875 | perm = (typemode & ~ctx->dmask & 0777) |
1876 | | (dsetgid & S_ISGID); |
1877 | else |
1878 | perm = typemode & ~ctx->fmask & 0777; |
1879 | /* |
1880 | * Try to get a security id available for |
1881 | * file creation (from inheritance or argument). |
1882 | * This is not possible for NTFS 1.x, and we will |
1883 | * have to build a security attribute later. |
1884 | */ |
1885 | if (!ctx->security.mapping[MAPUSERS]) |
1886 | securid = const_cpu_to_le32(0); |
1887 | else |
1888 | if (ctx->inherit) |
1889 | securid = ntfs_inherited_id(&security, |
1890 | dir_ni, S_ISDIR(type)); |
1891 | else |
1892 | #if POSIXACLS |
1893 | securid = ntfs_alloc_securid(&security, |
1894 | security.uid, gid, |
1895 | dir_ni, perm, S_ISDIR(type)); |
1896 | #else |
1897 | securid = ntfs_alloc_securid(&security, |
1898 | security.uid, gid, |
1899 | perm & ~security.umask, S_ISDIR(type)); |
1900 | #endif |
1901 | /* Create object specified in @type. */ |
1902 | switch (type) { |
1903 | case S_IFCHR: |
1904 | case S_IFBLK: |
1905 | ni = ntfs_create_device(dir_ni, securid, |
1906 | uname, uname_len, type, dev); |
1907 | break; |
1908 | case S_IFLNK: |
1909 | utarget_len = ntfs_mbstoucs(target, &utarget); |
1910 | if (utarget_len < 0) { |
1911 | res = -errno; |
1912 | goto exit; |
1913 | } |
1914 | ni = ntfs_create_symlink(dir_ni, securid, |
1915 | uname, uname_len, |
1916 | utarget, utarget_len); |
1917 | break; |
1918 | default: |
1919 | ni = ntfs_create(dir_ni, securid, uname, |
1920 | uname_len, type); |
1921 | break; |
1922 | } |
1923 | if (ni) { |
1924 | /* |
1925 | * set the security attribute if a security id |
1926 | * could not be allocated (eg NTFS 1.x) |
1927 | */ |
1928 | if (ctx->security.mapping[MAPUSERS]) { |
1929 | #if POSIXACLS |
1930 | if (!securid |
1931 | && ntfs_set_inherited_posix(&security, ni, |
1932 | security.uid, gid, |
1933 | dir_ni, perm) < 0) |
1934 | set_fuse_error(&res); |
1935 | #else |
1936 | if (!securid |
1937 | && ntfs_set_owner_mode(&security, ni, |
1938 | security.uid, gid, |
1939 | perm & ~security.umask) < 0) |
1940 | set_fuse_error(&res); |
1941 | #endif |
1942 | } |
1943 | set_archive(ni); |
1944 | /* mark a need to compress the end of file */ |
1945 | if (fi && (ni->flags & FILE_ATTR_COMPRESSED)) { |
1946 | state |= CLOSE_COMPRESSED; |
1947 | } |
1948 | #ifdef HAVE_SETXATTR /* extended attributes interface required */ |
1949 | /* mark a future need to fixup encrypted inode */ |
1950 | if (fi |
1951 | && ctx->efs_raw |
1952 | && (ni->flags & FILE_ATTR_ENCRYPTED)) |
1953 | state |= CLOSE_ENCRYPTED; |
1954 | #endif /* HAVE_SETXATTR */ |
1955 | if (fi && ctx->dmtime) |
1956 | state |= CLOSE_DMTIME; |
1957 | ntfs_inode_update_mbsname(dir_ni, name, ni->mft_no); |
1958 | NInoSetDirty(ni); |
1959 | e->ino = ni->mft_no; |
1960 | e->generation = 1; |
1961 | e->attr_timeout = ATTR_TIMEOUT; |
1962 | e->entry_timeout = ENTRY_TIMEOUT; |
1963 | res = ntfs_fuse_getstat(&security, ni, &e->attr); |
1964 | /* |
1965 | * closing ni requires access to dir_ni to |
1966 | * synchronize the index, avoid double opening. |
1967 | */ |
1968 | if (ntfs_inode_close_in_dir(ni, dir_ni)) |
1969 | set_fuse_error(&res); |
1970 | ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME); |
1971 | } else |
1972 | res = -errno; |
1973 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
1974 | } else |
1975 | res = -errno; |
1976 | #endif |
1977 | |
1978 | exit: |
1979 | free(uname); |
1980 | if (ntfs_inode_close(dir_ni)) |
1981 | set_fuse_error(&res); |
1982 | if (utarget) |
1983 | free(utarget); |
1984 | if ((res >= 0) && fi) { |
1985 | of = (struct open_file*)malloc(sizeof(struct open_file)); |
1986 | if (of) { |
1987 | of->parent = 0; |
1988 | of->ino = e->ino; |
1989 | of->state = state; |
1990 | of->next = ctx->open_files; |
1991 | of->previous = (struct open_file*)NULL; |
1992 | if (ctx->open_files) |
1993 | ctx->open_files->previous = of; |
1994 | ctx->open_files = of; |
1995 | fi->fh = (long)of; |
1996 | } |
1997 | } |
1998 | return res; |
1999 | } |
2000 | |
2001 | static void ntfs_fuse_create_file(fuse_req_t req, fuse_ino_t parent, |
2002 | const char *name, mode_t mode, |
2003 | struct fuse_file_info *fi) |
2004 | { |
2005 | int res; |
2006 | struct fuse_entry_param entry; |
2007 | |
2008 | res = ntfs_fuse_create(req, parent, name, mode & (S_IFMT | 07777), |
2009 | 0, &entry, NULL, fi); |
2010 | if (res < 0) |
2011 | fuse_reply_err(req, -res); |
2012 | else |
2013 | fuse_reply_create(req, &entry, fi); |
2014 | } |
2015 | |
2016 | static void ntfs_fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, |
2017 | mode_t mode, dev_t rdev) |
2018 | { |
2019 | int res; |
2020 | struct fuse_entry_param e; |
2021 | |
2022 | res = ntfs_fuse_create(req, parent, name, mode & (S_IFMT | 07777), |
2023 | rdev, &e,NULL,(struct fuse_file_info*)NULL); |
2024 | if (res < 0) |
2025 | fuse_reply_err(req, -res); |
2026 | else |
2027 | fuse_reply_entry(req, &e); |
2028 | } |
2029 | |
2030 | static void ntfs_fuse_symlink(fuse_req_t req, const char *target, |
2031 | fuse_ino_t parent, const char *name) |
2032 | { |
2033 | int res; |
2034 | struct fuse_entry_param entry; |
2035 | |
2036 | res = ntfs_fuse_create(req, parent, name, S_IFLNK, 0, |
2037 | &entry, target, (struct fuse_file_info*)NULL); |
2038 | if (res < 0) |
2039 | fuse_reply_err(req, -res); |
2040 | else |
2041 | fuse_reply_entry(req, &entry); |
2042 | } |
2043 | |
2044 | |
2045 | static int ntfs_fuse_newlink(fuse_req_t req __attribute__((unused)), |
2046 | fuse_ino_t ino, fuse_ino_t newparent, |
2047 | const char *newname, struct fuse_entry_param *e) |
2048 | { |
2049 | ntfschar *uname = NULL; |
2050 | ntfs_inode *dir_ni = NULL, *ni; |
2051 | int res = 0, uname_len; |
2052 | struct SECURITY_CONTEXT security; |
2053 | |
2054 | /* Open file for which create hard link. */ |
2055 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
2056 | if (!ni) { |
2057 | res = -errno; |
2058 | goto exit; |
2059 | } |
2060 | |
2061 | /* Do not accept linking to a directory (except for renaming) */ |
2062 | if (e && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { |
2063 | errno = EPERM; |
2064 | res = -errno; |
2065 | goto exit; |
2066 | } |
2067 | /* Generate unicode filename. */ |
2068 | uname_len = ntfs_mbstoucs(newname, &uname); |
2069 | if ((uname_len < 0) |
2070 | || (ctx->windows_names |
2071 | && ntfs_forbidden_chars(uname,uname_len))) { |
2072 | res = -errno; |
2073 | goto exit; |
2074 | } |
2075 | /* Open parent directory. */ |
2076 | dir_ni = ntfs_inode_open(ctx->vol, INODE(newparent)); |
2077 | if (!dir_ni) { |
2078 | res = -errno; |
2079 | goto exit; |
2080 | } |
2081 | |
2082 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2083 | /* make sure the target parent directory is writeable */ |
2084 | if (ntfs_fuse_fill_security_context(req, &security) |
2085 | && !ntfs_allowed_access(&security,dir_ni,S_IWRITE + S_IEXEC)) |
2086 | res = -EACCES; |
2087 | else |
2088 | #else |
2089 | ntfs_fuse_fill_security_context(req, &security); |
2090 | #endif |
2091 | { |
2092 | if (ntfs_link(ni, dir_ni, uname, uname_len)) { |
2093 | res = -errno; |
2094 | goto exit; |
2095 | } |
2096 | ntfs_inode_update_mbsname(dir_ni, newname, ni->mft_no); |
2097 | if (e) { |
2098 | e->ino = ni->mft_no; |
2099 | e->generation = 1; |
2100 | e->attr_timeout = ATTR_TIMEOUT; |
2101 | e->entry_timeout = ENTRY_TIMEOUT; |
2102 | res = ntfs_fuse_getstat(&security, ni, &e->attr); |
2103 | } |
2104 | set_archive(ni); |
2105 | ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); |
2106 | ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME); |
2107 | } |
2108 | exit: |
2109 | /* |
2110 | * Must close dir_ni first otherwise ntfs_inode_sync_file_name(ni) |
2111 | * may fail because ni may not be in parent's index on the disk yet. |
2112 | */ |
2113 | if (ntfs_inode_close(dir_ni)) |
2114 | set_fuse_error(&res); |
2115 | if (ntfs_inode_close(ni)) |
2116 | set_fuse_error(&res); |
2117 | free(uname); |
2118 | return (res); |
2119 | } |
2120 | |
2121 | static void ntfs_fuse_link(fuse_req_t req, fuse_ino_t ino, |
2122 | fuse_ino_t newparent, const char *newname) |
2123 | { |
2124 | struct fuse_entry_param entry; |
2125 | int res; |
2126 | |
2127 | res = ntfs_fuse_newlink(req, ino, newparent, newname, &entry); |
2128 | if (res) |
2129 | fuse_reply_err(req, -res); |
2130 | else |
2131 | fuse_reply_entry(req, &entry); |
2132 | } |
2133 | |
2134 | static int ntfs_fuse_rm(fuse_req_t req, fuse_ino_t parent, const char *name, |
2135 | enum RM_TYPES rm_type __attribute__((unused))) |
2136 | { |
2137 | ntfschar *uname = NULL; |
2138 | ntfschar *ugname; |
2139 | ntfs_inode *dir_ni = NULL, *ni = NULL; |
2140 | int res = 0, uname_len; |
2141 | int ugname_len; |
2142 | u64 iref; |
2143 | fuse_ino_t ino; |
2144 | struct open_file *of; |
2145 | char ghostname[GHOSTLTH]; |
2146 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2147 | struct SECURITY_CONTEXT security; |
2148 | #endif |
2149 | |
2150 | /* Open parent directory. */ |
2151 | dir_ni = ntfs_inode_open(ctx->vol, INODE(parent)); |
2152 | if (!dir_ni) { |
2153 | res = -errno; |
2154 | goto exit; |
2155 | } |
2156 | /* Generate unicode filename. */ |
2157 | uname_len = ntfs_mbstoucs(name, &uname); |
2158 | if (uname_len < 0) { |
2159 | res = -errno; |
2160 | goto exit; |
2161 | } |
2162 | /* Open object for delete. */ |
2163 | iref = ntfs_inode_lookup_by_mbsname(dir_ni, name); |
2164 | if (iref == (u64)-1) { |
2165 | res = -errno; |
2166 | goto exit; |
2167 | } |
2168 | ino = (fuse_ino_t)MREF(iref); |
2169 | /* deny unlinking metadata files */ |
2170 | if (ino < FILE_first_user) { |
2171 | res = -EPERM; |
2172 | goto exit; |
2173 | } |
2174 | |
2175 | ni = ntfs_inode_open(ctx->vol, ino); |
2176 | if (!ni) { |
2177 | res = -errno; |
2178 | goto exit; |
2179 | } |
2180 | |
2181 | #if defined(__sun) && defined (__SVR4) |
2182 | /* on Solaris : deny unlinking directories */ |
2183 | if (rm_type |
2184 | == (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? RM_LINK : RM_DIR)) { |
2185 | errno = EPERM; |
2186 | res = -errno; |
2187 | goto exit; |
2188 | } |
2189 | #endif /* defined(__sun) && defined (__SVR4) */ |
2190 | |
2191 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2192 | /* JPA deny unlinking if directory is not writable and executable */ |
2193 | if (ntfs_fuse_fill_security_context(req, &security) |
2194 | && !ntfs_allowed_dir_access(&security, dir_ni, ino, ni, |
2195 | S_IEXEC + S_IWRITE + S_ISVTX)) { |
2196 | errno = EACCES; |
2197 | res = -errno; |
2198 | goto exit; |
2199 | } |
2200 | #endif |
2201 | /* |
2202 | * We keep one open_file record per opening, to avoid |
2203 | * having to check the list of open files when opening |
2204 | * and closing (which are more frequent than unlinking). |
2205 | * As a consequence, we may have to create several |
2206 | * ghosts names for the same file. |
2207 | * The file may have been opened with a different name |
2208 | * in a different parent directory. The ghost is |
2209 | * nevertheless created in the parent directory of the |
2210 | * name being unlinked, and permissions to do so are the |
2211 | * same as required for unlinking. |
2212 | */ |
2213 | for (of=ctx->open_files; of; of = of->next) { |
2214 | if ((of->ino == ino) && !(of->state & CLOSE_GHOST)) { |
2215 | /* file was open, create a ghost in unlink parent */ |
2216 | ntfs_inode *gni; |
2217 | u64 gref; |
2218 | |
2219 | /* ni has to be closed for linking ghost */ |
2220 | if (ni) { |
2221 | if (ntfs_inode_close(ni)) { |
2222 | res = -errno; |
2223 | goto exit; |
2224 | } |
2225 | ni = (ntfs_inode*)NULL; |
2226 | } |
2227 | of->state |= CLOSE_GHOST; |
2228 | of->parent = parent; |
2229 | of->ghost = ++ctx->latest_ghost; |
2230 | sprintf(ghostname,ghostformat,of->ghost); |
2231 | /* Generate unicode filename. */ |
2232 | ugname = (ntfschar*)NULL; |
2233 | ugname_len = ntfs_mbstoucs(ghostname, &ugname); |
2234 | if (ugname_len < 0) { |
2235 | res = -errno; |
2236 | goto exit; |
2237 | } |
2238 | /* sweep existing ghost if any, ignoring errors */ |
2239 | gref = ntfs_inode_lookup_by_mbsname(dir_ni, ghostname); |
2240 | if (gref != (u64)-1) { |
2241 | gni = ntfs_inode_open(ctx->vol, MREF(gref)); |
2242 | ntfs_delete(ctx->vol, (char*)NULL, gni, dir_ni, |
2243 | ugname, ugname_len); |
2244 | /* ntfs_delete() always closes gni and dir_ni */ |
2245 | dir_ni = (ntfs_inode*)NULL; |
2246 | } else { |
2247 | if (ntfs_inode_close(dir_ni)) { |
2248 | res = -errno; |
2249 | goto out; |
2250 | } |
2251 | dir_ni = (ntfs_inode*)NULL; |
2252 | } |
2253 | free(ugname); |
2254 | res = ntfs_fuse_newlink(req, of->ino, parent, ghostname, |
2255 | (struct fuse_entry_param*)NULL); |
2256 | if (res) |
2257 | goto out; |
2258 | /* now reopen then parent directory */ |
2259 | dir_ni = ntfs_inode_open(ctx->vol, INODE(parent)); |
2260 | if (!dir_ni) { |
2261 | res = -errno; |
2262 | goto exit; |
2263 | } |
2264 | } |
2265 | } |
2266 | if (!ni) { |
2267 | ni = ntfs_inode_open(ctx->vol, ino); |
2268 | if (!ni) { |
2269 | res = -errno; |
2270 | goto exit; |
2271 | } |
2272 | } |
2273 | if (ntfs_delete(ctx->vol, (char*)NULL, ni, dir_ni, |
2274 | uname, uname_len)) |
2275 | res = -errno; |
2276 | /* ntfs_delete() always closes ni and dir_ni */ |
2277 | ni = dir_ni = NULL; |
2278 | exit: |
2279 | if (ntfs_inode_close(ni) && !res) |
2280 | res = -errno; |
2281 | if (ntfs_inode_close(dir_ni) && !res) |
2282 | res = -errno; |
2283 | out : |
2284 | free(uname); |
2285 | return res; |
2286 | } |
2287 | |
2288 | static void ntfs_fuse_unlink(fuse_req_t req, fuse_ino_t parent, |
2289 | const char *name) |
2290 | { |
2291 | int res; |
2292 | |
2293 | res = ntfs_fuse_rm(req, parent, name, RM_LINK); |
2294 | if (res) |
2295 | fuse_reply_err(req, -res); |
2296 | else |
2297 | fuse_reply_err(req, 0); |
2298 | } |
2299 | |
2300 | static int ntfs_fuse_safe_rename(fuse_req_t req, fuse_ino_t ino, |
2301 | fuse_ino_t parent, const char *name, fuse_ino_t xino, |
2302 | fuse_ino_t newparent, const char *newname, |
2303 | const char *tmp) |
2304 | { |
2305 | int ret; |
2306 | |
2307 | ntfs_log_trace("Entering\n"); |
2308 | |
2309 | ret = ntfs_fuse_newlink(req, xino, newparent, tmp, |
2310 | (struct fuse_entry_param*)NULL); |
2311 | if (ret) |
2312 | return ret; |
2313 | |
2314 | ret = ntfs_fuse_rm(req, newparent, newname, RM_ANY); |
2315 | if (!ret) { |
2316 | |
2317 | ret = ntfs_fuse_newlink(req, ino, newparent, newname, |
2318 | (struct fuse_entry_param*)NULL); |
2319 | if (ret) |
2320 | goto restore; |
2321 | |
2322 | ret = ntfs_fuse_rm(req, parent, name, RM_ANY); |
2323 | if (ret) { |
2324 | if (ntfs_fuse_rm(req, newparent, newname, RM_ANY)) |
2325 | goto err; |
2326 | goto restore; |
2327 | } |
2328 | } |
2329 | |
2330 | goto cleanup; |
2331 | restore: |
2332 | if (ntfs_fuse_newlink(req, xino, newparent, newname, |
2333 | (struct fuse_entry_param*)NULL)) { |
2334 | err: |
2335 | ntfs_log_perror("Rename failed. Existing file '%s' was renamed " |
2336 | "to '%s'", newname, tmp); |
2337 | } else { |
2338 | cleanup: |
2339 | /* |
2340 | * Condition for this unlink has already been checked in |
2341 | * "ntfs_fuse_rename_existing_dest()", so it should never |
2342 | * fail (unless concurrent access to directories when fuse |
2343 | * is multithreaded) |
2344 | */ |
2345 | if (ntfs_fuse_rm(req, newparent, tmp, RM_ANY) < 0) |
2346 | ntfs_log_perror("Rename failed. Existing file '%s' still present " |
2347 | "as '%s'", newname, tmp); |
2348 | } |
2349 | return ret; |
2350 | } |
2351 | |
2352 | static int ntfs_fuse_rename_existing_dest(fuse_req_t req, fuse_ino_t ino, |
2353 | fuse_ino_t parent, const char *name, |
2354 | fuse_ino_t xino, fuse_ino_t newparent, |
2355 | const char *newname) |
2356 | { |
2357 | int ret, len; |
2358 | char *tmp; |
2359 | const char *ext = ".ntfs-3g-"; |
2360 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2361 | ntfs_inode *newdir_ni; |
2362 | struct SECURITY_CONTEXT security; |
2363 | #endif |
2364 | |
2365 | ntfs_log_trace("Entering\n"); |
2366 | |
2367 | len = strlen(newname) + strlen(ext) + 10 + 1; /* wc(str(2^32)) + \0 */ |
2368 | tmp = (char*)ntfs_malloc(len); |
2369 | if (!tmp) |
2370 | return -errno; |
2371 | |
2372 | ret = snprintf(tmp, len, "%s%s%010d", newname, ext, ++ntfs_sequence); |
2373 | if (ret != len - 1) { |
2374 | ntfs_log_error("snprintf failed: %d != %d\n", ret, len - 1); |
2375 | ret = -EOVERFLOW; |
2376 | } else { |
2377 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2378 | /* |
2379 | * Make sure existing dest can be removed. |
2380 | * This is only needed if parent directory is |
2381 | * sticky, because in this situation condition |
2382 | * for unlinking is different from condition for |
2383 | * linking |
2384 | */ |
2385 | newdir_ni = ntfs_inode_open(ctx->vol, INODE(newparent)); |
2386 | if (newdir_ni) { |
2387 | if (!ntfs_fuse_fill_security_context(req,&security) |
2388 | || ntfs_allowed_dir_access(&security, newdir_ni, |
2389 | xino, (ntfs_inode*)NULL, |
2390 | S_IEXEC + S_IWRITE + S_ISVTX)) { |
2391 | if (ntfs_inode_close(newdir_ni)) |
2392 | ret = -errno; |
2393 | else |
2394 | ret = ntfs_fuse_safe_rename(req, ino, |
2395 | parent, name, xino, |
2396 | newparent, newname, |
2397 | tmp); |
2398 | } else { |
2399 | ntfs_inode_close(newdir_ni); |
2400 | ret = -EACCES; |
2401 | } |
2402 | } else |
2403 | ret = -errno; |
2404 | #else |
2405 | ret = ntfs_fuse_safe_rename(req, ino, parent, name, |
2406 | xino, newparent, newname, tmp); |
2407 | #endif |
2408 | } |
2409 | free(tmp); |
2410 | return ret; |
2411 | } |
2412 | |
2413 | static void ntfs_fuse_rename(fuse_req_t req, fuse_ino_t parent, |
2414 | const char *name, fuse_ino_t newparent, |
2415 | const char *newname) |
2416 | { |
2417 | int ret; |
2418 | fuse_ino_t ino; |
2419 | fuse_ino_t xino; |
2420 | ntfs_inode *ni; |
2421 | |
2422 | ntfs_log_debug("rename: old: '%s' new: '%s'\n", name, newname); |
2423 | |
2424 | /* |
2425 | * FIXME: Rename should be atomic. |
2426 | */ |
2427 | |
2428 | ino = ntfs_fuse_inode_lookup(parent, name); |
2429 | if (ino == (fuse_ino_t)-1) { |
2430 | ret = -errno; |
2431 | goto out; |
2432 | } |
2433 | /* Check whether target is present */ |
2434 | xino = ntfs_fuse_inode_lookup(newparent, newname); |
2435 | if (xino != (fuse_ino_t)-1) { |
2436 | /* |
2437 | * Target exists : no need to check whether it |
2438 | * designates the same inode, this has already |
2439 | * been checked (by fuse ?) |
2440 | */ |
2441 | ni = ntfs_inode_open(ctx->vol, INODE(xino)); |
2442 | if (!ni) |
2443 | ret = -errno; |
2444 | else { |
2445 | ret = ntfs_check_empty_dir(ni); |
2446 | if (ret < 0) { |
2447 | ret = -errno; |
2448 | ntfs_inode_close(ni); |
2449 | goto out; |
2450 | } |
2451 | |
2452 | if (ntfs_inode_close(ni)) { |
2453 | set_fuse_error(&ret); |
2454 | goto out; |
2455 | } |
2456 | ret = ntfs_fuse_rename_existing_dest(req, ino, parent, |
2457 | name, xino, newparent, newname); |
2458 | } |
2459 | } else { |
2460 | /* target does not exist */ |
2461 | ret = ntfs_fuse_newlink(req, ino, newparent, newname, |
2462 | (struct fuse_entry_param*)NULL); |
2463 | if (ret) |
2464 | goto out; |
2465 | |
2466 | ret = ntfs_fuse_rm(req, parent, name, RM_ANY); |
2467 | if (ret) |
2468 | ntfs_fuse_rm(req, newparent, newname, RM_ANY); |
2469 | } |
2470 | out: |
2471 | if (ret) |
2472 | fuse_reply_err(req, -ret); |
2473 | else |
2474 | fuse_reply_err(req, 0); |
2475 | } |
2476 | |
2477 | static void ntfs_fuse_release(fuse_req_t req, fuse_ino_t ino, |
2478 | struct fuse_file_info *fi) |
2479 | { |
2480 | ntfs_inode *ni = NULL; |
2481 | ntfs_attr *na = NULL; |
2482 | struct open_file *of; |
2483 | char ghostname[GHOSTLTH]; |
2484 | int res; |
2485 | |
2486 | of = (struct open_file*)(long)fi->fh; |
2487 | /* Only for marked descriptors there is something to do */ |
2488 | if (!of |
2489 | || !(of->state & (CLOSE_COMPRESSED |
2490 | | CLOSE_ENCRYPTED | CLOSE_DMTIME))) { |
2491 | res = 0; |
2492 | goto out; |
2493 | } |
2494 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
2495 | if (!ni) { |
2496 | res = -errno; |
2497 | goto exit; |
2498 | } |
2499 | na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); |
2500 | if (!na) { |
2501 | res = -errno; |
2502 | goto exit; |
2503 | } |
2504 | res = 0; |
2505 | if (of->state & CLOSE_DMTIME) |
2506 | ntfs_inode_update_times(ni,NTFS_UPDATE_MCTIME); |
2507 | if (of->state & CLOSE_COMPRESSED) |
2508 | res = ntfs_attr_pclose(na); |
2509 | #ifdef HAVE_SETXATTR /* extended attributes interface required */ |
2510 | if (of->state & CLOSE_ENCRYPTED) |
2511 | res = ntfs_efs_fixup_attribute(NULL, na); |
2512 | #endif /* HAVE_SETXATTR */ |
2513 | exit: |
2514 | if (na) |
2515 | ntfs_attr_close(na); |
2516 | if (ntfs_inode_close(ni)) |
2517 | set_fuse_error(&res); |
2518 | out: |
2519 | /* remove the associate ghost file (even if release failed) */ |
2520 | if (of) { |
2521 | if (of->state & CLOSE_GHOST) { |
2522 | sprintf(ghostname,ghostformat,of->ghost); |
2523 | ntfs_fuse_rm(req, of->parent, ghostname, RM_ANY); |
2524 | } |
2525 | /* remove from open files list */ |
2526 | if (of->next) |
2527 | of->next->previous = of->previous; |
2528 | if (of->previous) |
2529 | of->previous->next = of->next; |
2530 | else |
2531 | ctx->open_files = of->next; |
2532 | free(of); |
2533 | } |
2534 | if (res) |
2535 | fuse_reply_err(req, -res); |
2536 | else |
2537 | fuse_reply_err(req, 0); |
2538 | } |
2539 | |
2540 | static void ntfs_fuse_mkdir(fuse_req_t req, fuse_ino_t parent, |
2541 | const char *name, mode_t mode) |
2542 | { |
2543 | int res; |
2544 | struct fuse_entry_param entry; |
2545 | |
2546 | res = ntfs_fuse_create(req, parent, name, S_IFDIR | (mode & 07777), |
2547 | 0, &entry, (char*)NULL, (struct fuse_file_info*)NULL); |
2548 | if (res < 0) |
2549 | fuse_reply_err(req, -res); |
2550 | else |
2551 | fuse_reply_entry(req, &entry); |
2552 | } |
2553 | |
2554 | static void ntfs_fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) |
2555 | { |
2556 | int res; |
2557 | |
2558 | res = ntfs_fuse_rm(req, parent, name, RM_DIR); |
2559 | if (res) |
2560 | fuse_reply_err(req, -res); |
2561 | else |
2562 | fuse_reply_err(req, 0); |
2563 | } |
2564 | |
2565 | static void ntfs_fuse_fsync(fuse_req_t req, |
2566 | fuse_ino_t ino __attribute__((unused)), |
2567 | int type __attribute__((unused)), |
2568 | struct fuse_file_info *fi __attribute__((unused))) |
2569 | { |
2570 | /* sync the full device */ |
2571 | if (ntfs_device_sync(ctx->vol->dev)) |
2572 | fuse_reply_err(req, errno); |
2573 | else |
2574 | fuse_reply_err(req, 0); |
2575 | } |
2576 | |
2577 | static void ntfs_fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, |
2578 | uint64_t vidx) |
2579 | { |
2580 | ntfs_inode *ni; |
2581 | ntfs_attr *na; |
2582 | LCN lcn; |
2583 | uint64_t lidx = 0; |
2584 | int ret = 0; |
2585 | int cl_per_bl = ctx->vol->cluster_size / blocksize; |
2586 | |
2587 | if (blocksize > ctx->vol->cluster_size) { |
2588 | ret = -EINVAL; |
2589 | goto done; |
2590 | } |
2591 | |
2592 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
2593 | if (!ni) { |
2594 | ret = -errno; |
2595 | goto done; |
2596 | } |
2597 | |
2598 | na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); |
2599 | if (!na) { |
2600 | ret = -errno; |
2601 | goto close_inode; |
2602 | } |
2603 | |
2604 | if ((na->data_flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED)) |
2605 | || !NAttrNonResident(na)) { |
2606 | ret = -EINVAL; |
2607 | goto close_attr; |
2608 | } |
2609 | |
2610 | if (ntfs_attr_map_whole_runlist(na)) { |
2611 | ret = -errno; |
2612 | goto close_attr; |
2613 | } |
2614 | |
2615 | lcn = ntfs_rl_vcn_to_lcn(na->rl, vidx / cl_per_bl); |
2616 | lidx = (lcn > 0) ? lcn * cl_per_bl + vidx % cl_per_bl : 0; |
2617 | |
2618 | close_attr: |
2619 | ntfs_attr_close(na); |
2620 | close_inode: |
2621 | if (ntfs_inode_close(ni)) |
2622 | set_fuse_error(&ret); |
2623 | done : |
2624 | if (ret < 0) |
2625 | fuse_reply_err(req, -ret); |
2626 | else |
2627 | fuse_reply_bmap(req, lidx); |
2628 | } |
2629 | |
2630 | #ifdef HAVE_SETXATTR |
2631 | |
2632 | /* |
2633 | * Name space identifications and prefixes |
2634 | */ |
2635 | |
2636 | enum { |
2637 | XATTRNS_NONE, |
2638 | XATTRNS_USER, |
2639 | XATTRNS_SYSTEM, |
2640 | XATTRNS_SECURITY, |
2641 | XATTRNS_TRUSTED, |
2642 | XATTRNS_OPEN |
2643 | } ; |
2644 | |
2645 | /* |
2646 | * Check whether access to internal data as an extended |
2647 | * attribute in system name space is allowed |
2648 | * |
2649 | * Returns pointer to inode if allowed, |
2650 | * NULL and errno set if not allowed |
2651 | */ |
2652 | |
2653 | static ntfs_inode *ntfs_check_access_xattr(fuse_req_t req, |
2654 | struct SECURITY_CONTEXT *security, |
2655 | fuse_ino_t ino, int attr, BOOL setting) |
2656 | { |
2657 | ntfs_inode *dir_ni; |
2658 | ntfs_inode *ni; |
2659 | BOOL foracl; |
2660 | BOOL bad; |
2661 | mode_t acctype; |
2662 | |
2663 | ni = (ntfs_inode*)NULL; |
2664 | foracl = (attr == XATTR_POSIX_ACC) |
2665 | || (attr == XATTR_POSIX_DEF); |
2666 | /* |
2667 | * When accessing Posix ACL, return unsupported if ACL |
2668 | * were disabled or no user mapping has been defined. |
2669 | * However no error will be returned to getfacl |
2670 | */ |
2671 | if ((!ntfs_fuse_fill_security_context(req, security) |
2672 | || (ctx->secure_flags |
2673 | & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_RAW)))) |
2674 | && foracl) { |
2675 | errno = EOPNOTSUPP; |
2676 | } else { |
2677 | /* |
2678 | * parent directory must be executable, and |
2679 | * for setting a DOS name it must be writeable |
2680 | */ |
2681 | if (setting && (attr == XATTR_NTFS_DOS_NAME)) |
2682 | acctype = S_IEXEC | S_IWRITE; |
2683 | else |
2684 | acctype = S_IEXEC; |
2685 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
2686 | /* basic access was checked previously in a lookup */ |
2687 | if (ni && (acctype != S_IEXEC)) { |
2688 | bad = FALSE; |
2689 | /* do not reopen root */ |
2690 | if (ni->mft_no == FILE_root) { |
2691 | /* forbid getting/setting names on root */ |
2692 | if ((attr == XATTR_NTFS_DOS_NAME) |
2693 | || !ntfs_real_allowed_access(security, |
2694 | ni, acctype)) |
2695 | bad = TRUE; |
2696 | } else { |
2697 | dir_ni = ntfs_dir_parent_inode(ni); |
2698 | if (dir_ni) { |
2699 | if (!ntfs_real_allowed_access(security, |
2700 | dir_ni, acctype)) |
2701 | bad = TRUE; |
2702 | if (ntfs_inode_close(dir_ni)) |
2703 | bad = TRUE; |
2704 | } else |
2705 | bad = TRUE; |
2706 | } |
2707 | if (bad) { |
2708 | ntfs_inode_close(ni); |
2709 | ni = (ntfs_inode*)NULL; |
2710 | } |
2711 | } |
2712 | } |
2713 | return (ni); |
2714 | } |
2715 | |
2716 | /* |
2717 | * Determine the name space of an extended attribute |
2718 | */ |
2719 | |
2720 | static int xattr_namespace(const char *name) |
2721 | { |
2722 | int namespace; |
2723 | |
2724 | if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) { |
2725 | namespace = XATTRNS_NONE; |
2726 | if (!strncmp(name, nf_ns_user_prefix, |
2727 | nf_ns_user_prefix_len) |
2728 | && (strlen(name) != (size_t)nf_ns_user_prefix_len)) |
2729 | namespace = XATTRNS_USER; |
2730 | else if (!strncmp(name, nf_ns_system_prefix, |
2731 | nf_ns_system_prefix_len) |
2732 | && (strlen(name) != (size_t)nf_ns_system_prefix_len)) |
2733 | namespace = XATTRNS_SYSTEM; |
2734 | else if (!strncmp(name, nf_ns_security_prefix, |
2735 | nf_ns_security_prefix_len) |
2736 | && (strlen(name) != (size_t)nf_ns_security_prefix_len)) |
2737 | namespace = XATTRNS_SECURITY; |
2738 | else if (!strncmp(name, nf_ns_trusted_prefix, |
2739 | nf_ns_trusted_prefix_len) |
2740 | && (strlen(name) != (size_t)nf_ns_trusted_prefix_len)) |
2741 | namespace = XATTRNS_TRUSTED; |
2742 | } else |
2743 | namespace = XATTRNS_OPEN; |
2744 | return (namespace); |
2745 | } |
2746 | |
2747 | /* |
2748 | * Fix the prefix of an extended attribute |
2749 | */ |
2750 | |
2751 | static int fix_xattr_prefix(const char *name, int namespace, ntfschar **lename) |
2752 | { |
2753 | int len; |
2754 | char *prefixed; |
2755 | |
2756 | *lename = (ntfschar*)NULL; |
2757 | switch (namespace) { |
2758 | case XATTRNS_USER : |
2759 | /* |
2760 | * user name space : remove user prefix |
2761 | */ |
2762 | len = ntfs_mbstoucs(name + nf_ns_user_prefix_len, lename); |
2763 | break; |
2764 | case XATTRNS_SYSTEM : |
2765 | case XATTRNS_SECURITY : |
2766 | case XATTRNS_TRUSTED : |
2767 | /* |
2768 | * security, trusted and unmapped system name spaces : |
2769 | * insert ntfs-3g prefix |
2770 | */ |
2771 | prefixed = (char*)ntfs_malloc(strlen(xattr_ntfs_3g) |
2772 | + strlen(name) + 1); |
2773 | if (prefixed) { |
2774 | strcpy(prefixed,xattr_ntfs_3g); |
2775 | strcat(prefixed,name); |
2776 | len = ntfs_mbstoucs(prefixed, lename); |
2777 | free(prefixed); |
2778 | } else |
2779 | len = -1; |
2780 | break; |
2781 | case XATTRNS_OPEN : |
2782 | /* |
2783 | * in open name space mode : do no fix prefix |
2784 | */ |
2785 | len = ntfs_mbstoucs(name, lename); |
2786 | break; |
2787 | default : |
2788 | len = -1; |
2789 | } |
2790 | return (len); |
2791 | } |
2792 | |
2793 | static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) |
2794 | { |
2795 | ntfs_attr_search_ctx *actx = NULL; |
2796 | ntfs_inode *ni; |
2797 | char *list = (char*)NULL; |
2798 | int ret = 0; |
2799 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2800 | struct SECURITY_CONTEXT security; |
2801 | #endif |
2802 | |
2803 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2804 | ntfs_fuse_fill_security_context(req, &security); |
2805 | #endif |
2806 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
2807 | if (!ni) { |
2808 | ret = -errno; |
2809 | goto out; |
2810 | } |
2811 | /* Return with no result for symlinks, fifo, etc. */ |
2812 | if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) |
2813 | goto exit; |
2814 | /* otherwise file must be readable */ |
2815 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2816 | if (!ntfs_allowed_access(&security,ni,S_IREAD)) { |
2817 | ret = -EACCES; |
2818 | goto exit; |
2819 | } |
2820 | #endif |
2821 | actx = ntfs_attr_get_search_ctx(ni, NULL); |
2822 | if (!actx) { |
2823 | ret = -errno; |
2824 | goto exit; |
2825 | } |
2826 | if (size) { |
2827 | list = (char*)malloc(size); |
2828 | if (!list) { |
2829 | ret = -errno; |
2830 | goto exit; |
2831 | } |
2832 | } |
2833 | |
2834 | if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR) |
2835 | || (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) { |
2836 | ret = ntfs_fuse_listxattr_common(ni, actx, list, size, |
2837 | ctx->streams == NF_STREAMS_INTERFACE_XATTR); |
2838 | if (ret < 0) |
2839 | goto exit; |
2840 | } |
2841 | if (errno != ENOENT) |
2842 | ret = -errno; |
2843 | exit: |
2844 | if (actx) |
2845 | ntfs_attr_put_search_ctx(actx); |
2846 | if (ntfs_inode_close(ni)) |
2847 | set_fuse_error(&ret); |
2848 | out : |
2849 | if (ret < 0) |
2850 | fuse_reply_err(req, -ret); |
2851 | else |
2852 | if (size) |
2853 | fuse_reply_buf(req, list, ret); |
2854 | else |
2855 | fuse_reply_xattr(req, ret); |
2856 | free(list); |
2857 | } |
2858 | |
2859 | static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, |
2860 | size_t size) |
2861 | { |
2862 | ntfs_inode *ni; |
2863 | ntfs_inode *dir_ni; |
2864 | ntfs_attr *na = NULL; |
2865 | char *value = (char*)NULL; |
2866 | ntfschar *lename = (ntfschar*)NULL; |
2867 | int lename_len; |
2868 | int res; |
2869 | s64 rsize; |
2870 | enum SYSTEMXATTRS attr; |
2871 | int namespace; |
2872 | struct SECURITY_CONTEXT security; |
2873 | |
2874 | attr = ntfs_xattr_system_type(name,ctx->vol); |
2875 | if (attr != XATTR_UNMAPPED) { |
2876 | /* |
2877 | * hijack internal data and ACL retrieval, whatever |
2878 | * mode was selected for xattr (from the user's |
2879 | * point of view, ACLs are not xattr) |
2880 | */ |
2881 | if (size) |
2882 | value = (char*)ntfs_malloc(size); |
2883 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2884 | if (!size || value) { |
2885 | ni = ntfs_check_access_xattr(req, &security, ino, |
2886 | attr, FALSE); |
2887 | if (ni) { |
2888 | if (ntfs_allowed_access(&security,ni,S_IREAD)) { |
2889 | if (attr == XATTR_NTFS_DOS_NAME) |
2890 | dir_ni = ntfs_dir_parent_inode(ni); |
2891 | else |
2892 | dir_ni = (ntfs_inode*)NULL; |
2893 | res = ntfs_xattr_system_getxattr(&security, |
2894 | attr, ni, dir_ni, value, size); |
2895 | if (dir_ni && ntfs_inode_close(dir_ni)) |
2896 | set_fuse_error(&res); |
2897 | } else |
2898 | res = -errno; |
2899 | if (ntfs_inode_close(ni)) |
2900 | set_fuse_error(&res); |
2901 | } else |
2902 | res = -errno; |
2903 | } |
2904 | #else |
2905 | /* |
2906 | * Standard access control has been done by fuse/kernel |
2907 | */ |
2908 | if (!size || value) { |
2909 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
2910 | if (ni) { |
2911 | /* user mapping not mandatory */ |
2912 | ntfs_fuse_fill_security_context(req, &security); |
2913 | if (attr == XATTR_NTFS_DOS_NAME) |
2914 | dir_ni = ntfs_dir_parent_inode(ni); |
2915 | else |
2916 | dir_ni = (ntfs_inode*)NULL; |
2917 | res = ntfs_xattr_system_getxattr(&security, |
2918 | attr, ni, dir_ni, value, size); |
2919 | if (dir_ni && ntfs_inode_close(dir_ni)) |
2920 | set_fuse_error(&res); |
2921 | if (ntfs_inode_close(ni)) |
2922 | set_fuse_error(&res); |
2923 | } else |
2924 | res = -errno; |
2925 | } else |
2926 | res = -errno; |
2927 | #endif |
2928 | if (res < 0) |
2929 | fuse_reply_err(req, -res); |
2930 | else |
2931 | if (size) |
2932 | fuse_reply_buf(req, value, res); |
2933 | else |
2934 | fuse_reply_xattr(req, res); |
2935 | free(value); |
2936 | return; |
2937 | } |
2938 | if (ctx->streams == NF_STREAMS_INTERFACE_NONE) { |
2939 | res = -EOPNOTSUPP; |
2940 | goto out; |
2941 | } |
2942 | namespace = xattr_namespace(name); |
2943 | if (namespace == XATTRNS_NONE) { |
2944 | res = -EOPNOTSUPP; |
2945 | goto out; |
2946 | } |
2947 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2948 | ntfs_fuse_fill_security_context(req,&security); |
2949 | /* trusted only readable by root */ |
2950 | if ((namespace == XATTRNS_TRUSTED) |
2951 | && security.uid) { |
2952 | res = -ENODATA; |
2953 | goto out; |
2954 | } |
2955 | #endif |
2956 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
2957 | if (!ni) { |
2958 | res = -errno; |
2959 | goto out; |
2960 | } |
2961 | /* Return with no result for symlinks, fifo, etc. */ |
2962 | if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { |
2963 | res = -ENODATA; |
2964 | goto exit; |
2965 | } |
2966 | /* otherwise file must be readable */ |
2967 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
2968 | if (!ntfs_allowed_access(&security, ni, S_IREAD)) { |
2969 | res = -errno; |
2970 | goto exit; |
2971 | } |
2972 | #endif |
2973 | lename_len = fix_xattr_prefix(name, namespace, &lename); |
2974 | if (lename_len == -1) { |
2975 | res = -errno; |
2976 | goto exit; |
2977 | } |
2978 | na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); |
2979 | if (!na) { |
2980 | res = -ENODATA; |
2981 | goto exit; |
2982 | } |
2983 | rsize = na->data_size; |
2984 | if (ctx->efs_raw |
2985 | && rsize |
2986 | && (na->data_flags & ATTR_IS_ENCRYPTED) |
2987 | && NAttrNonResident(na)) |
2988 | rsize = ((na->data_size + 511) & ~511) + 2; |
2989 | if (size) { |
2990 | if (size >= (size_t)rsize) { |
2991 | value = (char*)ntfs_malloc(rsize); |
2992 | if (value) |
2993 | res = ntfs_attr_pread(na, 0, rsize, value); |
2994 | if (!value || (res != rsize)) |
2995 | res = -errno; |
2996 | } else |
2997 | res = -ERANGE; |
2998 | } else |
2999 | res = rsize; |
3000 | exit: |
3001 | if (na) |
3002 | ntfs_attr_close(na); |
3003 | free(lename); |
3004 | if (ntfs_inode_close(ni)) |
3005 | set_fuse_error(&res); |
3006 | |
3007 | out : |
3008 | if (res < 0) |
3009 | fuse_reply_err(req, -res); |
3010 | else |
3011 | if (size) |
3012 | fuse_reply_buf(req, value, res); |
3013 | else |
3014 | fuse_reply_xattr(req, res); |
3015 | free(value); |
3016 | } |
3017 | |
3018 | static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, |
3019 | const char *value, size_t size, int flags) |
3020 | { |
3021 | ntfs_inode *ni; |
3022 | ntfs_inode *dir_ni; |
3023 | ntfs_attr *na = NULL; |
3024 | ntfschar *lename = NULL; |
3025 | int res, lename_len; |
3026 | size_t total; |
3027 | s64 part; |
3028 | enum SYSTEMXATTRS attr; |
3029 | int namespace; |
3030 | struct SECURITY_CONTEXT security; |
3031 | |
3032 | attr = ntfs_xattr_system_type(name,ctx->vol); |
3033 | if (attr != XATTR_UNMAPPED) { |
3034 | /* |
3035 | * hijack internal data and ACL setting, whatever |
3036 | * mode was selected for xattr (from the user's |
3037 | * point of view, ACLs are not xattr) |
3038 | * Note : updating an ACL does not set ctime |
3039 | */ |
3040 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
3041 | ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE); |
3042 | if (ni) { |
3043 | if (ntfs_allowed_as_owner(&security, ni)) { |
3044 | if (attr == XATTR_NTFS_DOS_NAME) |
3045 | dir_ni = ntfs_dir_parent_inode(ni); |
3046 | else |
3047 | dir_ni = (ntfs_inode*)NULL; |
3048 | res = ntfs_xattr_system_setxattr(&security, |
3049 | attr, ni, dir_ni, value, size, flags); |
3050 | /* never have to close dir_ni */ |
3051 | if (res) |
3052 | res = -errno; |
3053 | } else |
3054 | res = -errno; |
3055 | if ((attr != XATTR_NTFS_DOS_NAME) |
3056 | && ntfs_inode_close(ni)) |
3057 | set_fuse_error(&res); |
3058 | } else |
3059 | res = -errno; |
3060 | #else |
3061 | /* creation of a new name is not controlled by fuse */ |
3062 | if (attr == XATTR_NTFS_DOS_NAME) |
3063 | ni = ntfs_check_access_xattr(req, &security, |
3064 | ino, attr, TRUE); |
3065 | else |
3066 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
3067 | if (ni) { |
3068 | /* |
3069 | * user mapping is not mandatory |
3070 | * if defined, only owner is allowed |
3071 | */ |
3072 | if (!ntfs_fuse_fill_security_context(req, &security) |
3073 | || ntfs_allowed_as_owner(&security, ni)) { |
3074 | if (attr == XATTR_NTFS_DOS_NAME) |
3075 | dir_ni = ntfs_dir_parent_inode(ni); |
3076 | else |
3077 | dir_ni = (ntfs_inode*)NULL; |
3078 | res = ntfs_xattr_system_setxattr(&security, |
3079 | attr, ni, dir_ni, value, size, flags); |
3080 | /* never have to close dir_ni */ |
3081 | if (res) |
3082 | res = -errno; |
3083 | } else |
3084 | res = -errno; |
3085 | if ((attr != XATTR_NTFS_DOS_NAME) |
3086 | && ntfs_inode_close(ni)) |
3087 | set_fuse_error(&res); |
3088 | } else |
3089 | res = -errno; |
3090 | #endif |
3091 | #if CACHEING && !defined(FUSE_INTERNAL) |
3092 | /* |
3093 | * Most of system xattr settings cause changes to some |
3094 | * file attribute (st_mode, st_nlink, st_mtime, etc.), |
3095 | * so we must invalidate cached data when cacheing is |
3096 | * in use (not possible with internal fuse or external |
3097 | * fuse before 2.8) |
3098 | */ |
3099 | if ((res >= 0) |
3100 | && fuse_lowlevel_notify_inval_inode(ctx->fc, ino, -1, 0)) |
3101 | res = -errno; |
3102 | #endif |
3103 | if (res < 0) |
3104 | fuse_reply_err(req, -res); |
3105 | else |
3106 | fuse_reply_err(req, 0); |
3107 | return; |
3108 | } |
3109 | if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR) |
3110 | && (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR)) { |
3111 | res = -EOPNOTSUPP; |
3112 | goto out; |
3113 | } |
3114 | namespace = xattr_namespace(name); |
3115 | if (namespace == XATTRNS_NONE) { |
3116 | res = -EOPNOTSUPP; |
3117 | goto out; |
3118 | } |
3119 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
3120 | ntfs_fuse_fill_security_context(req,&security); |
3121 | /* security and trusted only settable by root */ |
3122 | if (((namespace == XATTRNS_SECURITY) |
3123 | || (namespace == XATTRNS_TRUSTED)) |
3124 | && security.uid) { |
3125 | res = -EPERM; |
3126 | goto out; |
3127 | } |
3128 | #endif |
3129 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
3130 | if (!ni) { |
3131 | res = -errno; |
3132 | goto out; |
3133 | } |
3134 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
3135 | switch (namespace) { |
3136 | case XATTRNS_SECURITY : |
3137 | case XATTRNS_TRUSTED : |
3138 | if (security.uid) { |
3139 | res = -EPERM; |
3140 | goto exit; |
3141 | } |
3142 | break; |
3143 | case XATTRNS_SYSTEM : |
3144 | if (!ntfs_allowed_as_owner(&security, ni)) { |
3145 | res = -EACCES; |
3146 | goto exit; |
3147 | } |
3148 | break; |
3149 | default : |
3150 | /* User xattr not allowed for symlinks, fifo, etc. */ |
3151 | if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { |
3152 | res = -EPERM; |
3153 | goto exit; |
3154 | } |
3155 | if (!ntfs_allowed_access(&security,ni,S_IWRITE)) { |
3156 | res = -EACCES; |
3157 | goto exit; |
3158 | } |
3159 | break; |
3160 | } |
3161 | #else |
3162 | /* User xattr not allowed for symlinks, fifo, etc. */ |
3163 | if ((namespace == XATTRNS_USER) |
3164 | && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) { |
3165 | res = -EPERM; |
3166 | goto exit; |
3167 | } |
3168 | #endif |
3169 | lename_len = fix_xattr_prefix(name, namespace, &lename); |
3170 | if ((lename_len == -1) |
3171 | || (ctx->windows_names |
3172 | && ntfs_forbidden_chars(lename,lename_len))) { |
3173 | res = -errno; |
3174 | goto exit; |
3175 | } |
3176 | na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); |
3177 | if (na && flags == XATTR_CREATE) { |
3178 | res = -EEXIST; |
3179 | goto exit; |
3180 | } |
3181 | if (!na) { |
3182 | if (flags == XATTR_REPLACE) { |
3183 | res = -ENODATA; |
3184 | goto exit; |
3185 | } |
3186 | if (ntfs_attr_add(ni, AT_DATA, lename, lename_len, NULL, 0)) { |
3187 | res = -errno; |
3188 | goto exit; |
3189 | } |
3190 | if (!(ni->flags & FILE_ATTR_ARCHIVE)) { |
3191 | set_archive(ni); |
3192 | NInoFileNameSetDirty(ni); |
3193 | } |
3194 | na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); |
3195 | if (!na) { |
3196 | res = -errno; |
3197 | goto exit; |
3198 | } |
3199 | } else { |
3200 | /* currently compressed streams can only be wiped out */ |
3201 | if (ntfs_attr_truncate(na, (s64)0 /* size */)) { |
3202 | res = -errno; |
3203 | goto exit; |
3204 | } |
3205 | } |
3206 | total = 0; |
3207 | res = 0; |
3208 | if (size) { |
3209 | do { |
3210 | part = ntfs_attr_pwrite(na, total, size - total, |
3211 | &value[total]); |
3212 | if (part > 0) |
3213 | total += part; |
3214 | } while ((part > 0) && (total < size)); |
3215 | } |
3216 | if ((total != size) || ntfs_attr_pclose(na)) |
3217 | res = -errno; |
3218 | else { |
3219 | if (ctx->efs_raw |
3220 | && (ni->flags & FILE_ATTR_ENCRYPTED)) { |
3221 | if (ntfs_efs_fixup_attribute(NULL,na)) |
3222 | res = -errno; |
3223 | } |
3224 | } |
3225 | if (!res && !(ni->flags & FILE_ATTR_ARCHIVE)) { |
3226 | set_archive(ni); |
3227 | NInoFileNameSetDirty(ni); |
3228 | } |
3229 | exit: |
3230 | if (na) |
3231 | ntfs_attr_close(na); |
3232 | free(lename); |
3233 | if (ntfs_inode_close(ni)) |
3234 | set_fuse_error(&res); |
3235 | out : |
3236 | if (res < 0) |
3237 | fuse_reply_err(req, -res); |
3238 | else |
3239 | fuse_reply_err(req, 0); |
3240 | } |
3241 | |
3242 | static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) |
3243 | { |
3244 | ntfs_inode *ni; |
3245 | ntfs_inode *dir_ni; |
3246 | ntfschar *lename = NULL; |
3247 | int res = 0, lename_len; |
3248 | enum SYSTEMXATTRS attr; |
3249 | int namespace; |
3250 | struct SECURITY_CONTEXT security; |
3251 | |
3252 | attr = ntfs_xattr_system_type(name,ctx->vol); |
3253 | if (attr != XATTR_UNMAPPED) { |
3254 | switch (attr) { |
3255 | /* |
3256 | * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES |
3257 | * is never allowed |
3258 | */ |
3259 | case XATTR_NTFS_ACL : |
3260 | case XATTR_NTFS_ATTRIB : |
3261 | case XATTR_NTFS_ATTRIB_BE : |
3262 | case XATTR_NTFS_EFSINFO : |
3263 | case XATTR_NTFS_TIMES : |
3264 | case XATTR_NTFS_TIMES_BE : |
3265 | case XATTR_NTFS_CRTIME : |
3266 | case XATTR_NTFS_CRTIME_BE : |
3267 | res = -EPERM; |
3268 | break; |
3269 | default : |
3270 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
3271 | ni = ntfs_check_access_xattr(req, &security, ino, |
3272 | attr,TRUE); |
3273 | if (ni) { |
3274 | if (ntfs_allowed_as_owner(&security, ni)) { |
3275 | if (attr == XATTR_NTFS_DOS_NAME) |
3276 | dir_ni = ntfs_dir_parent_inode(ni); |
3277 | else |
3278 | dir_ni = (ntfs_inode*)NULL; |
3279 | res = ntfs_xattr_system_removexattr(&security, |
3280 | attr, ni, dir_ni); |
3281 | if (res) |
3282 | res = -errno; |
3283 | /* never have to close dir_ni */ |
3284 | } else |
3285 | res = -errno; |
3286 | if ((attr != XATTR_NTFS_DOS_NAME) |
3287 | && ntfs_inode_close(ni)) |
3288 | set_fuse_error(&res); |
3289 | } else |
3290 | res = -errno; |
3291 | #else |
3292 | /* creation of a new name is not controlled by fuse */ |
3293 | if (attr == XATTR_NTFS_DOS_NAME) |
3294 | ni = ntfs_check_access_xattr(req, &security, |
3295 | ino, attr, TRUE); |
3296 | else |
3297 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
3298 | if (ni) { |
3299 | /* |
3300 | * user mapping is not mandatory |
3301 | * if defined, only owner is allowed |
3302 | */ |
3303 | if (!ntfs_fuse_fill_security_context(req, &security) |
3304 | || ntfs_allowed_as_owner(&security, ni)) { |
3305 | if (attr == XATTR_NTFS_DOS_NAME) |
3306 | dir_ni = ntfs_dir_parent_inode(ni); |
3307 | else |
3308 | dir_ni = (ntfs_inode*)NULL; |
3309 | res = ntfs_xattr_system_removexattr(&security, |
3310 | attr, ni, dir_ni); |
3311 | /* never have to close dir_ni */ |
3312 | if (res) |
3313 | res = -errno; |
3314 | } else |
3315 | res = -errno; |
3316 | if ((attr != XATTR_NTFS_DOS_NAME) |
3317 | && ntfs_inode_close(ni)) |
3318 | set_fuse_error(&res); |
3319 | } else |
3320 | res = -errno; |
3321 | #endif |
3322 | #if CACHEING && !defined(FUSE_INTERNAL) |
3323 | /* |
3324 | * Some allowed system xattr removals cause changes to |
3325 | * some file attribute (st_mode, st_nlink, etc.), |
3326 | * so we must invalidate cached data when cacheing is |
3327 | * in use (not possible with internal fuse or external |
3328 | * fuse before 2.8) |
3329 | */ |
3330 | if ((res >= 0) |
3331 | && fuse_lowlevel_notify_inval_inode(ctx->fc, |
3332 | ino, -1, 0)) |
3333 | res = -errno; |
3334 | #endif |
3335 | break; |
3336 | } |
3337 | if (res < 0) |
3338 | fuse_reply_err(req, -res); |
3339 | else |
3340 | fuse_reply_err(req, 0); |
3341 | return; |
3342 | } |
3343 | if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR) |
3344 | && (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR)) { |
3345 | res = -EOPNOTSUPP; |
3346 | goto out; |
3347 | } |
3348 | namespace = xattr_namespace(name); |
3349 | if (namespace == XATTRNS_NONE) { |
3350 | res = -EOPNOTSUPP; |
3351 | goto out; |
3352 | } |
3353 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
3354 | ntfs_fuse_fill_security_context(req,&security); |
3355 | /* security and trusted only settable by root */ |
3356 | if (((namespace == XATTRNS_SECURITY) |
3357 | || (namespace == XATTRNS_TRUSTED)) |
3358 | && security.uid) { |
3359 | res = -EACCES; |
3360 | goto out; |
3361 | } |
3362 | #endif |
3363 | ni = ntfs_inode_open(ctx->vol, INODE(ino)); |
3364 | if (!ni) { |
3365 | res = -errno; |
3366 | goto out; |
3367 | } |
3368 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
3369 | switch (namespace) { |
3370 | case XATTRNS_SECURITY : |
3371 | case XATTRNS_TRUSTED : |
3372 | if (security.uid) { |
3373 | res = -EPERM; |
3374 | goto exit; |
3375 | } |
3376 | break; |
3377 | case XATTRNS_SYSTEM : |
3378 | if (!ntfs_allowed_as_owner(&security, ni)) { |
3379 | res = -EACCES; |
3380 | goto exit; |
3381 | } |
3382 | break; |
3383 | default : |
3384 | /* User xattr not allowed for symlinks, fifo, etc. */ |
3385 | if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { |
3386 | res = -EPERM; |
3387 | goto exit; |
3388 | } |
3389 | if (!ntfs_allowed_access(&security,ni,S_IWRITE)) { |
3390 | res = -EACCES; |
3391 | goto exit; |
3392 | } |
3393 | break; |
3394 | } |
3395 | #else |
3396 | /* User xattr not allowed for symlinks, fifo, etc. */ |
3397 | if ((namespace == XATTRNS_USER) |
3398 | && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) { |
3399 | res = -EPERM; |
3400 | goto exit; |
3401 | } |
3402 | #endif |
3403 | lename_len = fix_xattr_prefix(name, namespace, &lename); |
3404 | if (lename_len == -1) { |
3405 | res = -errno; |
3406 | goto exit; |
3407 | } |
3408 | if (ntfs_attr_remove(ni, AT_DATA, lename, lename_len)) { |
3409 | if (errno == ENOENT) |
3410 | errno = ENODATA; |
3411 | res = -errno; |
3412 | } |
3413 | if (!(ni->flags & FILE_ATTR_ARCHIVE)) { |
3414 | set_archive(ni); |
3415 | NInoFileNameSetDirty(ni); |
3416 | } |
3417 | exit: |
3418 | free(lename); |
3419 | if (ntfs_inode_close(ni)) |
3420 | set_fuse_error(&res); |
3421 | out : |
3422 | if (res < 0) |
3423 | fuse_reply_err(req, -res); |
3424 | else |
3425 | fuse_reply_err(req, 0); |
3426 | return; |
3427 | |
3428 | } |
3429 | |
3430 | #else |
3431 | #if POSIXACLS |
3432 | #error "Option inconsistency : POSIXACLS requires SETXATTR" |
3433 | #endif |
3434 | #endif /* HAVE_SETXATTR */ |
3435 | |
3436 | static void ntfs_close(void) |
3437 | { |
3438 | struct SECURITY_CONTEXT security; |
3439 | |
3440 | if (!ctx) |
3441 | return; |
3442 | |
3443 | if (!ctx->vol) |
3444 | return; |
3445 | |
3446 | if (ctx->mounted) { |
3447 | ntfs_log_info("Unmounting %s (%s)\n", opts.device, |
3448 | ctx->vol->vol_name); |
3449 | if (ntfs_fuse_fill_security_context((fuse_req_t)NULL, &security)) { |
3450 | if (ctx->seccache && ctx->seccache->head.p_reads) { |
3451 | ntfs_log_info("Permissions cache : %lu writes, " |
3452 | "%lu reads, %lu.%1lu%% hits\n", |
3453 | ctx->seccache->head.p_writes, |
3454 | ctx->seccache->head.p_reads, |
3455 | 100 * ctx->seccache->head.p_hits |
3456 | / ctx->seccache->head.p_reads, |
3457 | 1000 * ctx->seccache->head.p_hits |
3458 | / ctx->seccache->head.p_reads % 10); |
3459 | } |
3460 | } |
3461 | ntfs_close_secure(&security); |
3462 | } |
3463 | |
3464 | if (ntfs_umount(ctx->vol, FALSE)) |
3465 | ntfs_log_perror("Failed to close volume %s", opts.device); |
3466 | |
3467 | ctx->vol = NULL; |
3468 | } |
3469 | |
3470 | static void ntfs_fuse_destroy2(void *notused __attribute__((unused))) |
3471 | { |
3472 | ntfs_close(); |
3473 | } |
3474 | |
3475 | static struct fuse_lowlevel_ops ntfs_3g_ops = { |
3476 | .lookup = ntfs_fuse_lookup, |
3477 | .getattr = ntfs_fuse_getattr, |
3478 | .readlink = ntfs_fuse_readlink, |
3479 | .opendir = ntfs_fuse_opendir, |
3480 | .readdir = ntfs_fuse_readdir, |
3481 | .releasedir = ntfs_fuse_releasedir, |
3482 | .open = ntfs_fuse_open, |
3483 | .release = ntfs_fuse_release, |
3484 | .read = ntfs_fuse_read, |
3485 | .write = ntfs_fuse_write, |
3486 | .setattr = ntfs_fuse_setattr, |
3487 | #if HAVE_SYS_STATVFS_H |
3488 | .statfs = ntfs_fuse_statfs, |
3489 | #endif |
3490 | .create = ntfs_fuse_create_file, |
3491 | .mknod = ntfs_fuse_mknod, |
3492 | .symlink = ntfs_fuse_symlink, |
3493 | .link = ntfs_fuse_link, |
3494 | .unlink = ntfs_fuse_unlink, |
3495 | .rename = ntfs_fuse_rename, |
3496 | .mkdir = ntfs_fuse_mkdir, |
3497 | .rmdir = ntfs_fuse_rmdir, |
3498 | .fsync = ntfs_fuse_fsync, |
3499 | .fsyncdir = ntfs_fuse_fsync, |
3500 | .bmap = ntfs_fuse_bmap, |
3501 | .destroy = ntfs_fuse_destroy2, |
3502 | #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) |
3503 | .access = ntfs_fuse_access, |
3504 | #endif |
3505 | #ifdef HAVE_SETXATTR |
3506 | .getxattr = ntfs_fuse_getxattr, |
3507 | .setxattr = ntfs_fuse_setxattr, |
3508 | .removexattr = ntfs_fuse_removexattr, |
3509 | .listxattr = ntfs_fuse_listxattr, |
3510 | #endif /* HAVE_SETXATTR */ |
3511 | #if 0 && (defined(__APPLE__) || defined(__DARWIN__)) /* Unfinished. */ |
3512 | /* MacFUSE extensions. */ |
3513 | .getxtimes = ntfs_macfuse_getxtimes, |
3514 | .setcrtime = ntfs_macfuse_setcrtime, |
3515 | .setbkuptime = ntfs_macfuse_setbkuptime, |
3516 | .setchgtime = ntfs_macfuse_setchgtime, |
3517 | #endif /* defined(__APPLE__) || defined(__DARWIN__) */ |
3518 | #if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \ |
3519 | || (defined(__APPLE__) || defined(__DARWIN__)) |
3520 | .init = ntfs_init |
3521 | #endif |
3522 | }; |
3523 | |
3524 | static int ntfs_fuse_init(void) |
3525 | { |
3526 | ctx = (ntfs_fuse_context_t*)ntfs_calloc(sizeof(ntfs_fuse_context_t)); |
3527 | if (!ctx) |
3528 | return -1; |
3529 | |
3530 | *ctx = (ntfs_fuse_context_t) { |
3531 | .uid = getuid(), |
3532 | .gid = getgid(), |
3533 | #if defined(linux) |
3534 | .streams = NF_STREAMS_INTERFACE_XATTR, |
3535 | #else |
3536 | .streams = NF_STREAMS_INTERFACE_NONE, |
3537 | #endif |
3538 | .atime = ATIME_RELATIVE, |
3539 | .silent = TRUE, |
3540 | .recover = TRUE |
3541 | }; |
3542 | return 0; |
3543 | } |
3544 | |
3545 | static int ntfs_open(const char *device) |
3546 | { |
3547 | unsigned long flags = 0; |
3548 | ntfs_volume *vol; |
3549 | |
3550 | if (!ctx->blkdev) |
3551 | flags |= NTFS_MNT_EXCLUSIVE; |
3552 | if (ctx->ro) |
3553 | flags |= NTFS_MNT_RDONLY; |
3554 | if (ctx->recover) |
3555 | flags |= NTFS_MNT_RECOVER; |
3556 | if (ctx->hiberfile) |
3557 | flags |= NTFS_MNT_IGNORE_HIBERFILE; |
3558 | |
3559 | ctx->vol = vol = ntfs_mount(device, flags); |
3560 | if (!vol) { |
3561 | ntfs_log_perror("Failed to mount '%s'", device); |
3562 | goto err_out; |
3563 | } |
3564 | if (ctx->sync && ctx->vol->dev) |
3565 | NDevSetSync(ctx->vol->dev); |
3566 | if (ctx->compression) |
3567 | NVolSetCompression(ctx->vol); |
3568 | else |
3569 | NVolClearCompression(ctx->vol); |
3570 | #ifdef HAVE_SETXATTR |
3571 | /* archivers must see hidden files */ |
3572 | if (ctx->efs_raw) |
3573 | ctx->hide_hid_files = FALSE; |
3574 | #endif |
3575 | if (ntfs_set_shown_files(ctx->vol, ctx->show_sys_files, |
3576 | !ctx->hide_hid_files, ctx->hide_dot_files)) |
3577 | goto err_out; |
3578 | |
3579 | if (ctx->ignore_case && ntfs_set_ignore_case(vol)) |
3580 | goto err_out; |
3581 | |
3582 | vol->free_clusters = ntfs_attr_get_free_bits(vol->lcnbmp_na); |
3583 | if (vol->free_clusters < 0) { |
3584 | ntfs_log_perror("Failed to read NTFS $Bitmap"); |
3585 | goto err_out; |
3586 | } |
3587 | |
3588 | vol->free_mft_records = ntfs_get_nr_free_mft_records(vol); |
3589 | if (vol->free_mft_records < 0) { |
3590 | ntfs_log_perror("Failed to calculate free MFT records"); |
3591 | goto err_out; |
3592 | } |
3593 | |
3594 | if (ctx->hiberfile && ntfs_volume_check_hiberfile(vol, 0)) { |
3595 | if (errno != EPERM) |
3596 | goto err_out; |
3597 | if (ntfs_fuse_rm((fuse_req_t)NULL,FILE_root,"hiberfil.sys", |
3598 | RM_LINK)) |
3599 | goto err_out; |
3600 | } |
3601 | |
3602 | errno = 0; |
3603 | err_out: |
3604 | return ntfs_volume_error(errno); |
3605 | |
3606 | } |
3607 | |
3608 | static void usage(void) |
3609 | { |
3610 | ntfs_log_info(usage_msg, EXEC_NAME, VERSION, FUSE_TYPE, fuse_version(), |
3611 | 5 + POSIXACLS*6 - KERNELPERMS*3 + CACHEING, |
3612 | EXEC_NAME, ntfs_home); |
3613 | } |
3614 | |
3615 | #if defined(linux) || defined(__uClinux__) |
3616 | |
3617 | static const char *dev_fuse_msg = |
3618 | "HINT: You should be root, or make ntfs-3g setuid root, or load the FUSE\n" |
3619 | " kernel module as root ('modprobe fuse' or 'insmod <path_to>/fuse.ko'" |
3620 | " or insmod <path_to>/fuse.o'). Make also sure that the fuse device" |
3621 | " exists. It's usually either /dev/fuse or /dev/misc/fuse."; |
3622 | |
3623 | static const char *fuse26_kmod_msg = |
3624 | "WARNING: Deficient Linux kernel detected. Some driver features are\n" |
3625 | " not available (swap file on NTFS, boot from NTFS by LILO), and\n" |
3626 | " unmount is not safe unless it's made sure the ntfs-3g process\n" |
3627 | " naturally terminates after calling 'umount'. If you wish this\n" |
3628 | " message to disappear then you should upgrade to at least kernel\n" |
3629 | " version 2.6.20, or request help from your distribution to fix\n" |
3630 | " the kernel problem. The below web page has more information:\n" |
3631 | " http://tuxera.com/community/ntfs-3g-faq/#fuse26\n" |
3632 | "\n"; |
3633 | |
3634 | static void mknod_dev_fuse(const char *dev) |
3635 | { |
3636 | struct stat st; |
3637 | |
3638 | if (stat(dev, &st) && (errno == ENOENT)) { |
3639 | mode_t mask = umask(0); |
3640 | if (mknod(dev, S_IFCHR | 0666, makedev(10, 229))) { |
3641 | ntfs_log_perror("Failed to create '%s'", dev); |
3642 | if (errno == EPERM) |
3643 | ntfs_log_error("%s", dev_fuse_msg); |
3644 | } |
3645 | umask(mask); |
3646 | } |
3647 | } |
3648 | |
3649 | static void create_dev_fuse(void) |
3650 | { |
3651 | mknod_dev_fuse("/dev/fuse"); |
3652 | |
3653 | #ifdef __UCLIBC__ |
3654 | { |
3655 | struct stat st; |
3656 | /* The fuse device is under /dev/misc using devfs. */ |
3657 | if (stat("/dev/misc", &st) && (errno == ENOENT)) { |
3658 | mode_t mask = umask(0); |
3659 | mkdir("/dev/misc", 0775); |
3660 | umask(mask); |
3661 | } |
3662 | mknod_dev_fuse("/dev/misc/fuse"); |
3663 | } |
3664 | #endif |
3665 | } |
3666 | |
3667 | static fuse_fstype get_fuse_fstype(void) |
3668 | { |
3669 | char buf[256]; |
3670 | fuse_fstype fstype = FSTYPE_NONE; |
3671 | |
3672 | FILE *f = fopen("/proc/filesystems", "r"); |
3673 | if (!f) { |
3674 | ntfs_log_perror("Failed to open /proc/filesystems"); |
3675 | return FSTYPE_UNKNOWN; |
3676 | } |
3677 | |
3678 | while (fgets(buf, sizeof(buf), f)) { |
3679 | if (strstr(buf, "fuseblk\n")) { |
3680 | fstype = FSTYPE_FUSEBLK; |
3681 | break; |
3682 | } |
3683 | if (strstr(buf, "fuse\n")) |
3684 | fstype = FSTYPE_FUSE; |
3685 | } |
3686 | |
3687 | fclose(f); |
3688 | return fstype; |
3689 | } |
3690 | |
3691 | static fuse_fstype load_fuse_module(void) |
3692 | { |
3693 | int i; |
3694 | struct stat st; |
3695 | pid_t pid; |
3696 | const char *cmd = "/sbin/modprobe"; |
3697 | struct timespec req = { 0, 100000000 }; /* 100 msec */ |
3698 | fuse_fstype fstype; |
3699 | |
3700 | if (!stat(cmd, &st) && !geteuid()) { |
3701 | pid = fork(); |
3702 | if (!pid) { |
3703 | execl(cmd, cmd, "fuse", NULL); |
3704 | _exit(1); |
3705 | } else if (pid != -1) |
3706 | waitpid(pid, NULL, 0); |
3707 | } |
3708 | |
3709 | for (i = 0; i < 10; i++) { |
3710 | /* |
3711 | * We sleep first because despite the detection of the loaded |
3712 | * FUSE kernel module, fuse_mount() can still fail if it's not |
3713 | * fully functional/initialized. Note, of course this is still |
3714 | * unreliable but usually helps. |
3715 | */ |
3716 | nanosleep(&req, NULL); |
3717 | fstype = get_fuse_fstype(); |
3718 | if (fstype != FSTYPE_NONE) |
3719 | break; |
3720 | } |
3721 | return fstype; |
3722 | } |
3723 | |
3724 | #endif |
3725 | |
3726 | static struct fuse_chan *try_fuse_mount(char *parsed_options) |
3727 | { |
3728 | struct fuse_chan *fc = NULL; |
3729 | struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); |
3730 | |
3731 | /* The fuse_mount() options get modified, so we always rebuild it */ |
3732 | if ((fuse_opt_add_arg(&margs, EXEC_NAME) == -1 || |
3733 | fuse_opt_add_arg(&margs, "-o") == -1 || |
3734 | fuse_opt_add_arg(&margs, parsed_options) == -1)) { |
3735 | ntfs_log_error("Failed to set FUSE options.\n"); |
3736 | goto free_args; |
3737 | } |
3738 | |
3739 | fc = fuse_mount(opts.mnt_point, &margs); |
3740 | free_args: |
3741 | fuse_opt_free_args(&margs); |
3742 | return fc; |
3743 | |
3744 | } |
3745 | |
3746 | static int set_fuseblk_options(char **parsed_options) |
3747 | { |
3748 | char options[64]; |
3749 | long pagesize; |
3750 | u32 blksize = ctx->vol->cluster_size; |
3751 | |
3752 | pagesize = sysconf(_SC_PAGESIZE); |
3753 | if (pagesize < 1) |
3754 | pagesize = 4096; |
3755 | |
3756 | if (blksize > (u32)pagesize) |
3757 | blksize = pagesize; |
3758 | |
3759 | snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize); |
3760 | if (ntfs_strappend(parsed_options, options)) |
3761 | return -1; |
3762 | return 0; |
3763 | } |
3764 | |
3765 | static struct fuse_session *mount_fuse(char *parsed_options) |
3766 | { |
3767 | struct fuse_session *se = NULL; |
3768 | struct fuse_args args = FUSE_ARGS_INIT(0, NULL); |
3769 | |
3770 | ctx->fc = try_fuse_mount(parsed_options); |
3771 | if (!ctx->fc) |
3772 | return NULL; |
3773 | |
3774 | if (fuse_opt_add_arg(&args, "") == -1) |
3775 | goto err; |
3776 | if (ctx->debug) |
3777 | if (fuse_opt_add_arg(&args, "-odebug") == -1) |
3778 | goto err; |
3779 | |
3780 | se = fuse_lowlevel_new(&args , &ntfs_3g_ops, sizeof(ntfs_3g_ops), NULL); |
3781 | if (!se) |
3782 | goto err; |
3783 | |
3784 | |
3785 | if (fuse_set_signal_handlers(se)) |
3786 | goto err_destroy; |
3787 | fuse_session_add_chan(se, ctx->fc); |
3788 | out: |
3789 | fuse_opt_free_args(&args); |
3790 | return se; |
3791 | err_destroy: |
3792 | fuse_session_destroy(se); |
3793 | se = NULL; |
3794 | err: |
3795 | fuse_unmount(opts.mnt_point, ctx->fc); |
3796 | goto out; |
3797 | } |
3798 | |
3799 | static void setup_logging(char *parsed_options) |
3800 | { |
3801 | if (!ctx->no_detach) { |
3802 | if (daemon(0, ctx->debug)) |
3803 | ntfs_log_error("Failed to daemonize.\n"); |
3804 | else if (!ctx->debug) { |
3805 | #ifndef DEBUG |
3806 | ntfs_log_set_handler(ntfs_log_handler_syslog); |
3807 | /* Override default libntfs identify. */ |
3808 | openlog(EXEC_NAME, LOG_PID, LOG_DAEMON); |
3809 | #endif |
3810 | } |
3811 | } |
3812 | |
3813 | ctx->seccache = (struct PERMISSIONS_CACHE*)NULL; |
3814 | |
3815 | ntfs_log_info("Version %s %s %d\n", VERSION, FUSE_TYPE, fuse_version()); |
3816 | if (strcmp(opts.arg_device,opts.device)) |
3817 | ntfs_log_info("Requested device %s canonicalized as %s\n", |
3818 | opts.arg_device,opts.device); |
3819 | ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS %d.%d)\n", |
3820 | opts.device, (ctx->ro) ? "Read-Only" : "Read-Write", |
3821 | ctx->vol->vol_name, ctx->vol->major_ver, |
3822 | ctx->vol->minor_ver); |
3823 | ntfs_log_info("Cmdline options: %s\n", opts.options ? opts.options : ""); |
3824 | ntfs_log_info("Mount options: %s\n", parsed_options); |
3825 | } |
3826 | |
3827 | int main(int argc, char *argv[]) |
3828 | { |
3829 | char *parsed_options = NULL; |
3830 | struct fuse_session *se; |
3831 | #if !(defined(__sun) && defined (__SVR4)) |
3832 | fuse_fstype fstype = FSTYPE_UNKNOWN; |
3833 | #endif |
3834 | const char *permissions_mode = (const char*)NULL; |
3835 | const char *failed_secure = (const char*)NULL; |
3836 | #if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) |
3837 | struct XATTRMAPPING *xattr_mapping = (struct XATTRMAPPING*)NULL; |
3838 | #endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ |
3839 | struct stat sbuf; |
3840 | unsigned long existing_mount; |
3841 | int err, fd; |
3842 | |
3843 | /* |
3844 | * Make sure file descriptors 0, 1 and 2 are open, |
3845 | * otherwise chaos would ensue. |
3846 | */ |
3847 | do { |
3848 | fd = open("/dev/null", O_RDWR); |
3849 | if (fd > 2) |
3850 | close(fd); |
3851 | } while (fd >= 0 && fd <= 2); |
3852 | |
3853 | #ifndef FUSE_INTERNAL |
3854 | if ((getuid() != geteuid()) || (getgid() != getegid())) { |
3855 | fprintf(stderr, "%s", setuid_msg); |
3856 | return NTFS_VOLUME_INSECURE; |
3857 | } |
3858 | #endif |
3859 | if (drop_privs()) |
3860 | return NTFS_VOLUME_NO_PRIVILEGE; |
3861 | |
3862 | ntfs_set_locale(); |
3863 | ntfs_log_set_handler(ntfs_log_handler_stderr); |
3864 | |
3865 | if (ntfs_parse_options(&opts, usage, argc, argv)) { |
3866 | usage(); |
3867 | return NTFS_VOLUME_SYNTAX_ERROR; |
3868 | } |
3869 | |
3870 | if (ntfs_fuse_init()) { |
3871 | err = NTFS_VOLUME_OUT_OF_MEMORY; |
3872 | goto err2; |
3873 | } |
3874 | |
3875 | parsed_options = parse_mount_options(ctx, &opts, TRUE); |
3876 | if (!parsed_options) { |
3877 | err = NTFS_VOLUME_SYNTAX_ERROR; |
3878 | goto err_out; |
3879 | } |
3880 | if (!ntfs_check_if_mounted(opts.device,&existing_mount) |
3881 | && (existing_mount & NTFS_MF_MOUNTED) |
3882 | /* accept multiple read-only mounts */ |
3883 | && (!(existing_mount & NTFS_MF_READONLY) || !ctx->ro)) { |
3884 | err = NTFS_VOLUME_LOCKED; |
3885 | goto err_out; |
3886 | } |
3887 | |
3888 | /* need absolute mount point for junctions */ |
3889 | if (opts.mnt_point[0] == '/') |
3890 | ctx->abs_mnt_point = strdup(opts.mnt_point); |
3891 | else { |
3892 | ctx->abs_mnt_point = (char*)ntfs_malloc(PATH_MAX); |
3893 | if (ctx->abs_mnt_point) { |
3894 | if (getcwd(ctx->abs_mnt_point, |
3895 | PATH_MAX - strlen(opts.mnt_point) - 1)) { |
3896 | strcat(ctx->abs_mnt_point, "/"); |
3897 | strcat(ctx->abs_mnt_point, opts.mnt_point); |
3898 | #if defined(__sun) && defined (__SVR4) |
3899 | /* Solaris also wants the absolute mount point */ |
3900 | opts.mnt_point = ctx->abs_mnt_point; |
3901 | #endif /* defined(__sun) && defined (__SVR4) */ |
3902 | } |
3903 | } |
3904 | } |
3905 | if (!ctx->abs_mnt_point) { |
3906 | err = NTFS_VOLUME_OUT_OF_MEMORY; |
3907 | goto err_out; |
3908 | } |
3909 | |
3910 | ctx->security.uid = 0; |
3911 | ctx->security.gid = 0; |
3912 | if ((opts.mnt_point[0] == '/') |
3913 | && !stat(opts.mnt_point,&sbuf)) { |
3914 | /* collect owner of mount point, useful for default mapping */ |
3915 | ctx->security.uid = sbuf.st_uid; |
3916 | ctx->security.gid = sbuf.st_gid; |
3917 | } |
3918 | |
3919 | #if defined(linux) || defined(__uClinux__) |
3920 | fstype = get_fuse_fstype(); |
3921 | |
3922 | err = NTFS_VOLUME_NO_PRIVILEGE; |
3923 | if (restore_privs()) |
3924 | goto err_out; |
3925 | |
3926 | if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN) |
3927 | fstype = load_fuse_module(); |
3928 | create_dev_fuse(); |
3929 | |
3930 | if (drop_privs()) |
3931 | goto err_out; |
3932 | #endif |
3933 | if (stat(opts.device, &sbuf)) { |
3934 | ntfs_log_perror("Failed to access '%s'", opts.device); |
3935 | err = NTFS_VOLUME_NO_PRIVILEGE; |
3936 | goto err_out; |
3937 | } |
3938 | |
3939 | #if !(defined(__sun) && defined (__SVR4)) |
3940 | /* Always use fuseblk for block devices unless it's surely missing. */ |
3941 | if (S_ISBLK(sbuf.st_mode) && (fstype != FSTYPE_FUSE)) |
3942 | ctx->blkdev = TRUE; |
3943 | #endif |
3944 | |
3945 | #ifndef FUSE_INTERNAL |
3946 | if (getuid() && ctx->blkdev) { |
3947 | ntfs_log_error("%s", unpriv_fuseblk_msg); |
3948 | err = NTFS_VOLUME_NO_PRIVILEGE; |
3949 | goto err2; |
3950 | } |
3951 | #endif |
3952 | err = ntfs_open(opts.device); |
3953 | if (err) |
3954 | goto err_out; |
3955 | |
3956 | /* Force read-only mount if the device was found read-only */ |
3957 | if (!ctx->ro && NVolReadOnly(ctx->vol)) { |
3958 | ctx->ro = TRUE; |
3959 | if (ntfs_strinsert(&parsed_options, ",ro")) |
3960 | goto err_out; |
3961 | } |
3962 | /* We must do this after ntfs_open() to be able to set the blksize */ |
3963 | if (ctx->blkdev && set_fuseblk_options(&parsed_options)) |
3964 | goto err_out; |
3965 | |
3966 | ctx->security.vol = ctx->vol; |
3967 | ctx->vol->secure_flags = ctx->secure_flags; |
3968 | #ifdef HAVE_SETXATTR /* extended attributes interface required */ |
3969 | ctx->vol->efs_raw = ctx->efs_raw; |
3970 | #endif /* HAVE_SETXATTR */ |
3971 | /* JPA open $Secure, (whatever NTFS version !) */ |
3972 | /* to initialize security data */ |
3973 | if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3)) |
3974 | failed_secure = "Could not open file $Secure"; |
3975 | if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path, |
3976 | (ctx->vol->secure_flags |
3977 | & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL))) |
3978 | && !(ctx->vol->secure_flags & (1 << SECURITY_WANTED)))) { |
3979 | #if POSIXACLS |
3980 | /* use basic permissions if requested */ |
3981 | if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT)) |
3982 | permissions_mode = "User mapping built, Posix ACLs not used"; |
3983 | else { |
3984 | permissions_mode = "User mapping built, Posix ACLs in use"; |
3985 | #if KERNELACLS |
3986 | if (ntfs_strinsert(&parsed_options, |
3987 | ",default_permissions,acl")) { |
3988 | err = NTFS_VOLUME_SYNTAX_ERROR; |
3989 | goto err_out; |
3990 | } |
3991 | #endif /* KERNELACLS */ |
3992 | } |
3993 | #else /* POSIXACLS */ |
3994 | if (!(ctx->vol->secure_flags |
3995 | & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL)))) { |
3996 | /* |
3997 | * No explicit option but user mapping found |
3998 | * force default security |
3999 | */ |
4000 | #if KERNELPERMS |
4001 | ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT); |
4002 | if (ntfs_strinsert(&parsed_options, ",default_permissions")) { |
4003 | err = NTFS_VOLUME_SYNTAX_ERROR; |
4004 | goto err_out; |
4005 | } |
4006 | #endif /* KERNELPERMS */ |
4007 | } |
4008 | permissions_mode = "User mapping built"; |
4009 | #endif /* POSIXACLS */ |
4010 | } else { |
4011 | ctx->security.uid = ctx->uid; |
4012 | ctx->security.gid = ctx->gid; |
4013 | /* same ownership/permissions for all files */ |
4014 | ctx->security.mapping[MAPUSERS] = (struct MAPPING*)NULL; |
4015 | ctx->security.mapping[MAPGROUPS] = (struct MAPPING*)NULL; |
4016 | if ((ctx->vol->secure_flags & (1 << SECURITY_WANTED)) |
4017 | && !(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) { |
4018 | ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT); |
4019 | if (ntfs_strinsert(&parsed_options, ",default_permissions")) { |
4020 | err = NTFS_VOLUME_SYNTAX_ERROR; |
4021 | goto err_out; |
4022 | } |
4023 | } |
4024 | if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT)) { |
4025 | ctx->vol->secure_flags |= (1 << SECURITY_RAW); |
4026 | permissions_mode = "Global ownership and permissions enforced"; |
4027 | } else { |
4028 | ctx->vol->secure_flags &= ~(1 << SECURITY_RAW); |
4029 | permissions_mode = "Ownership and permissions disabled"; |
4030 | } |
4031 | } |
4032 | if (ctx->usermap_path) |
4033 | free (ctx->usermap_path); |
4034 | |
4035 | #if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) |
4036 | xattr_mapping = ntfs_xattr_build_mapping(ctx->vol, |
4037 | ctx->xattrmap_path); |
4038 | ctx->vol->xattr_mapping = xattr_mapping; |
4039 | /* |
4040 | * Errors are logged, do not refuse mounting, it would be |
4041 | * too difficult to fix the unmountable mapping file. |
4042 | */ |
4043 | if (ctx->xattrmap_path) |
4044 | free(ctx->xattrmap_path); |
4045 | #endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ |
4046 | |
4047 | se = mount_fuse(parsed_options); |
4048 | if (!se) { |
4049 | err = NTFS_VOLUME_FUSE_ERROR; |
4050 | goto err_out; |
4051 | } |
4052 | |
4053 | ctx->mounted = TRUE; |
4054 | |
4055 | #if defined(linux) || defined(__uClinux__) |
4056 | if (S_ISBLK(sbuf.st_mode) && (fstype == FSTYPE_FUSE)) |
4057 | ntfs_log_info("%s", fuse26_kmod_msg); |
4058 | #endif |
4059 | setup_logging(parsed_options); |
4060 | if (failed_secure) |
4061 | ntfs_log_info("%s\n",failed_secure); |
4062 | if (permissions_mode) |
4063 | ntfs_log_info("%s, configuration type %d\n",permissions_mode, |
4064 | 5 + POSIXACLS*6 - KERNELPERMS*3 + CACHEING); |
4065 | |
4066 | fuse_session_loop(se); |
4067 | fuse_remove_signal_handlers(se); |
4068 | |
4069 | err = 0; |
4070 | |
4071 | fuse_unmount(opts.mnt_point, ctx->fc); |
4072 | fuse_session_destroy(se); |
4073 | err_out: |
4074 | ntfs_mount_error(opts.device, opts.mnt_point, err); |
4075 | if (ctx->abs_mnt_point) |
4076 | free(ctx->abs_mnt_point); |
4077 | #if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) |
4078 | ntfs_xattr_free_mapping(xattr_mapping); |
4079 | #endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ |
4080 | err2: |
4081 | ntfs_close(); |
4082 | free(ctx); |
4083 | free(parsed_options); |
4084 | free(opts.options); |
4085 | free(opts.device); |
4086 | return err; |
4087 | } |
4088 | |
4089 |