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.
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.
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]
23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
35 * Get file attribute information through a file name or a file descriptor.
38 #include <sys/param.h>
39 #include <sys/isa_defs.h>
40 #include <sys/types.h>
41 #include <sys/sysmacros.h>
43 #include <sys/systm.h>
44 #include <sys/errno.h>
45 #include <sys/fcntl.h>
46 #include <sys/pathname.h>
49 #include <sys/vnode.h>
54 #include <sys/debug.h>
55 #include <sys/cmn_err.h>
57 #include <fs/fs_subr.h>
60 * Get the vp to be stated and the cred to be used for the call
65 cstatat_getvp(int fd
, char *name
, int follow
, vnode_t
**vp
, cred_t
**cred
)
76 * Only return EFAULT for fstatat when fd == AT_FDCWD && name == NULL
86 if (copyin(name
, &startchar
, sizeof (char)))
88 if (startchar
!= '/') {
89 if ((fp
= getf(fd
)) == NULL
) {
92 startvp
= fp
->f_vnode
;
105 if (AU_AUDITING() && startvp
!= NULL
)
106 audit_setfsat_path(1);
109 if (error
= lookupnameat(name
, UIO_USERSPACE
, follow
, NULLVPP
,
111 if ((error
== ESTALE
) &&
112 fs_need_estale_retry(estale_retry
++))
126 * Native syscall interfaces:
128 * N-bit kernel, N-bit applications, N-bit file offsets
131 static int cstatat(int, char *, struct stat
*, int, int);
132 static int cstat(vnode_t
*vp
, struct stat
*, int, cred_t
*);
135 * fstat can and should be fast, do an inline implementation here.
137 #define FSTAT_BODY(fd, sb, statfn) \
142 if (fd == AT_FDCWD) \
143 return (set_errno(EFAULT)); \
144 if ((fp = getf(fd)) == NULL) \
145 return (set_errno(EBADF)); \
146 error = statfn(fp->f_vnode, sb, 0, fp->f_cred); \
149 return (set_errno(error)); \
154 fstat(int fd
, struct stat
*sb
)
156 FSTAT_BODY(fd
, sb
, cstat
)
160 fstatat(int fd
, char *name
, struct stat
*sb
, int flags
)
166 return (fstat(fd
, sb
));
168 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
169 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
171 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
173 return (cstatat(fd
, name
, sb
, followflag
, csflags
));
177 stat(char *name
, struct stat
*sb
)
179 return (fstatat(AT_FDCWD
, name
, sb
, 0));
183 lstat(char *name
, struct stat
*sb
)
185 return (fstatat(AT_FDCWD
, name
, sb
, AT_SYMLINK_NOFOLLOW
));
189 * Common code for stat(), lstat(), and fstat().
190 * (32-bit kernel, 32-bit applications, 32-bit files)
191 * (64-bit kernel, 64-bit applications, 64-bit files)
194 cstat(vnode_t
*vp
, struct stat
*ubp
, int flag
, cred_t
*cr
)
201 vattr
.va_mask
= AT_STAT
| AT_NBLOCKS
| AT_BLKSIZE
| AT_SIZE
;
202 if ((error
= VOP_GETATTR(vp
, &vattr
, flag
, cr
, NULL
)) != 0)
206 * (32-bit kernel, 32-bit applications, 32-bit files)
207 * NOTE: 32-bit kernel maintains a 64-bit unsigend va_size.
209 * st_size of devices (VBLK and VCHR special files) is a special case.
210 * POSIX does not define size behavior for special files, so the
211 * following Solaris specific behavior is not a violation. Solaris
212 * returns the size of the device.
214 * For compatibility with 32-bit programs which happen to do stat() on
215 * a (mknod) bigger than 2GB we suppress the large file EOVERFLOW and
216 * instead we return the value MAXOFF32_T (LONG_MAX).
218 * 32-bit applications that care about the size of devices should be
219 * built 64-bit or use a large file interface (lfcompile(5) or lf64(5)).
221 if ((vattr
.va_size
> MAXOFF32_T
) &&
222 ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))) {
223 /* OVERFLOW | UNKNOWN_SIZE */
224 vattr
.va_size
= MAXOFF32_T
;
227 if (vattr
.va_size
> MAXOFF_T
|| vattr
.va_nblocks
> LONG_MAX
||
228 vattr
.va_nodeid
> ULONG_MAX
)
231 bzero(&sb
, sizeof (sb
));
232 sb
.st_dev
= vattr
.va_fsid
;
233 sb
.st_ino
= (ino_t
)vattr
.va_nodeid
;
234 sb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
235 sb
.st_nlink
= vattr
.va_nlink
;
236 sb
.st_uid
= vattr
.va_uid
;
237 sb
.st_gid
= vattr
.va_gid
;
238 sb
.st_rdev
= vattr
.va_rdev
;
239 sb
.st_size
= (off_t
)vattr
.va_size
;
240 sb
.st_atim
= vattr
.va_atime
;
241 sb
.st_mtim
= vattr
.va_mtime
;
242 sb
.st_ctim
= vattr
.va_ctime
;
243 sb
.st_blksize
= vattr
.va_blksize
;
244 sb
.st_blocks
= (blkcnt_t
)vattr
.va_nblocks
;
245 if (vp
->v_vfsp
!= NULL
) {
246 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
247 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
248 (void) strcpy(sb
.st_fstype
, vswp
->vsw_name
);
250 if (copyout(&sb
, ubp
, sizeof (sb
)))
256 cstatat(int fd
, char *name
, struct stat
*sb
, int follow
, int flags
)
262 int estale_retry
= 0;
264 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
266 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
267 return (set_errno(error
));
268 error
= cstat(vp
, sb
, flags
, cred
);
272 if (error
== ESTALE
&&
273 fs_need_estale_retry(estale_retry
++))
275 return (set_errno(error
));
280 #if defined(_SYSCALL32_IMPL)
283 * 64-bit kernel, 32-bit applications, 32-bit file offsets
285 static int cstatat32(int, char *, struct stat32
*, int, int);
286 static int cstat32(vnode_t
*, struct stat32
*, int, cred_t
*);
289 fstat32(int fd
, struct stat32
*sb
)
291 FSTAT_BODY(fd
, sb
, cstat32
)
295 fstatat32(int fd
, char *name
, struct stat32
*sb
, int flags
)
301 return (fstat32(fd
, sb
));
303 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
304 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
306 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
308 return (cstatat32(fd
, name
, sb
, followflag
, csflags
));
312 stat32(char *name
, struct stat32
*sb
)
314 return (fstatat32(AT_FDCWD
, name
, sb
, 0));
318 lstat32(char *name
, struct stat32
*sb
)
320 return (fstatat32(AT_FDCWD
, name
, sb
, AT_SYMLINK_NOFOLLOW
));
324 cstat32(vnode_t
*vp
, struct stat32
*ubp
, int flag
, struct cred
*cr
)
330 dev32_t st_dev
, st_rdev
;
332 vattr
.va_mask
= AT_STAT
| AT_NBLOCKS
| AT_BLKSIZE
| AT_SIZE
;
333 if (error
= VOP_GETATTR(vp
, &vattr
, flag
, cr
, NULL
))
336 /* devices are a special case, see comments in cstat */
337 if ((vattr
.va_size
> MAXOFF32_T
) &&
338 ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))) {
339 /* OVERFLOW | UNKNOWN_SIZE */
340 vattr
.va_size
= MAXOFF32_T
;
343 /* check for large values */
344 if (!cmpldev(&st_dev
, vattr
.va_fsid
) ||
345 !cmpldev(&st_rdev
, vattr
.va_rdev
) ||
346 vattr
.va_size
> MAXOFF32_T
||
347 vattr
.va_nblocks
> INT32_MAX
||
348 vattr
.va_nodeid
> UINT32_MAX
||
349 TIMESPEC_OVERFLOW(&(vattr
.va_atime
)) ||
350 TIMESPEC_OVERFLOW(&(vattr
.va_mtime
)) ||
351 TIMESPEC_OVERFLOW(&(vattr
.va_ctime
)))
354 bzero(&sb
, sizeof (sb
));
356 sb
.st_ino
= (ino32_t
)vattr
.va_nodeid
;
357 sb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
358 sb
.st_nlink
= vattr
.va_nlink
;
359 sb
.st_uid
= vattr
.va_uid
;
360 sb
.st_gid
= vattr
.va_gid
;
361 sb
.st_rdev
= st_rdev
;
362 sb
.st_size
= (off32_t
)vattr
.va_size
;
363 TIMESPEC_TO_TIMESPEC32(&(sb
.st_atim
), &(vattr
.va_atime
));
364 TIMESPEC_TO_TIMESPEC32(&(sb
.st_mtim
), &(vattr
.va_mtime
));
365 TIMESPEC_TO_TIMESPEC32(&(sb
.st_ctim
), &(vattr
.va_ctime
));
366 sb
.st_blksize
= vattr
.va_blksize
;
367 sb
.st_blocks
= (blkcnt32_t
)vattr
.va_nblocks
;
368 if (vp
->v_vfsp
!= NULL
) {
369 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
370 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
371 (void) strcpy(sb
.st_fstype
, vswp
->vsw_name
);
373 if (copyout(&sb
, ubp
, sizeof (sb
)))
379 cstatat32(int fd
, char *name
, struct stat32
*sb
, int follow
, int flags
)
385 int estale_retry
= 0;
387 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
389 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
390 return (set_errno(error
));
391 error
= cstat32(vp
, sb
, flags
, cred
);
395 if (error
== ESTALE
&&
396 fs_need_estale_retry(estale_retry
++))
398 return (set_errno(error
));
403 #endif /* _SYSCALL32_IMPL */
408 * 32-bit kernel, 32-bit applications, 64-bit file offsets.
410 * These routines are implemented differently on 64-bit kernels.
412 static int cstatat64(int, char *, struct stat64
*, int, int);
413 static int cstat64(vnode_t
*, struct stat64
*, int, cred_t
*);
416 fstat64(int fd
, struct stat64
*sb
)
418 FSTAT_BODY(fd
, sb
, cstat64
)
422 fstatat64(int fd
, char *name
, struct stat64
*sb
, int flags
)
428 return (fstat64(fd
, sb
));
430 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
431 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
433 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
435 return (cstatat64(fd
, name
, sb
, followflag
, csflags
));
439 stat64(char *name
, struct stat64
*sb
)
441 return (fstatat64(AT_FDCWD
, name
, sb
, 0));
445 lstat64(char *name
, struct stat64
*sb
)
447 return (fstatat64(AT_FDCWD
, name
, sb
, AT_SYMLINK_NOFOLLOW
));
451 cstat64(vnode_t
*vp
, struct stat64
*ubp
, int flag
, cred_t
*cr
)
458 vattr
.va_mask
= AT_STAT
| AT_NBLOCKS
| AT_BLKSIZE
| AT_SIZE
;
459 if (error
= VOP_GETATTR(vp
, &vattr
, flag
, cr
, NULL
))
462 bzero(&lsb
, sizeof (lsb
));
463 lsb
.st_dev
= vattr
.va_fsid
;
464 lsb
.st_ino
= vattr
.va_nodeid
;
465 lsb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
466 lsb
.st_nlink
= vattr
.va_nlink
;
467 lsb
.st_uid
= vattr
.va_uid
;
468 lsb
.st_gid
= vattr
.va_gid
;
469 lsb
.st_rdev
= vattr
.va_rdev
;
470 lsb
.st_size
= vattr
.va_size
;
471 lsb
.st_atim
= vattr
.va_atime
;
472 lsb
.st_mtim
= vattr
.va_mtime
;
473 lsb
.st_ctim
= vattr
.va_ctime
;
474 lsb
.st_blksize
= vattr
.va_blksize
;
475 lsb
.st_blocks
= vattr
.va_nblocks
;
476 if (vp
->v_vfsp
!= NULL
) {
477 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
478 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
479 (void) strcpy(lsb
.st_fstype
, vswp
->vsw_name
);
481 if (copyout(&lsb
, ubp
, sizeof (lsb
)))
487 cstatat64(int fd
, char *name
, struct stat64
*sb
, int follow
, int flags
)
493 int estale_retry
= 0;
495 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
497 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
498 return (set_errno(error
));
499 error
= cstat64(vp
, sb
, flags
, cred
);
503 if (error
== ESTALE
&&
504 fs_need_estale_retry(estale_retry
++))
506 return (set_errno(error
));
513 #if defined(_SYSCALL32_IMPL)
516 * 64-bit kernel, 32-bit applications, 64-bit file offsets.
518 * We'd really like to call the "native" stat calls for these ones,
519 * but the problem is that the 64-bit ABI defines the 'stat64' structure
520 * differently from the way the 32-bit ABI defines it.
523 static int cstatat64_32(int, char *, struct stat64_32
*, int, int);
524 static int cstat64_32(vnode_t
*, struct stat64_32
*, int, cred_t
*);
527 fstat64_32(int fd
, struct stat64_32
*sb
)
529 FSTAT_BODY(fd
, sb
, cstat64_32
)
533 fstatat64_32(int fd
, char *name
, struct stat64_32
*sb
, int flags
)
539 return (fstat64_32(fd
, sb
));
541 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
542 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
544 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
546 return (cstatat64_32(fd
, name
, sb
, followflag
, csflags
));
550 stat64_32(char *name
, struct stat64_32
*sb
)
552 return (fstatat64_32(AT_FDCWD
, name
, sb
, 0));
556 lstat64_32(char *name
, struct stat64_32
*sb
)
558 return (fstatat64_32(AT_FDCWD
, name
, sb
, AT_SYMLINK_NOFOLLOW
));
562 cstat64_32(vnode_t
*vp
, struct stat64_32
*ubp
, int flag
, cred_t
*cr
)
565 struct stat64_32 lsb
;
568 dev32_t st_dev
, st_rdev
;
570 vattr
.va_mask
= AT_STAT
| AT_NBLOCKS
| AT_BLKSIZE
| AT_SIZE
;
571 if (error
= VOP_GETATTR(vp
, &vattr
, flag
, cr
, NULL
))
574 if (!cmpldev(&st_dev
, vattr
.va_fsid
) ||
575 !cmpldev(&st_rdev
, vattr
.va_rdev
) ||
576 TIMESPEC_OVERFLOW(&(vattr
.va_atime
)) ||
577 TIMESPEC_OVERFLOW(&(vattr
.va_mtime
)) ||
578 TIMESPEC_OVERFLOW(&(vattr
.va_ctime
)))
581 bzero(&lsb
, sizeof (lsb
));
583 lsb
.st_ino
= vattr
.va_nodeid
;
584 lsb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
585 lsb
.st_nlink
= vattr
.va_nlink
;
586 lsb
.st_uid
= vattr
.va_uid
;
587 lsb
.st_gid
= vattr
.va_gid
;
588 lsb
.st_rdev
= st_rdev
;
589 lsb
.st_size
= vattr
.va_size
;
590 TIMESPEC_TO_TIMESPEC32(&(lsb
.st_atim
), &(vattr
.va_atime
));
591 TIMESPEC_TO_TIMESPEC32(&(lsb
.st_mtim
), &(vattr
.va_mtime
));
592 TIMESPEC_TO_TIMESPEC32(&(lsb
.st_ctim
), &(vattr
.va_ctime
));
593 lsb
.st_blksize
= vattr
.va_blksize
;
594 lsb
.st_blocks
= vattr
.va_nblocks
;
595 if (vp
->v_vfsp
!= NULL
) {
596 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
597 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
598 (void) strcpy(lsb
.st_fstype
, vswp
->vsw_name
);
600 if (copyout(&lsb
, ubp
, sizeof (lsb
)))
606 cstatat64_32(int fd
, char *name
, struct stat64_32
*sb
, int follow
, int flags
)
612 int estale_retry
= 0;
614 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
616 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
617 return (set_errno(error
));
618 error
= cstat64_32(vp
, sb
, flags
, cred
);
622 if (error
== ESTALE
&&
623 fs_need_estale_retry(estale_retry
++))
625 return (set_errno(error
));
630 #endif /* _SYSCALL32_IMPL */