1 /**
2 * Copyright (c) 2005-2007 Yura Pakhuchiy
3 * Copyright (c) 2005 Yuval Fledel
4 * Copyright (c) 2006-2009 Szabolcs Szakacsits
5 * Copyright (c) 2007-2021 Jean-Pierre Andre
6 * Copyright (c) 2009 Erik Larsson
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program (in the main directory of the NTFS-3G
20 * distribution in the file COPYING); if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23 #include "lowntfs.h"
24
25 #include <stdlib.h>
26 #include <errno.h>
27
28 #include "libntfs/dir.h"
29 #include "libntfs/reparse.h"
30 #include "libntfs/misc.h"
31
32
33 #define DISABLE_PLUGINS
34 #define KERNELPERMS 1
35 #define INODE(ino) ino
36 #define ntfs_allowed_dir_access(...) (1) /* permissions checks done elsewhere */
37
38 #define set_archive(ni) (ni)->flags |= FILE_ATTR_ARCHIVE
39
40
41 static const char ntfs_bad_reparse[] = "unsupported reparse tag 0x%08lx";
42 /* exact length of target text, without the terminator */
43 #define ntfs_bad_reparse_lth (sizeof(ntfs_bad_reparse) + 2)
44
45 static const char ghostformat[] = ".ghost-ntfs-3g-%020llu";
46 #define GHOSTLTH 40 /* max length of a ghost file name - see ghostformat */
47
48 static u32 ntfs_sequence = 0;
49
50
51 static void
set_fuse_error(int * err)52 set_fuse_error(int *err)
53 {
54 if (!*err)
55 *err = errno;
56 }
57
58 static void
ntfs_fuse_update_times(ntfs_inode * ni,ntfs_time_update_flags mask)59 ntfs_fuse_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
60 {
61 #ifdef __HAIKU__
62 mask &= ~NTFS_UPDATE_ATIME;
63 #else
64 if (ctx->atime == ATIME_DISABLED)
65 mask &= ~NTFS_UPDATE_ATIME;
66 else if (ctx->atime == ATIME_RELATIVE && mask == NTFS_UPDATE_ATIME &&
67 (sle64_to_cpu(ni->last_access_time)
68 >= sle64_to_cpu(ni->last_data_change_time)) &&
69 (sle64_to_cpu(ni->last_access_time)
70 >= sle64_to_cpu(ni->last_mft_change_time)))
71 return;
72 #endif
73 ntfs_inode_update_times(ni, mask);
74 }
75
76
ntfs_fuse_fill_security_context(struct lowntfs_context * ctx,struct SECURITY_CONTEXT * scx)77 static BOOL ntfs_fuse_fill_security_context(struct lowntfs_context *ctx,
78 struct SECURITY_CONTEXT *scx)
79 {
80 const struct fuse_ctx *fusecontext;
81
82 scx->vol = ctx->vol;
83 scx->mapping[MAPUSERS] = NULL;
84 scx->mapping[MAPGROUPS] = NULL;
85 scx->pseccache = NULL;
86 scx->uid = 0;
87 scx->gid = 0;
88 scx->tid = 0;
89 scx->umask = 0;
90 return (scx->mapping[MAPUSERS] != (struct MAPPING*)NULL);
91 }
92
93
94 u64
ntfs_fuse_inode_lookup(struct lowntfs_context * ctx,u64 parent,const char * name)95 ntfs_fuse_inode_lookup(struct lowntfs_context *ctx, u64 parent, const char *name)
96 {
97 u64 ino = (u64)-1;
98 u64 inum;
99 ntfs_inode *dir_ni;
100
101 /* Open target directory. */
102 dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
103 if (dir_ni) {
104 /* Lookup file */
105 inum = ntfs_inode_lookup_by_mbsname(dir_ni, name);
106 /* never return inodes 0 and 1 */
107 if (MREF(inum) <= 1) {
108 inum = (u64)-1;
109 errno = ENOENT;
110 }
111 if (ntfs_inode_close(dir_ni)
112 || (inum == (u64)-1))
113 ino = (u64)-1;
114 else
115 ino = MREF(inum);
116 }
117 return (ino);
118 }
119
120
121 int
ntfs_fuse_getstat(struct lowntfs_context * ctx,struct SECURITY_CONTEXT * scx,ntfs_inode * ni,struct stat * stbuf)122 ntfs_fuse_getstat(struct lowntfs_context *ctx, struct SECURITY_CONTEXT *scx,
123 ntfs_inode *ni, struct stat *stbuf)
124 {
125 int res = 0;
126 ntfs_attr *na;
127 BOOL withusermapping;
128
129 memset(stbuf, 0, sizeof(struct stat));
130 withusermapping = scx && (scx->mapping[MAPUSERS] != (struct MAPPING*)NULL);
131 stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
132 if (ctx->posix_nlink
133 && !(ni->flags & FILE_ATTR_REPARSE_POINT))
134 stbuf->st_nlink = ntfs_dir_link_cnt(ni);
135 if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
136 || (ni->flags & FILE_ATTR_REPARSE_POINT)) {
137 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
138 #ifndef DISABLE_PLUGINS
139 const plugin_operations_t *ops;
140 REPARSE_POINT *reparse;
141
142 res = CALL_REPARSE_PLUGIN(ni, getattr, stbuf);
143 if (!res) {
144 apply_umask(stbuf);
145 } else {
146 stbuf->st_size = ntfs_bad_reparse_lth;
147 stbuf->st_blocks =
148 (ni->allocated_size + 511) >> 9;
149 stbuf->st_mode = S_IFLNK;
150 res = 0;
151 }
152 goto ok;
153 #else /* DISABLE_PLUGINS */
154 char *target;
155
156 errno = 0;
157 target = ntfs_make_symlink(ni, ctx->abs_mnt_point);
158 /*
159 * If the reparse point is not a valid
160 * directory junction, and there is no error
161 * we still display as a symlink
162 */
163 if (target || (errno == EOPNOTSUPP)) {
164 if (target)
165 stbuf->st_size = strlen(target);
166 else
167 stbuf->st_size = ntfs_bad_reparse_lth;
168 stbuf->st_blocks =
169 (ni->allocated_size + 511) >> 9;
170 stbuf->st_nlink =
171 le16_to_cpu(ni->mrec->link_count);
172 stbuf->st_mode = S_IFLNK;
173 free(target);
174 } else {
175 res = -errno;
176 goto exit;
177 }
178 #endif /* DISABLE_PLUGINS */
179 } else {
180 /* Directory. */
181 stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask);
182 /* get index size, if not known */
183 if (!test_nino_flag(ni, KnownSize)) {
184 na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION,
185 NTFS_INDEX_I30, 4);
186 if (na) {
187 ni->data_size = na->data_size;
188 ni->allocated_size = na->allocated_size;
189 set_nino_flag(ni, KnownSize);
190 ntfs_attr_close(na);
191 }
192 }
193 stbuf->st_size = ni->data_size;
194 stbuf->st_blocks = ni->allocated_size >> 9;
195 if (!ctx->posix_nlink)
196 stbuf->st_nlink = 1; /* Make find(1) work */
197 }
198 } else {
199 /* Regular or Interix (INTX) file. */
200 stbuf->st_mode = S_IFREG;
201 stbuf->st_size = ni->data_size;
202 #ifdef HAVE_SETXATTR /* extended attributes interface required */
203 /*
204 * return data size rounded to next 512 byte boundary for
205 * encrypted files to include padding required for decryption
206 * also include 2 bytes for padding info
207 */
208 if (ctx->efs_raw
209 && (ni->flags & FILE_ATTR_ENCRYPTED)
210 && ni->data_size)
211 stbuf->st_size = ((ni->data_size + 511) & ~511) + 2;
212 #endif /* HAVE_SETXATTR */
213 /*
214 * Temporary fix to make ActiveSync work via Samba 3.0.
215 * See more on the ntfs-3g-devel list.
216 */
217 stbuf->st_blocks = (ni->allocated_size + 511) >> 9;
218 if (ni->flags & FILE_ATTR_SYSTEM) {
219 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
220 if (!na) {
221 stbuf->st_ino = ni->mft_no;
222 goto nodata;
223 }
224 /* Check whether it's Interix FIFO or socket. */
225 if (!(ni->flags & FILE_ATTR_HIDDEN)) {
226 /* FIFO. */
227 if (na->data_size == 0)
228 stbuf->st_mode = S_IFIFO;
229 /* Socket link. */
230 if (na->data_size == 1)
231 stbuf->st_mode = S_IFSOCK;
232 }
233 /*
234 * Check whether it's Interix symbolic link, block or
235 * character device.
236 */
237 if ((u64)na->data_size <= sizeof(INTX_FILE_TYPES)
238 + sizeof(ntfschar) * PATH_MAX
239 && (u64)na->data_size >
240 sizeof(INTX_FILE_TYPES)) {
241 INTX_FILE *intx_file;
242
243 intx_file =
244 (INTX_FILE*)ntfs_malloc(na->data_size);
245 if (!intx_file) {
246 res = -errno;
247 ntfs_attr_close(na);
248 goto exit;
249 }
250 if (ntfs_attr_pread(na, 0, na->data_size,
251 intx_file) != na->data_size) {
252 res = -errno;
253 free(intx_file);
254 ntfs_attr_close(na);
255 goto exit;
256 }
257 if (intx_file->magic == INTX_BLOCK_DEVICE &&
258 na->data_size == (s64)offsetof(
259 INTX_FILE, device_end)) {
260 stbuf->st_mode = S_IFBLK;
261 stbuf->st_rdev = makedev(le64_to_cpu(
262 intx_file->major),
263 le64_to_cpu(
264 intx_file->minor));
265 }
266 if (intx_file->magic == INTX_CHARACTER_DEVICE &&
267 na->data_size == (s64)offsetof(
268 INTX_FILE, device_end)) {
269 stbuf->st_mode = S_IFCHR;
270 stbuf->st_rdev = makedev(le64_to_cpu(
271 intx_file->major),
272 le64_to_cpu(
273 intx_file->minor));
274 }
275 if (intx_file->magic == INTX_SYMBOLIC_LINK) {
276 char *target = NULL;
277 int len;
278
279 /* st_size should be set to length of
280 * symlink target as multibyte string */
281 len = ntfs_ucstombs(
282 intx_file->target,
283 (na->data_size -
284 offsetof(INTX_FILE,
285 target)) /
286 sizeof(ntfschar),
287 &target, 0);
288 if (len < 0) {
289 res = -errno;
290 free(intx_file);
291 ntfs_attr_close(na);
292 goto exit;
293 }
294 free(target);
295 stbuf->st_mode = S_IFLNK;
296 stbuf->st_size = len;
297 }
298 free(intx_file);
299 }
300 ntfs_attr_close(na);
301 }
302 stbuf->st_mode |= (0777 & ~ctx->fmask);
303 }
304 #ifndef DISABLE_PLUGINS
305 ok:
306 #endif /* DISABLE_PLUGINS */
307 if (withusermapping) {
308 ntfs_get_owner_mode(scx,ni,stbuf);
309 } else {
310 #ifndef __HAIKU__
311 stbuf->st_uid = ctx->uid;
312 stbuf->st_gid = ctx->gid;
313 #endif
314 }
315 if (S_ISLNK(stbuf->st_mode))
316 stbuf->st_mode |= 0777;
317 nodata :
318 stbuf->st_ino = ni->mft_no;
319 #ifdef HAVE_STRUCT_STAT_ST_ATIMESPEC
320 stbuf->st_atimespec = ntfs2timespec(ni->last_access_time);
321 stbuf->st_ctimespec = ntfs2timespec(ni->last_mft_change_time);
322 stbuf->st_mtimespec = ntfs2timespec(ni->last_data_change_time);
323 #elif defined(HAVE_STRUCT_STAT_ST_ATIM)
324 stbuf->st_atim = ntfs2timespec(ni->last_access_time);
325 stbuf->st_ctim = ntfs2timespec(ni->last_mft_change_time);
326 stbuf->st_mtim = ntfs2timespec(ni->last_data_change_time);
327 #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
328 {
329 struct timespec ts;
330
331 ts = ntfs2timespec(ni->last_access_time);
332 stbuf->st_atime = ts.tv_sec;
333 stbuf->st_atimensec = ts.tv_nsec;
334 ts = ntfs2timespec(ni->last_mft_change_time);
335 stbuf->st_ctime = ts.tv_sec;
336 stbuf->st_ctimensec = ts.tv_nsec;
337 ts = ntfs2timespec(ni->last_data_change_time);
338 stbuf->st_mtime = ts.tv_sec;
339 stbuf->st_mtimensec = ts.tv_nsec;
340 }
341 #else
342 #warning "No known way to set nanoseconds in struct stat !"
343 {
344 struct timespec ts;
345
346 ts = ntfs2timespec(ni->last_access_time);
347 stbuf->st_atime = ts.tv_sec;
348 ts = ntfs2timespec(ni->last_mft_change_time);
349 stbuf->st_ctime = ts.tv_sec;
350 ts = ntfs2timespec(ni->last_data_change_time);
351 stbuf->st_mtime = ts.tv_sec;
352 }
353 #endif
354 #ifdef __HAIKU__
355 stbuf->st_crtim = ntfs2timespec(ni->creation_time);
356 #endif
357 exit:
358 return (res);
359 }
360
361
362 int
ntfs_fuse_readlink(struct lowntfs_context * ctx,u64 ino,void * buffer,size_t * bufferSize)363 ntfs_fuse_readlink(struct lowntfs_context* ctx, u64 ino, void* buffer, size_t* bufferSize)
364 {
365 ntfs_inode *ni = NULL;
366 ntfs_attr *na = NULL;
367 INTX_FILE *intx_file = NULL;
368 char *buf = (char*)NULL;
369 int res = 0;
370
371 /* Get inode. */
372 ni = ntfs_inode_open(ctx->vol, INODE(ino));
373 if (!ni) {
374 res = -errno;
375 goto exit;
376 }
377 /*
378 * Reparse point : analyze as a junction point
379 */
380 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
381 REPARSE_POINT *reparse;
382 le32 tag;
383 int lth;
384 #ifndef DISABLE_PLUGINS
385 const plugin_operations_t *ops;
386
387 res = CALL_REPARSE_PLUGIN(ni, readlink, &buf);
388 /* plugin missing or reparse tag failing the check */
389 if (res && ((errno == ELIBACC) || (errno == EINVAL)))
390 errno = EOPNOTSUPP;
391 #else /* DISABLE_PLUGINS */
392 errno = 0;
393 res = 0;
394 buf = ntfs_make_symlink(ni, ctx->abs_mnt_point);
395 #endif /* DISABLE_PLUGINS */
396 if (!buf && (errno == EOPNOTSUPP)) {
397 buf = (char*)malloc(ntfs_bad_reparse_lth + 1);
398 if (buf) {
399 reparse = ntfs_get_reparse_point(ni);
400 if (reparse) {
401 tag = reparse->reparse_tag;
402 free(reparse);
403 } else
404 tag = const_cpu_to_le32(0);
405 lth = snprintf(buf, ntfs_bad_reparse_lth + 1,
406 ntfs_bad_reparse,
407 (long)le32_to_cpu(tag));
408 res = 0;
409 if (lth != ntfs_bad_reparse_lth) {
410 free(buf);
411 buf = (char*)NULL;
412 }
413 }
414 }
415 if (!buf)
416 res = -errno;
417 goto exit;
418 }
419 /* Sanity checks. */
420 if (!(ni->flags & FILE_ATTR_SYSTEM)) {
421 res = -EINVAL;
422 goto exit;
423 }
424 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
425 if (!na) {
426 res = -errno;
427 goto exit;
428 }
429 if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)) {
430 res = -EINVAL;
431 goto exit;
432 }
433 if ((size_t)na->data_size > sizeof(INTX_FILE_TYPES) +
434 sizeof(ntfschar) * PATH_MAX) {
435 res = -ENAMETOOLONG;
436 goto exit;
437 }
438 /* Receive file content. */
439 intx_file = (INTX_FILE*)ntfs_malloc(na->data_size);
440 if (!intx_file) {
441 res = -errno;
442 goto exit;
443 }
444 if (ntfs_attr_pread(na, 0, na->data_size, intx_file) != na->data_size) {
445 res = -errno;
446 goto exit;
447 }
448 /* Sanity check. */
449 if (intx_file->magic != INTX_SYMBOLIC_LINK) {
450 res = -EINVAL;
451 goto exit;
452 }
453 /* Convert link from unicode to local encoding. */
454 if (ntfs_ucstombs(intx_file->target, (na->data_size -
455 offsetof(INTX_FILE, target)) / sizeof(ntfschar),
456 &buf, 0) < 0) {
457 res = -errno;
458 goto exit;
459 }
460 exit:
461 if (intx_file)
462 free(intx_file);
463 if (na)
464 ntfs_attr_close(na);
465 ntfs_inode_close(ni);
466
467 #ifdef __HAIKU__
468 if (buf && !res) {
469 strlcpy(buffer, buf, *bufferSize);
470 *bufferSize = strlen(buf);
471 // Indicate the actual length of the link.
472 }
473 #endif
474
475 free(buf);
476 return res;
477 }
478
479
480 int
ntfs_fuse_read(ntfs_inode * ni,off_t offset,char * buf,size_t size)481 ntfs_fuse_read(ntfs_inode* ni, off_t offset, char* buf, size_t size)
482 {
483 ntfs_attr *na = NULL;
484 int res;
485 s64 total = 0;
486 s64 max_read;
487
488 if (!size) {
489 res = 0;
490 goto exit;
491 }
492
493 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
494 #ifndef DISABLE_PLUGINS
495 const plugin_operations_t *ops;
496 REPARSE_POINT *reparse;
497 struct open_file *of;
498
499 of = (struct open_file*)(long)fi->fh;
500 res = CALL_REPARSE_PLUGIN(ni, read, buf, size, offset, &of->fi);
501 if (res >= 0) {
502 goto stamps;
503 }
504 #else /* DISABLE_PLUGINS */
505 errno = EOPNOTSUPP;
506 res = errno;
507 #endif /* DISABLE_PLUGINS */
508 goto exit;
509 }
510 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
511 if (!na) {
512 res = errno;
513 goto exit;
514 }
515 max_read = na->data_size;
516 #ifdef HAVE_SETXATTR /* extended attributes interface required */
517 /* limit reads at next 512 byte boundary for encrypted attributes */
518 if (ctx->efs_raw
519 && max_read
520 && (na->data_flags & ATTR_IS_ENCRYPTED)
521 && NAttrNonResident(na)) {
522 max_read = ((na->data_size+511) & ~511) + 2;
523 }
524 #endif /* HAVE_SETXATTR */
525 if (offset + (off_t)size > max_read) {
526 if (max_read < offset)
527 goto ok;
528 size = max_read - offset;
529 }
530 while (size > 0) {
531 s64 ret = ntfs_attr_pread(na, offset, size, buf + total);
532 if (ret != (s64)size)
533 ntfs_log_perror("ntfs_attr_pread error reading inode %lld at "
534 "offset %lld: %lld <> %lld", (long long)ni->mft_no,
535 (long long)offset, (long long)size, (long long)ret);
536 if (ret <= 0 || ret > (s64)size) {
537 res = (ret < 0) ? errno : EIO;
538 goto exit;
539 }
540 size -= ret;
541 offset += ret;
542 total += ret;
543 }
544 ok:
545 res = total;
546 #ifndef DISABLE_PLUGINS
547 stamps :
548 #endif /* DISABLE_PLUGINS */
549 ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME);
550 exit:
551 if (na)
552 ntfs_attr_close(na);
553 return res;
554 }
555
556 int
ntfs_fuse_write(struct lowntfs_context * ctx,ntfs_inode * ni,const char * buf,size_t size,off_t offset)557 ntfs_fuse_write(struct lowntfs_context* ctx, ntfs_inode* ni, const char *buf,
558 size_t size, off_t offset)
559 {
560 ntfs_attr *na = NULL;
561 int res, total = 0;
562
563 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
564 #ifndef DISABLE_PLUGINS
565 const plugin_operations_t *ops;
566 REPARSE_POINT *reparse;
567 struct open_file *of;
568
569 of = (struct open_file*)(long)fi->fh;
570 res = CALL_REPARSE_PLUGIN(ni, write, buf, size, offset,
571 &of->fi);
572 if (res >= 0) {
573 goto stamps;
574 }
575 #else /* DISABLE_PLUGINS */
576 res = EOPNOTSUPP;
577 errno = EOPNOTSUPP;
578 #endif /* DISABLE_PLUGINS */
579 goto exit;
580 }
581 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
582 if (!na) {
583 res = errno;
584 goto exit;
585 }
586 while (size) {
587 s64 ret = ntfs_attr_pwrite(na, offset, size, buf + total);
588 if (ret <= 0) {
589 res = errno;
590 goto exit;
591 }
592 size -= ret;
593 offset += ret;
594 total += ret;
595 }
596 res = total;
597 #ifndef DISABLE_PLUGINS
598 stamps :
599 #endif /* DISABLE_PLUGINS */
600 if ((res > 0)
601 && (!ctx->dmtime
602 || (sle64_to_cpu(ntfs_current_time())
603 - sle64_to_cpu(ni->last_data_change_time)) > ctx->dmtime))
604 ntfs_fuse_update_times(ni, NTFS_UPDATE_MCTIME);
605 exit:
606 if (na)
607 ntfs_attr_close(na);
608 if (res > 0)
609 set_archive(ni);
610 return res;
611 }
612
613 int
ntfs_fuse_create(struct lowntfs_context * ctx,ino_t parent,const char * name,mode_t typemode,dev_t dev,const char * target,ino_t * ino)614 ntfs_fuse_create(struct lowntfs_context *ctx, ino_t parent, const char *name,
615 mode_t typemode, dev_t dev, const char *target, ino_t* ino)
616 {
617 ntfschar *uname = NULL, *utarget = NULL;
618 ntfs_inode *dir_ni = NULL, *ni;
619 struct open_file *of;
620 int state = 0;
621 le32 securid;
622 gid_t gid;
623 mode_t dsetgid;
624 mode_t type = typemode & ~07777;
625 mode_t perm;
626 struct SECURITY_CONTEXT security;
627 int res = 0, uname_len, utarget_len;
628 const int fi = 1;
629
630 /* Generate unicode filename. */
631 uname_len = ntfs_mbstoucs(name, &uname);
632 if ((uname_len < 0)
633 || (ctx->windows_names
634 && ntfs_forbidden_names(ctx->vol,uname,uname_len,TRUE))) {
635 res = -errno;
636 goto exit;
637 }
638 /* Deny creating into $Extend */
639 if (parent == FILE_Extend) {
640 errno = EPERM;
641 res = -errno;
642 goto exit;
643 }
644 /* Open parent directory. */
645 dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
646 if (!dir_ni) {
647 res = -errno;
648 goto exit;
649 }
650 #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
651 /* make sure parent directory is writeable and executable */
652 if (!ntfs_fuse_fill_security_context(ctx, &security)
653 || ntfs_allowed_create(&security,
654 dir_ni, &gid, &dsetgid)) {
655 #else
656 ntfs_fuse_fill_security_context(ctx, &security);
657 ntfs_allowed_create(&security, dir_ni, &gid, &dsetgid);
658 #endif
659 if (S_ISDIR(type))
660 perm = (typemode & ~ctx->dmask & 0777)
661 | (dsetgid & S_ISGID);
662 else
663 if ((ctx->special_files == NTFS_FILES_WSL)
664 && S_ISLNK(type))
665 perm = typemode | 0777;
666 else
667 perm = typemode & ~ctx->fmask & 0777;
668 /*
669 * Try to get a security id available for
670 * file creation (from inheritance or argument).
671 * This is not possible for NTFS 1.x, and we will
672 * have to build a security attribute later.
673 */
674 if (!security.mapping[MAPUSERS])
675 securid = const_cpu_to_le32(0);
676 else
677 if (ctx->inherit)
678 securid = ntfs_inherited_id(&security,
679 dir_ni, S_ISDIR(type));
680 else
681 #if POSIXACLS
682 securid = ntfs_alloc_securid(&security,
683 security.uid, gid,
684 dir_ni, perm, S_ISDIR(type));
685 #else
686 securid = ntfs_alloc_securid(&security,
687 security.uid, gid,
688 perm & ~security.umask, S_ISDIR(type));
689 #endif
690 /* Create object specified in @type. */
691 if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
692 #ifndef DISABLE_PLUGINS
693 const plugin_operations_t *ops;
694 REPARSE_POINT *reparse;
695
696 reparse = (REPARSE_POINT*)NULL;
697 ops = select_reparse_plugin(ctx, dir_ni, &reparse);
698 if (ops && ops->create) {
699 ni = (*ops->create)(dir_ni, reparse,
700 securid, uname, uname_len, type);
701 } else {
702 ni = (ntfs_inode*)NULL;
703 errno = EOPNOTSUPP;
704 }
705 free(reparse);
706 #else /* DISABLE_PLUGINS */
707 ni = (ntfs_inode*)NULL;
708 errno = EOPNOTSUPP;
709 res = -errno;
710 #endif /* DISABLE_PLUGINS */
711 } else {
712 switch (type) {
713 case S_IFCHR:
714 case S_IFBLK:
715 ni = ntfs_create_device(dir_ni, securid,
716 uname, uname_len,
717 type, dev);
718 break;
719 case S_IFLNK:
720 utarget_len = ntfs_mbstoucs(target,
721 &utarget);
722 if (utarget_len < 0) {
723 res = -errno;
724 goto exit;
725 }
726 ni = ntfs_create_symlink(dir_ni,
727 securid,
728 uname, uname_len,
729 utarget, utarget_len);
730 break;
731 default:
732 ni = ntfs_create(dir_ni, securid, uname,
733 uname_len, type);
734 break;
735 }
736 }
737 if (ni) {
738 /*
739 * set the security attribute if a security id
740 * could not be allocated (eg NTFS 1.x)
741 */
742 if (security.mapping[MAPUSERS]) {
743 #if POSIXACLS
744 if (!securid
745 && ntfs_set_inherited_posix(&security, ni,
746 security.uid, gid,
747 dir_ni, perm) < 0)
748 set_fuse_error(&res);
749 #else
750 if (!securid
751 && ntfs_set_owner_mode(&security, ni,
752 security.uid, gid,
753 perm & ~security.umask) < 0)
754 set_fuse_error(&res);
755 #endif
756 }
757 set_archive(ni);
758 /* mark a need to compress the end of file */
759 if (fi && (ni->flags & FILE_ATTR_COMPRESSED)) {
760 state |= CLOSE_COMPRESSED;
761 }
762 #ifdef HAVE_SETXATTR /* extended attributes interface required */
763 /* mark a future need to fixup encrypted inode */
764 if (fi
765 && ctx->efs_raw
766 && (ni->flags & FILE_ATTR_ENCRYPTED))
767 state |= CLOSE_ENCRYPTED;
768 #endif /* HAVE_SETXATTR */
769 if (fi && ctx->dmtime)
770 state |= CLOSE_DMTIME;
771 ntfs_inode_update_mbsname(dir_ni, name, ni->mft_no);
772 NInoSetDirty(ni);
773 *ino = ni->mft_no;
774 #ifndef __HAIKU__
775 e->ino = ni->mft_no;
776 e->generation = 1;
777 e->attr_timeout = ATTR_TIMEOUT;
778 e->entry_timeout = ENTRY_TIMEOUT;
779 res = ntfs_fuse_getstat(&security, ni, &e->attr);
780 #endif
781 /*
782 * closing ni requires access to dir_ni to
783 * synchronize the index, avoid double opening.
784 */
785 if (ntfs_inode_close_in_dir(ni, dir_ni))
786 set_fuse_error(&res);
787 ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME);
788 } else
789 res = -errno;
790 #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
791 } else
792 res = -errno;
793 #endif
794
795 exit:
796 free(uname);
797 if (ntfs_inode_close(dir_ni))
798 set_fuse_error(&res);
799 if (utarget)
800 free(utarget);
801 #ifndef __HAIKU__
802 if ((res >= 0) && fi) {
803 of = (struct open_file*)malloc(sizeof(struct open_file));
804 if (of) {
805 of->parent = 0;
806 of->ino = e->ino;
807 of->state = state;
808 of->next = ctx->open_files;
809 of->previous = (struct open_file*)NULL;
810 if (ctx->open_files)
811 ctx->open_files->previous = of;
812 ctx->open_files = of;
813 fi->fh = (long)of;
814 }
815 }
816 #else
817 // FIXME: store "state" somewhere
818 #endif
819 return res;
820 }
821
ntfs_fuse_newlink(struct lowntfs_context * ctx,ino_t ino,ino_t newparent,const char * newname,struct fuse_entry_param * e)822 static int ntfs_fuse_newlink(struct lowntfs_context *ctx,
823 ino_t ino, ino_t newparent,
824 const char *newname, struct fuse_entry_param *e)
825 {
826 ntfschar *uname = NULL;
827 ntfs_inode *dir_ni = NULL, *ni;
828 int res = 0, uname_len;
829 struct SECURITY_CONTEXT security;
830
831 /* Open file for which create hard link. */
832 ni = ntfs_inode_open(ctx->vol, INODE(ino));
833 if (!ni) {
834 res = -errno;
835 goto exit;
836 }
837
838 /* Do not accept linking to a directory (except for renaming) */
839 if (e && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
840 errno = EPERM;
841 res = -errno;
842 goto exit;
843 }
844 /* Generate unicode filename. */
845 uname_len = ntfs_mbstoucs(newname, &uname);
846 if ((uname_len < 0)
847 || (ctx->windows_names
848 && ntfs_forbidden_names(ctx->vol,uname,uname_len,TRUE))) {
849 res = -errno;
850 goto exit;
851 }
852 /* Open parent directory. */
853 dir_ni = ntfs_inode_open(ctx->vol, INODE(newparent));
854 if (!dir_ni) {
855 res = -errno;
856 goto exit;
857 }
858
859 #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
860 /* make sure the target parent directory is writeable */
861 if (ntfs_fuse_fill_security_context(ctx, &security)
862 && !ntfs_allowed_access(&security,dir_ni,S_IWRITE + S_IEXEC))
863 res = -EACCES;
864 else
865 #else
866 ntfs_fuse_fill_security_context(ctx, &security);
867 #endif
868 {
869 if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
870 #ifndef DISABLE_PLUGINS
871 const plugin_operations_t *ops;
872 REPARSE_POINT *reparse;
873
874 res = CALL_REPARSE_PLUGIN(dir_ni, link,
875 ni, uname, uname_len);
876 if (res < 0)
877 goto exit;
878 #else /* DISABLE_PLUGINS */
879 res = -EOPNOTSUPP;
880 goto exit;
881 #endif /* DISABLE_PLUGINS */
882 } else {
883 if (ntfs_link(ni, dir_ni, uname, uname_len)) {
884 res = -errno;
885 goto exit;
886 }
887 }
888 ntfs_inode_update_mbsname(dir_ni, newname, ni->mft_no);
889 #ifndef __HAIKU__
890 if (e) {
891 e->ino = ni->mft_no;
892 e->generation = 1;
893 e->attr_timeout = ATTR_TIMEOUT;
894 e->entry_timeout = ENTRY_TIMEOUT;
895 res = ntfs_fuse_getstat(&security, ni, &e->attr);
896 }
897 #endif
898 set_archive(ni);
899 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
900 ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME);
901 }
902 exit:
903 /*
904 * Must close dir_ni first otherwise ntfs_inode_sync_file_name(ni)
905 * may fail because ni may not be in parent's index on the disk yet.
906 */
907 if (ntfs_inode_close(dir_ni))
908 set_fuse_error(&res);
909 if (ntfs_inode_close(ni))
910 set_fuse_error(&res);
911 free(uname);
912 return (res);
913 }
914
915
916 int
ntfs_fuse_rm(struct lowntfs_context * ctx,ino_t parent,const char * name,enum RM_TYPES rm_type)917 ntfs_fuse_rm(struct lowntfs_context *ctx, ino_t parent, const char *name,
918 enum RM_TYPES rm_type)
919 {
920 ntfschar *uname = NULL;
921 ntfschar *ugname;
922 ntfs_inode *dir_ni = NULL, *ni = NULL;
923 int res = 0, uname_len;
924 int ugname_len;
925 u64 iref;
926 ino_t ino;
927 char ghostname[GHOSTLTH];
928 #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
929 struct SECURITY_CONTEXT security;
930 #endif
931 #if defined(__sun) && defined (__SVR4)
932 int isdir;
933 #endif /* defined(__sun) && defined (__SVR4) */
934 int no_check_open = (rm_type & RM_NO_CHECK_OPEN) != 0;
935 rm_type &= ~RM_NO_CHECK_OPEN;
936
937 /* Deny removing from $Extend */
938 if (parent == FILE_Extend) {
939 res = -EPERM;
940 goto exit;
941 }
942 /* Open parent directory. */
943 dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
944 if (!dir_ni) {
945 res = -errno;
946 goto exit;
947 }
948 /* Generate unicode filename. */
949 uname_len = ntfs_mbstoucs(name, &uname);
950 if (uname_len < 0) {
951 res = -errno;
952 goto exit;
953 }
954 /* Open object for delete. */
955 iref = ntfs_inode_lookup_by_mbsname(dir_ni, name);
956 if (iref == (u64)-1) {
957 res = -errno;
958 goto exit;
959 }
960 ino = (ino_t)MREF(iref);
961 /* deny unlinking metadata files */
962 if (ino < FILE_first_user) {
963 errno = EPERM;
964 res = -errno;
965 goto exit;
966 }
967
968 ni = ntfs_inode_open(ctx->vol, ino);
969 if (!ni) {
970 res = -errno;
971 goto exit;
972 }
973
974 #if defined(__sun) && defined (__SVR4)
975 /* on Solaris : deny unlinking directories */
976 isdir = ni->mrec->flags & MFT_RECORD_IS_DIRECTORY;
977 #ifndef DISABLE_PLUGINS
978 /* get emulated type from plugin if available */
979 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
980 struct stat st;
981 const plugin_operations_t *ops;
982 REPARSE_POINT *reparse;
983
984 /* Avoid double opening of parent directory */
985 res = ntfs_inode_close(dir_ni);
986 if (res)
987 goto exit;
988 dir_ni = (ntfs_inode*)NULL;
989 res = CALL_REPARSE_PLUGIN(ni, getattr, &st);
990 if (res)
991 goto exit;
992 isdir = S_ISDIR(st.st_mode);
993 dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
994 if (!dir_ni) {
995 res = -errno;
996 goto exit;
997 }
998 }
999 #endif /* DISABLE_PLUGINS */
1000 if (rm_type == (isdir ? RM_LINK : RM_DIR)) {
1001 errno = (isdir ? EISDIR : ENOTDIR);
1002 res = -errno;
1003 goto exit;
1004 }
1005 #endif /* defined(__sun) && defined (__SVR4) */
1006
1007 #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1008 /* JPA deny unlinking if directory is not writable and executable */
1009 if (ntfs_fuse_fill_security_context(ctx, &security)
1010 && !ntfs_allowed_dir_access(&security, dir_ni, ino, ni,
1011 S_IEXEC + S_IWRITE + S_ISVTX)) {
1012 errno = EACCES;
1013 res = -errno;
1014 goto exit;
1015 }
1016 #endif
1017 #ifndef __HAIKU__
1018 /*
1019 * We keep one open_file record per opening, to avoid
1020 * having to check the list of open files when opening
1021 * and closing (which are more frequent than unlinking).
1022 * As a consequence, we may have to create several
1023 * ghosts names for the same file.
1024 * The file may have been opened with a different name
1025 * in a different parent directory. The ghost is
1026 * nevertheless created in the parent directory of the
1027 * name being unlinked, and permissions to do so are the
1028 * same as required for unlinking.
1029 */
1030 for (of=ctx->open_files; of; of = of->next) {
1031 if ((of->ino == ino) && !(of->state & CLOSE_GHOST)) {
1032 #else
1033 int* close_state = NULL;
1034 if (!no_check_open) {
1035 close_state = ntfs_haiku_get_close_state(ctx, ino);
1036 if (close_state && (*close_state & CLOSE_GHOST) == 0) {
1037 #endif
1038 /* file was open, create a ghost in unlink parent */
1039 ntfs_inode *gni;
1040 u64 gref;
1041
1042 /* ni has to be closed for linking ghost */
1043 if (ni) {
1044 if (ntfs_inode_close(ni)) {
1045 res = -errno;
1046 goto exit;
1047 }
1048 ni = (ntfs_inode*)NULL;
1049 }
1050 *close_state |= CLOSE_GHOST;
1051 u64 ghost = ++ctx->latest_ghost;
1052
1053 sprintf(ghostname,ghostformat,ghost);
1054 /* Generate unicode filename. */
1055 ugname = (ntfschar*)NULL;
1056 ugname_len = ntfs_mbstoucs(ghostname, &ugname);
1057 if (ugname_len < 0) {
1058 res = -errno;
1059 goto exit;
1060 }
1061 /* sweep existing ghost if any, ignoring errors */
1062 gref = ntfs_inode_lookup_by_mbsname(dir_ni, ghostname);
1063 if (gref != (u64)-1) {
1064 gni = ntfs_inode_open(ctx->vol, MREF(gref));
1065 ntfs_delete(ctx->vol, (char*)NULL, gni, dir_ni,
1066 ugname, ugname_len);
1067 /* ntfs_delete() always closes gni and dir_ni */
1068 dir_ni = (ntfs_inode*)NULL;
1069 } else {
1070 if (ntfs_inode_close(dir_ni)) {
1071 res = -errno;
1072 goto out;
1073 }
1074 dir_ni = (ntfs_inode*)NULL;
1075 }
1076 free(ugname);
1077 res = ntfs_fuse_newlink(ctx, ino, parent, ghostname,
1078 (struct fuse_entry_param*)NULL);
1079 if (res)
1080 goto out;
1081
1082 #ifdef __HAIKU__
1083 // We have to do this before the parent directory is reopened.
1084 ntfs_haiku_put_close_state(ctx, ino, ghost);
1085 close_state = NULL;
1086 #endif
1087
1088 /* now reopen then parent directory */
1089 dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
1090 if (!dir_ni) {
1091 res = -errno;
1092 goto exit;
1093 }
1094 }
1095 }
1096 if (!ni) {
1097 ni = ntfs_inode_open(ctx->vol, ino);
1098 if (!ni) {
1099 res = -errno;
1100 goto exit;
1101 }
1102 }
1103 if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
1104 #ifndef DISABLE_PLUGINS
1105 const plugin_operations_t *ops;
1106 REPARSE_POINT *reparse;
1107
1108 res = CALL_REPARSE_PLUGIN(dir_ni, unlink, (char*)NULL,
1109 ni, uname, uname_len);
1110 #else /* DISABLE_PLUGINS */
1111 errno = EOPNOTSUPP;
1112 res = -errno;
1113 #endif /* DISABLE_PLUGINS */
1114 } else {
1115 if (ntfs_delete(ctx->vol, (char*)NULL, ni, dir_ni,
1116 uname, uname_len))
1117 res = -errno;
1118 /* ntfs_delete() always closes ni and dir_ni */
1119 }
1120 ni = dir_ni = NULL;
1121 exit:
1122 if (ntfs_inode_close(ni) && !res)
1123 res = -errno;
1124 if (ntfs_inode_close(dir_ni) && !res)
1125 res = -errno;
1126 out :
1127 #ifdef __HAIKU__
1128 if (close_state)
1129 ntfs_haiku_put_close_state(ctx, ino, -1);
1130 #endif
1131 free(uname);
1132 return res;
1133 }
1134
1135 int ntfs_fuse_release(struct lowntfs_context *ctx, ino_t parent, ino_t ino, int state, u64 ghost)
1136 {
1137 ntfs_inode *ni = NULL;
1138 ntfs_attr *na = NULL;
1139 char ghostname[GHOSTLTH];
1140 int res;
1141
1142 /* Only for marked descriptors there is something to do */
1143 if (!(state & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED
1144 | CLOSE_DMTIME | CLOSE_REPARSE))) {
1145 res = 0;
1146 goto out;
1147 }
1148 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1149 if (!ni) {
1150 res = -errno;
1151 goto exit;
1152 }
1153 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
1154 #ifndef DISABLE_PLUGINS
1155 const plugin_operations_t *ops;
1156 REPARSE_POINT *reparse;
1157
1158 res = CALL_REPARSE_PLUGIN(ni, release, &of->fi);
1159 if (!res) {
1160 goto stamps;
1161 }
1162 #else /* DISABLE_PLUGINS */
1163 /* Assume release() was not needed */
1164 res = 0;
1165 #endif /* DISABLE_PLUGINS */
1166 goto exit;
1167 }
1168 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
1169 if (!na) {
1170 res = -errno;
1171 goto exit;
1172 }
1173 res = 0;
1174 if (state & CLOSE_COMPRESSED)
1175 res = ntfs_attr_pclose(na);
1176 #ifdef HAVE_SETXATTR /* extended attributes interface required */
1177 if (of->state & CLOSE_ENCRYPTED)
1178 res = ntfs_efs_fixup_attribute(NULL, na);
1179 #endif /* HAVE_SETXATTR */
1180 #ifndef DISABLE_PLUGINS
1181 stamps :
1182 #endif /* DISABLE_PLUGINS */
1183 if (state & CLOSE_DMTIME)
1184 ntfs_inode_update_times(ni,NTFS_UPDATE_MCTIME);
1185 exit:
1186 if (na)
1187 ntfs_attr_close(na);
1188 if (ntfs_inode_close(ni))
1189 set_fuse_error(&res);
1190 out:
1191 /* remove the associate ghost file (even if release failed) */
1192 if (1) {
1193 if (state & CLOSE_GHOST) {
1194 sprintf(ghostname,ghostformat,ghost);
1195 ntfs_fuse_rm(ctx, parent, ghostname, RM_ANY | RM_NO_CHECK_OPEN);
1196 }
1197 #ifndef __HAIKU__
1198 /* remove from open files list */
1199 if (of->next)
1200 of->next->previous = of->previous;
1201 if (of->previous)
1202 of->previous->next = of->next;
1203 else
1204 ctx->open_files = of->next;
1205 free(of);
1206 #endif
1207 }
1208 #ifndef __HAIKU__
1209 if (res)
1210 fuse_reply_err(req, -res);
1211 else
1212 fuse_reply_err(req, 0);
1213 #endif
1214 return res;
1215 }
1216
1217 static int ntfs_fuse_safe_rename(struct lowntfs_context *ctx, ino_t ino,
1218 ino_t parent, const char *name, ino_t xino,
1219 ino_t newparent, const char *newname,
1220 const char *tmp)
1221 {
1222 int ret;
1223
1224 ntfs_log_trace("Entering\n");
1225
1226 ret = ntfs_fuse_newlink(ctx, xino, newparent, tmp,
1227 (struct fuse_entry_param*)NULL);
1228 if (ret)
1229 return ret;
1230
1231 ret = ntfs_fuse_rm(ctx, newparent, newname, RM_ANY);
1232 if (!ret) {
1233
1234 ret = ntfs_fuse_newlink(ctx, ino, newparent, newname,
1235 (struct fuse_entry_param*)NULL);
1236 if (ret)
1237 goto restore;
1238
1239 ret = ntfs_fuse_rm(ctx, parent, name, RM_ANY | RM_NO_CHECK_OPEN);
1240 if (ret) {
1241 if (ntfs_fuse_rm(ctx, newparent, newname, RM_ANY))
1242 goto err;
1243 goto restore;
1244 }
1245 }
1246
1247 goto cleanup;
1248 restore:
1249 if (ntfs_fuse_newlink(ctx, xino, newparent, newname,
1250 (struct fuse_entry_param*)NULL)) {
1251 err:
1252 ntfs_log_perror("Rename failed. Existing file '%s' was renamed "
1253 "to '%s'", newname, tmp);
1254 } else {
1255 cleanup:
1256 /*
1257 * Condition for this unlink has already been checked in
1258 * "ntfs_fuse_rename_existing_dest()", so it should never
1259 * fail (unless concurrent access to directories when fuse
1260 * is multithreaded)
1261 */
1262 if (ntfs_fuse_rm(ctx, newparent, tmp, RM_ANY) < 0)
1263 ntfs_log_perror("Rename failed. Existing file '%s' still present "
1264 "as '%s'", newname, tmp);
1265 }
1266 return ret;
1267 }
1268
1269 static int ntfs_fuse_rename_existing_dest(struct lowntfs_context *ctx, ino_t ino,
1270 ino_t parent, const char *name,
1271 ino_t xino, ino_t newparent,
1272 const char *newname)
1273 {
1274 int ret, len;
1275 char *tmp;
1276 const char *ext = ".ntfs-3g-";
1277 #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1278 ntfs_inode *newdir_ni;
1279 struct SECURITY_CONTEXT security;
1280 #endif
1281
1282 ntfs_log_trace("Entering\n");
1283
1284 len = strlen(newname) + strlen(ext) + 10 + 1; /* wc(str(2^32)) + \0 */
1285 tmp = (char*)ntfs_malloc(len);
1286 if (!tmp)
1287 return -errno;
1288
1289 ret = snprintf(tmp, len, "%s%s%010d", newname, ext, ++ntfs_sequence);
1290 if (ret != len - 1) {
1291 ntfs_log_error("snprintf failed: %d != %d\n", ret, len - 1);
1292 ret = -EOVERFLOW;
1293 } else {
1294 #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1295 /*
1296 * Make sure existing dest can be removed.
1297 * This is only needed if parent directory is
1298 * sticky, because in this situation condition
1299 * for unlinking is different from condition for
1300 * linking
1301 */
1302 newdir_ni = ntfs_inode_open(ctx->vol, INODE(newparent));
1303 if (newdir_ni) {
1304 if (!ntfs_fuse_fill_security_context(ctx,&security)
1305 || ntfs_allowed_dir_access(&security, newdir_ni,
1306 xino, (ntfs_inode*)NULL,
1307 S_IEXEC + S_IWRITE + S_ISVTX)) {
1308 if (ntfs_inode_close(newdir_ni))
1309 ret = -errno;
1310 else
1311 ret = ntfs_fuse_safe_rename(ctx, ino,
1312 parent, name, xino,
1313 newparent, newname,
1314 tmp);
1315 } else {
1316 ntfs_inode_close(newdir_ni);
1317 ret = -EACCES;
1318 }
1319 } else
1320 ret = -errno;
1321 #else
1322 ret = ntfs_fuse_safe_rename(ctx, ino, parent, name,
1323 xino, newparent, newname, tmp);
1324 #endif
1325 }
1326 free(tmp);
1327 return ret;
1328 }
1329
1330
1331 int ntfs_fuse_rename(struct lowntfs_context *ctx, ino_t parent,
1332 const char *name, ino_t newparent,
1333 const char *newname)
1334 {
1335 int ret;
1336 ino_t ino;
1337 ino_t xino;
1338 ntfs_inode *ni;
1339
1340 ntfs_log_debug("rename: old: '%s' new: '%s'\n", name, newname);
1341
1342 /*
1343 * FIXME: Rename should be atomic.
1344 */
1345
1346 ino = ntfs_fuse_inode_lookup(ctx, parent, name);
1347 if (ino == (ino_t)-1) {
1348 ret = -errno;
1349 goto out;
1350 }
1351 /* Check whether target is present */
1352 xino = ntfs_fuse_inode_lookup(ctx, newparent, newname);
1353 if (xino != (ino_t)-1) {
1354 /*
1355 * Target exists : no need to check whether it
1356 * designates the same inode, this has already
1357 * been checked (by fuse ?)
1358 */
1359 ni = ntfs_inode_open(ctx->vol, INODE(xino));
1360 if (!ni)
1361 ret = -errno;
1362 else {
1363 ret = ntfs_check_empty_dir(ni);
1364 if (ret < 0) {
1365 ret = -errno;
1366 ntfs_inode_close(ni);
1367 goto out;
1368 }
1369
1370 if (ntfs_inode_close(ni)) {
1371 set_fuse_error(&ret);
1372 goto out;
1373 }
1374 ret = ntfs_fuse_rename_existing_dest(ctx, ino, parent,
1375 name, xino, newparent, newname);
1376 }
1377 } else {
1378 /* target does not exist */
1379 ret = ntfs_fuse_newlink(ctx, ino, newparent, newname,
1380 (struct fuse_entry_param*)NULL);
1381 if (ret)
1382 goto out;
1383
1384 ret = ntfs_fuse_rm(ctx, parent, name, RM_ANY | RM_NO_CHECK_OPEN);
1385 if (ret)
1386 ntfs_fuse_rm(ctx, newparent, newname, RM_ANY);
1387 }
1388 out:
1389 #ifndef __HAIKU__
1390 if (ret)
1391 fuse_reply_err(req, -ret);
1392 else
1393 fuse_reply_err(req, 0);
1394 #endif
1395 return ret;
1396 }
1397