xref: /haiku/src/add-ons/kernel/file_systems/ntfs/lowntfs.c (revision 5b62dce3a6656cb4778a79458a7022857fa92bad)
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