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