xref: /illumos-gate/usr/src/uts/common/syscall/stat.c (revision 8fd04b83)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 /*
36  * Get file attribute information through a file name or a file descriptor.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/isa_defs.h>
41 #include <sys/types.h>
42 #include <sys/sysmacros.h>
43 #include <sys/cred.h>
44 #include <sys/systm.h>
45 #include <sys/errno.h>
46 #include <sys/fcntl.h>
47 #include <sys/pathname.h>
48 #include <sys/stat.h>
49 #include <sys/vfs.h>
50 #include <sys/vnode.h>
51 #include <sys/mode.h>
52 #include <sys/file.h>
53 #include <sys/proc.h>
54 #include <sys/uio.h>
55 #include <sys/debug.h>
56 #include <sys/cmn_err.h>
57 #include <c2/audit.h>
58 #include <fs/fs_subr.h>
59 
60 /*
61  * Get the vp to be stated and the cred to be used for the call
62  * to VOP_GETATTR
63  */
64 
65 static int
66 cstatat_getvp(int fd, char *name, int follow, vnode_t **vp, cred_t **cred)
67 {
68 	vnode_t *startvp;
69 	file_t *fp;
70 	int error;
71 	cred_t *cr;
72 	int estale_retry = 0;
73 
74 	*vp = NULL;
75 
76 	/*
77 	 * Only return EFAULT for fstatat when fd == AT_FDCWD && name == NULL
78 	 */
79 
80 	if (fd == AT_FDCWD) {
81 		startvp = NULL;
82 		cr = CRED();
83 		crhold(cr);
84 	} else {
85 		char startchar;
86 
87 		if (copyin(name, &startchar, sizeof (char)))
88 			return (EFAULT);
89 		if (startchar != '/') {
90 			if ((fp = getf(fd)) == NULL) {
91 				return (EBADF);
92 			}
93 			startvp = fp->f_vnode;
94 			cr = fp->f_cred;
95 			crhold(cr);
96 			VN_HOLD(startvp);
97 			releasef(fd);
98 		} else {
99 			startvp = NULL;
100 			cr = CRED();
101 			crhold(cr);
102 		}
103 	}
104 	*cred = cr;
105 
106 	if (audit_active)
107 		audit_setfsat_path(1);
108 
109 lookup:
110 	if (error = lookupnameat(name, UIO_USERSPACE, follow, NULLVPP,
111 	    vp, startvp)) {
112 		if ((error == ESTALE) &&
113 		    fs_need_estale_retry(estale_retry++))
114 			goto lookup;
115 		if (startvp != NULL)
116 			VN_RELE(startvp);
117 		crfree(cr);
118 		return (error);
119 	}
120 	if (startvp != NULL)
121 		VN_RELE(startvp);
122 
123 	return (0);
124 }
125 
126 /*
127  * Native syscall interfaces:
128  *
129  * N-bit kernel, N-bit applications, N-bit file offsets
130  */
131 
132 static int cstatat(int, char *, struct stat *, int, int);
133 static int cstat(vnode_t *vp, struct stat *, int, cred_t *);
134 
135 /*
136  * fstat can and should be fast, do an inline implementation here.
137  */
138 #define	FSTAT_BODY(fd, sb, statfn)				\
139 	{							\
140 		file_t *fp;					\
141 		int error;					\
142 								\
143 		if (fd == AT_FDCWD)				\
144 			return (set_errno(EFAULT));		\
145 		if ((fp = getf(fd)) == NULL)			\
146 			return (set_errno(EBADF));		\
147 		if (audit_active)				\
148 			audit_setfsat_path(1);			\
149 		error = statfn(fp->f_vnode, sb, 0, fp->f_cred);	\
150 		releasef(fd);					\
151 		if (error)					\
152 			return (set_errno(error));		\
153 		return (0);					\
154 	}
155 
156 int
157 fstat(int fd, struct stat *sb)
158 {
159 	FSTAT_BODY(fd, sb, cstat)
160 }
161 
162 int
163 fstatat(int fd, char *name, struct stat *sb, int flags)
164 {
165 	int followflag;
166 	int csflags;
167 
168 	if (name == NULL)
169 		return (fstat(fd, sb));
170 
171 	followflag = (flags & AT_SYMLINK_NOFOLLOW);
172 	csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
173 	if (followflag == 0)
174 		csflags |= ATTR_REAL;	/* flag for procfs lookups */
175 
176 	return (cstatat(fd, name, sb, followflag, csflags));
177 }
178 
179 int
180 stat(char *name, struct stat *sb)
181 {
182 	return (fstatat(AT_FDCWD, name, sb, 0));
183 }
184 
185 int
186 lstat(char *name, struct stat *sb)
187 {
188 	return (fstatat(AT_FDCWD, name, sb, AT_SYMLINK_NOFOLLOW));
189 }
190 
191 /*
192  * Common code for stat(), lstat(), and fstat().
193  * (32-bit kernel, 32-bit applications, 32-bit files)
194  * (64-bit kernel, 64-bit applications, 64-bit files)
195  */
196 static int
197 cstat(vnode_t *vp, struct stat *ubp, int flag, cred_t *cr)
198 {
199 	struct vfssw *vswp;
200 	struct stat sb;
201 	vattr_t vattr;
202 	int error;
203 
204 	vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
205 	if ((error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) != 0)
206 		return (error);
207 #ifdef	_ILP32
208 	/*
209 	 * (32-bit kernel, 32-bit applications, 32-bit files)
210 	 * NOTE: 32-bit kernel maintains a 64-bit unsigend va_size.
211 	 *
212 	 * st_size of devices (VBLK and VCHR special files) is a special case.
213 	 * POSIX does not define size behavior for special files, so the
214 	 * following Solaris specific behavior is not a violation. Solaris
215 	 * returns the size of the device.
216 	 *
217 	 * For compatibility with 32-bit programs which happen to do stat() on
218 	 * a (mknod) bigger than 2GB we suppress the large file EOVERFLOW and
219 	 * instead we return the value MAXOFF32_T (LONG_MAX).
220 	 *
221 	 * 32-bit applications that care about the size of devices should be
222 	 * built 64-bit or use a large file interface (lfcompile(5) or lf64(5)).
223 	 */
224 	if ((vattr.va_size > MAXOFF32_T) &&
225 	    ((vp->v_type == VBLK) || (vp->v_type == VCHR))) {
226 		/* OVERFLOW | UNKNOWN_SIZE */
227 		vattr.va_size = MAXOFF32_T;
228 	}
229 #endif	/* _ILP32 */
230 	if (vattr.va_size > MAXOFF_T || vattr.va_nblocks > LONG_MAX ||
231 	    vattr.va_nodeid > ULONG_MAX)
232 		return (EOVERFLOW);
233 
234 	bzero(&sb, sizeof (sb));
235 	sb.st_dev = vattr.va_fsid;
236 	sb.st_ino = (ino_t)vattr.va_nodeid;
237 	sb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
238 	sb.st_nlink = vattr.va_nlink;
239 	sb.st_uid = vattr.va_uid;
240 	sb.st_gid = vattr.va_gid;
241 	sb.st_rdev = vattr.va_rdev;
242 	sb.st_size = (off_t)vattr.va_size;
243 	sb.st_atim = vattr.va_atime;
244 	sb.st_mtim = vattr.va_mtime;
245 	sb.st_ctim = vattr.va_ctime;
246 	sb.st_blksize = vattr.va_blksize;
247 	sb.st_blocks = (blkcnt_t)vattr.va_nblocks;
248 	if (vp->v_vfsp != NULL) {
249 		vswp = &vfssw[vp->v_vfsp->vfs_fstype];
250 		if (vswp->vsw_name && *vswp->vsw_name)
251 			(void) strcpy(sb.st_fstype, vswp->vsw_name);
252 	}
253 	if (copyout(&sb, ubp, sizeof (sb)))
254 		return (EFAULT);
255 	return (0);
256 }
257 
258 static int
259 cstatat(int fd, char *name, struct stat *sb, int follow, int flags)
260 {
261 	vnode_t *vp;
262 	int error;
263 	cred_t *cred;
264 	int link_follow;
265 	int estale_retry = 0;
266 
267 	link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
268 lookup:
269 	if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
270 		return (set_errno(error));
271 	error = cstat(vp, sb, flags, cred);
272 	crfree(cred);
273 	VN_RELE(vp);
274 	if (error != 0) {
275 		if (error == ESTALE &&
276 		    fs_need_estale_retry(estale_retry++))
277 			goto lookup;
278 		return (set_errno(error));
279 	}
280 	return (0);
281 }
282 
283 #if defined(_SYSCALL32_IMPL)
284 
285 /*
286  * 64-bit kernel, 32-bit applications, 32-bit file offsets
287  */
288 static int cstatat32(int, char *, struct stat32 *, int, int);
289 static int cstat32(vnode_t *, struct stat32 *, int, cred_t *);
290 
291 int
292 fstat32(int fd, struct stat32 *sb)
293 {
294 	FSTAT_BODY(fd, sb, cstat32)
295 }
296 
297 int
298 fstatat32(int fd, char *name, struct stat32 *sb, int flags)
299 {
300 	int followflag;
301 	int csflags;
302 
303 	if (name == NULL)
304 		return (fstat32(fd, sb));
305 
306 	followflag = (flags & AT_SYMLINK_NOFOLLOW);
307 	csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
308 	if (followflag == 0)
309 		csflags |= ATTR_REAL;	/* flag for procfs lookups */
310 
311 	return (cstatat32(fd, name, sb, followflag, csflags));
312 }
313 
314 int
315 stat32(char *name, struct stat32 *sb)
316 {
317 	return (fstatat32(AT_FDCWD, name, sb, 0));
318 }
319 
320 int
321 lstat32(char *name, struct stat32 *sb)
322 {
323 	return (fstatat32(AT_FDCWD, name, sb, AT_SYMLINK_NOFOLLOW));
324 }
325 
326 static int
327 cstat32(vnode_t *vp, struct stat32 *ubp, int flag, struct cred *cr)
328 {
329 	struct vfssw *vswp;
330 	struct stat32 sb;
331 	vattr_t vattr;
332 	int error;
333 	dev32_t st_dev, st_rdev;
334 
335 	vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
336 	if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
337 		return (error);
338 
339 	/* devices are a special case, see comments in cstat */
340 	if ((vattr.va_size > MAXOFF32_T) &&
341 	    ((vp->v_type == VBLK) || (vp->v_type == VCHR))) {
342 		/* OVERFLOW | UNKNOWN_SIZE */
343 		vattr.va_size = MAXOFF32_T;
344 	}
345 
346 	/* check for large values */
347 	if (!cmpldev(&st_dev, vattr.va_fsid) ||
348 	    !cmpldev(&st_rdev, vattr.va_rdev) ||
349 	    vattr.va_size > MAXOFF32_T ||
350 	    vattr.va_nblocks > INT32_MAX ||
351 	    vattr.va_nodeid > UINT32_MAX ||
352 	    TIMESPEC_OVERFLOW(&(vattr.va_atime)) ||
353 	    TIMESPEC_OVERFLOW(&(vattr.va_mtime)) ||
354 	    TIMESPEC_OVERFLOW(&(vattr.va_ctime)))
355 		return (EOVERFLOW);
356 
357 	bzero(&sb, sizeof (sb));
358 	sb.st_dev = st_dev;
359 	sb.st_ino = (ino32_t)vattr.va_nodeid;
360 	sb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
361 	sb.st_nlink = vattr.va_nlink;
362 	sb.st_uid = vattr.va_uid;
363 	sb.st_gid = vattr.va_gid;
364 	sb.st_rdev = st_rdev;
365 	sb.st_size = (off32_t)vattr.va_size;
366 	TIMESPEC_TO_TIMESPEC32(&(sb.st_atim), &(vattr.va_atime));
367 	TIMESPEC_TO_TIMESPEC32(&(sb.st_mtim), &(vattr.va_mtime));
368 	TIMESPEC_TO_TIMESPEC32(&(sb.st_ctim), &(vattr.va_ctime));
369 	sb.st_blksize = vattr.va_blksize;
370 	sb.st_blocks = (blkcnt32_t)vattr.va_nblocks;
371 	if (vp->v_vfsp != NULL) {
372 		vswp = &vfssw[vp->v_vfsp->vfs_fstype];
373 		if (vswp->vsw_name && *vswp->vsw_name)
374 			(void) strcpy(sb.st_fstype, vswp->vsw_name);
375 	}
376 	if (copyout(&sb, ubp, sizeof (sb)))
377 		return (EFAULT);
378 	return (0);
379 }
380 
381 static int
382 cstatat32(int fd, char *name, struct stat32 *sb, int follow, int flags)
383 {
384 	vnode_t *vp;
385 	int error;
386 	cred_t *cred;
387 	int link_follow;
388 	int estale_retry = 0;
389 
390 	link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
391 lookup:
392 	if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
393 		return (set_errno(error));
394 	error = cstat32(vp, sb, flags, cred);
395 	crfree(cred);
396 	VN_RELE(vp);
397 	if (error != 0) {
398 		if (error == ESTALE &&
399 		    fs_need_estale_retry(estale_retry++))
400 			goto lookup;
401 		return (set_errno(error));
402 	}
403 	return (0);
404 }
405 
406 #endif	/* _SYSCALL32_IMPL */
407 
408 #if defined(_ILP32)
409 
410 /*
411  * 32-bit kernel, 32-bit applications, 64-bit file offsets.
412  *
413  * These routines are implemented differently on 64-bit kernels.
414  */
415 static int cstatat64(int, char *, struct stat64 *, int, int);
416 static int cstat64(vnode_t *, struct stat64 *, int, cred_t *);
417 
418 int
419 fstat64(int fd, struct stat64 *sb)
420 {
421 	FSTAT_BODY(fd, sb, cstat64)
422 }
423 
424 int
425 fstatat64(int fd, char *name, struct stat64 *sb, int flags)
426 {
427 	int followflag;
428 	int csflags;
429 
430 	if (name == NULL)
431 		return (fstat64(fd, sb));
432 
433 	followflag = (flags & AT_SYMLINK_NOFOLLOW);
434 	csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
435 	if (followflag == 0)
436 		csflags |= ATTR_REAL;	/* flag for procfs lookups */
437 
438 	return (cstatat64(fd, name, sb, followflag, csflags));
439 }
440 
441 int
442 stat64(char *name, struct stat64 *sb)
443 {
444 	return (fstatat64(AT_FDCWD, name, sb, 0));
445 }
446 
447 int
448 lstat64(char *name, struct stat64 *sb)
449 {
450 	return (fstatat64(AT_FDCWD, name, sb, AT_SYMLINK_NOFOLLOW));
451 }
452 
453 static int
454 cstat64(vnode_t *vp, struct stat64 *ubp, int flag, cred_t *cr)
455 {
456 	struct vfssw *vswp;
457 	struct stat64 lsb;
458 	vattr_t vattr;
459 	int error;
460 
461 	vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
462 	if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
463 		return (error);
464 
465 	bzero(&lsb, sizeof (lsb));
466 	lsb.st_dev = vattr.va_fsid;
467 	lsb.st_ino = vattr.va_nodeid;
468 	lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
469 	lsb.st_nlink = vattr.va_nlink;
470 	lsb.st_uid = vattr.va_uid;
471 	lsb.st_gid = vattr.va_gid;
472 	lsb.st_rdev = vattr.va_rdev;
473 	lsb.st_size = vattr.va_size;
474 	lsb.st_atim = vattr.va_atime;
475 	lsb.st_mtim = vattr.va_mtime;
476 	lsb.st_ctim = vattr.va_ctime;
477 	lsb.st_blksize = vattr.va_blksize;
478 	lsb.st_blocks = vattr.va_nblocks;
479 	if (vp->v_vfsp != NULL) {
480 		vswp = &vfssw[vp->v_vfsp->vfs_fstype];
481 		if (vswp->vsw_name && *vswp->vsw_name)
482 			(void) strcpy(lsb.st_fstype, vswp->vsw_name);
483 	}
484 	if (copyout(&lsb, ubp, sizeof (lsb)))
485 		return (EFAULT);
486 	return (0);
487 }
488 
489 static int
490 cstatat64(int fd, char *name, struct stat64 *sb, int follow, int flags)
491 {
492 	vnode_t *vp;
493 	int error;
494 	cred_t *cred;
495 	int link_follow;
496 	int estale_retry = 0;
497 
498 	link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
499 lookup:
500 	if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
501 		return (set_errno(error));
502 	error = cstat64(vp, sb, flags, cred);
503 	crfree(cred);
504 	VN_RELE(vp);
505 	if (error != 0) {
506 		if (error == ESTALE &&
507 		    fs_need_estale_retry(estale_retry++))
508 			goto lookup;
509 		return (set_errno(error));
510 	}
511 	return (0);
512 }
513 
514 #endif	/* _ILP32 */
515 
516 #if defined(_SYSCALL32_IMPL)
517 
518 /*
519  * 64-bit kernel, 32-bit applications, 64-bit file offsets.
520  *
521  * We'd really like to call the "native" stat calls for these ones,
522  * but the problem is that the 64-bit ABI defines the 'stat64' structure
523  * differently from the way the 32-bit ABI defines it.
524  */
525 
526 static int cstatat64_32(int, char *, struct stat64_32 *, int, int);
527 static int cstat64_32(vnode_t *, struct stat64_32 *, int, cred_t *);
528 
529 int
530 fstat64_32(int fd, struct stat64_32 *sb)
531 {
532 	FSTAT_BODY(fd, sb, cstat64_32)
533 }
534 
535 int
536 fstatat64_32(int fd, char *name, struct stat64_32 *sb, int flags)
537 {
538 	int followflag;
539 	int csflags;
540 
541 	if (name == NULL)
542 		return (fstat64_32(fd, sb));
543 
544 	followflag = (flags & AT_SYMLINK_NOFOLLOW);
545 	csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
546 	if (followflag == 0)
547 		csflags |= ATTR_REAL;	/* flag for procfs lookups */
548 
549 	return (cstatat64_32(fd, name, sb, followflag, csflags));
550 }
551 
552 int
553 stat64_32(char *name, struct stat64_32 *sb)
554 {
555 	return (fstatat64_32(AT_FDCWD, name, sb, 0));
556 }
557 
558 int
559 lstat64_32(char *name, struct stat64_32 *sb)
560 {
561 	return (fstatat64_32(AT_FDCWD, name, sb, AT_SYMLINK_NOFOLLOW));
562 }
563 
564 static int
565 cstat64_32(vnode_t *vp, struct stat64_32 *ubp, int flag, cred_t *cr)
566 {
567 	struct vfssw *vswp;
568 	struct stat64_32 lsb;
569 	vattr_t vattr;
570 	int error;
571 	dev32_t st_dev, st_rdev;
572 
573 	vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
574 	if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
575 		return (error);
576 
577 	if (!cmpldev(&st_dev, vattr.va_fsid) ||
578 	    !cmpldev(&st_rdev, vattr.va_rdev) ||
579 	    TIMESPEC_OVERFLOW(&(vattr.va_atime)) ||
580 	    TIMESPEC_OVERFLOW(&(vattr.va_mtime)) ||
581 	    TIMESPEC_OVERFLOW(&(vattr.va_ctime)))
582 		return (EOVERFLOW);
583 
584 	bzero(&lsb, sizeof (lsb));
585 	lsb.st_dev = st_dev;
586 	lsb.st_ino = vattr.va_nodeid;
587 	lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
588 	lsb.st_nlink = vattr.va_nlink;
589 	lsb.st_uid = vattr.va_uid;
590 	lsb.st_gid = vattr.va_gid;
591 	lsb.st_rdev = st_rdev;
592 	lsb.st_size = vattr.va_size;
593 	TIMESPEC_TO_TIMESPEC32(&(lsb.st_atim), &(vattr.va_atime));
594 	TIMESPEC_TO_TIMESPEC32(&(lsb.st_mtim), &(vattr.va_mtime));
595 	TIMESPEC_TO_TIMESPEC32(&(lsb.st_ctim), &(vattr.va_ctime));
596 	lsb.st_blksize = vattr.va_blksize;
597 	lsb.st_blocks = vattr.va_nblocks;
598 	if (vp->v_vfsp != NULL) {
599 		vswp = &vfssw[vp->v_vfsp->vfs_fstype];
600 		if (vswp->vsw_name && *vswp->vsw_name)
601 			(void) strcpy(lsb.st_fstype, vswp->vsw_name);
602 	}
603 	if (copyout(&lsb, ubp, sizeof (lsb)))
604 		return (EFAULT);
605 	return (0);
606 }
607 
608 static int
609 cstatat64_32(int fd, char *name, struct stat64_32 *sb, int follow, int flags)
610 {
611 	vnode_t  *vp;
612 	int error;
613 	cred_t *cred;
614 	int link_follow;
615 	int estale_retry = 0;
616 
617 	link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
618 lookup:
619 	if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
620 		return (set_errno(error));
621 	error = cstat64_32(vp, sb, flags, cred);
622 	crfree(cred);
623 	VN_RELE(vp);
624 	if (error != 0) {
625 		if (error == ESTALE &&
626 		    fs_need_estale_retry(estale_retry++))
627 			goto lookup;
628 		return (set_errno(error));
629 	}
630 	return (0);
631 }
632 
633 #endif /* _SYSCALL32_IMPL */
634