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 52 set_fuse_error(int *err) 53 { 54 if (!*err) 55 *err = errno; 56 } 57 58 static void 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 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 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 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 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 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 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 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 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 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