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 <sys/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 * Common code for stat(), lstat(), and fstat().
178 * (32-bit kernel, 32-bit applications, 32-bit files)
179 * (64-bit kernel, 64-bit applications, 64-bit files)
182 cstat(vnode_t
*vp
, struct stat
*ubp
, int flag
, cred_t
*cr
)
189 vattr
.va_mask
= AT_STAT
| AT_NBLOCKS
| AT_BLKSIZE
| AT_SIZE
;
190 if ((error
= fop_getattr(vp
, &vattr
, flag
, cr
, NULL
)) != 0)
194 * (32-bit kernel, 32-bit applications, 32-bit files)
195 * NOTE: 32-bit kernel maintains a 64-bit unsigend va_size.
197 * st_size of devices (VBLK and VCHR special files) is a special case.
198 * POSIX does not define size behavior for special files, so the
199 * following Solaris specific behavior is not a violation. Solaris
200 * returns the size of the device.
202 * For compatibility with 32-bit programs which happen to do stat() on
203 * a (mknod) bigger than 2GB we suppress the large file EOVERFLOW and
204 * instead we return the value MAXOFF32_T (LONG_MAX).
206 * 32-bit applications that care about the size of devices should be
207 * built 64-bit or use a large file interface (lfcompile(5) or lf64(5)).
209 if ((vattr
.va_size
> MAXOFF32_T
) &&
210 ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))) {
211 /* OVERFLOW | UNKNOWN_SIZE */
212 vattr
.va_size
= MAXOFF32_T
;
215 if (vattr
.va_size
> MAXOFF_T
|| vattr
.va_nblocks
> LONG_MAX
||
216 vattr
.va_nodeid
> ULONG_MAX
)
219 bzero(&sb
, sizeof (sb
));
220 sb
.st_dev
= vattr
.va_fsid
;
221 sb
.st_ino
= (ino_t
)vattr
.va_nodeid
;
222 sb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
223 sb
.st_nlink
= vattr
.va_nlink
;
224 sb
.st_uid
= vattr
.va_uid
;
225 sb
.st_gid
= vattr
.va_gid
;
226 sb
.st_rdev
= vattr
.va_rdev
;
227 sb
.st_size
= (off_t
)vattr
.va_size
;
228 sb
.st_atim
= vattr
.va_atime
;
229 sb
.st_mtim
= vattr
.va_mtime
;
230 sb
.st_ctim
= vattr
.va_ctime
;
231 sb
.st_blksize
= vattr
.va_blksize
;
232 sb
.st_blocks
= (blkcnt_t
)vattr
.va_nblocks
;
233 if (vp
->v_vfsp
!= NULL
) {
234 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
235 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
236 (void) strcpy(sb
.st_fstype
, vswp
->vsw_name
);
238 if (copyout(&sb
, ubp
, sizeof (sb
)))
244 cstatat(int fd
, char *name
, struct stat
*sb
, int follow
, int flags
)
250 int estale_retry
= 0;
252 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
254 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
255 return (set_errno(error
));
256 error
= cstat(vp
, sb
, flags
, cred
);
260 if (error
== ESTALE
&&
261 fs_need_estale_retry(estale_retry
++))
263 return (set_errno(error
));
268 #if defined(_SYSCALL32_IMPL)
271 * 64-bit kernel, 32-bit applications, 32-bit file offsets
273 static int cstatat32(int, char *, struct stat32
*, int, int);
274 static int cstat32(vnode_t
*, struct stat32
*, int, cred_t
*);
277 fstat32(int fd
, struct stat32
*sb
)
279 FSTAT_BODY(fd
, sb
, cstat32
)
283 fstatat32(int fd
, char *name
, struct stat32
*sb
, int flags
)
289 return (fstat32(fd
, sb
));
291 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
292 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
294 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
296 return (cstatat32(fd
, name
, sb
, followflag
, csflags
));
300 cstat32(vnode_t
*vp
, struct stat32
*ubp
, int flag
, struct cred
*cr
)
306 dev32_t st_dev
, st_rdev
;
308 vattr
.va_mask
= AT_STAT
| AT_NBLOCKS
| AT_BLKSIZE
| AT_SIZE
;
309 if (error
= fop_getattr(vp
, &vattr
, flag
, cr
, NULL
))
312 /* devices are a special case, see comments in cstat */
313 if ((vattr
.va_size
> MAXOFF32_T
) &&
314 ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))) {
315 /* OVERFLOW | UNKNOWN_SIZE */
316 vattr
.va_size
= MAXOFF32_T
;
319 /* check for large values */
320 if (!cmpldev(&st_dev
, vattr
.va_fsid
) ||
321 !cmpldev(&st_rdev
, vattr
.va_rdev
) ||
322 vattr
.va_size
> MAXOFF32_T
||
323 vattr
.va_nblocks
> INT32_MAX
||
324 vattr
.va_nodeid
> UINT32_MAX
||
325 TIMESPEC_OVERFLOW(&(vattr
.va_atime
)) ||
326 TIMESPEC_OVERFLOW(&(vattr
.va_mtime
)) ||
327 TIMESPEC_OVERFLOW(&(vattr
.va_ctime
)))
330 bzero(&sb
, sizeof (sb
));
332 sb
.st_ino
= (ino32_t
)vattr
.va_nodeid
;
333 sb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
334 sb
.st_nlink
= vattr
.va_nlink
;
335 sb
.st_uid
= vattr
.va_uid
;
336 sb
.st_gid
= vattr
.va_gid
;
337 sb
.st_rdev
= st_rdev
;
338 sb
.st_size
= (off32_t
)vattr
.va_size
;
339 TIMESPEC_TO_TIMESPEC32(&(sb
.st_atim
), &(vattr
.va_atime
));
340 TIMESPEC_TO_TIMESPEC32(&(sb
.st_mtim
), &(vattr
.va_mtime
));
341 TIMESPEC_TO_TIMESPEC32(&(sb
.st_ctim
), &(vattr
.va_ctime
));
342 sb
.st_blksize
= vattr
.va_blksize
;
343 sb
.st_blocks
= (blkcnt32_t
)vattr
.va_nblocks
;
344 if (vp
->v_vfsp
!= NULL
) {
345 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
346 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
347 (void) strcpy(sb
.st_fstype
, vswp
->vsw_name
);
349 if (copyout(&sb
, ubp
, sizeof (sb
)))
355 cstatat32(int fd
, char *name
, struct stat32
*sb
, int follow
, int flags
)
361 int estale_retry
= 0;
363 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
365 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
366 return (set_errno(error
));
367 error
= cstat32(vp
, sb
, flags
, cred
);
371 if (error
== ESTALE
&&
372 fs_need_estale_retry(estale_retry
++))
374 return (set_errno(error
));
379 #endif /* _SYSCALL32_IMPL */
384 * 32-bit kernel, 32-bit applications, 64-bit file offsets.
386 * These routines are implemented differently on 64-bit kernels.
388 static int cstatat64(int, char *, struct stat64
*, int, int);
389 static int cstat64(vnode_t
*, struct stat64
*, int, cred_t
*);
392 fstat64(int fd
, struct stat64
*sb
)
394 FSTAT_BODY(fd
, sb
, cstat64
)
398 fstatat64(int fd
, char *name
, struct stat64
*sb
, int flags
)
404 return (fstat64(fd
, sb
));
406 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
407 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
409 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
411 return (cstatat64(fd
, name
, sb
, followflag
, csflags
));
415 cstat64(vnode_t
*vp
, struct stat64
*ubp
, int flag
, cred_t
*cr
)
422 vattr
.va_mask
= AT_STAT
| AT_NBLOCKS
| AT_BLKSIZE
| AT_SIZE
;
423 if (error
= fop_getattr(vp
, &vattr
, flag
, cr
, NULL
))
426 bzero(&lsb
, sizeof (lsb
));
427 lsb
.st_dev
= vattr
.va_fsid
;
428 lsb
.st_ino
= vattr
.va_nodeid
;
429 lsb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
430 lsb
.st_nlink
= vattr
.va_nlink
;
431 lsb
.st_uid
= vattr
.va_uid
;
432 lsb
.st_gid
= vattr
.va_gid
;
433 lsb
.st_rdev
= vattr
.va_rdev
;
434 lsb
.st_size
= vattr
.va_size
;
435 lsb
.st_atim
= vattr
.va_atime
;
436 lsb
.st_mtim
= vattr
.va_mtime
;
437 lsb
.st_ctim
= vattr
.va_ctime
;
438 lsb
.st_blksize
= vattr
.va_blksize
;
439 lsb
.st_blocks
= vattr
.va_nblocks
;
440 if (vp
->v_vfsp
!= NULL
) {
441 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
442 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
443 (void) strcpy(lsb
.st_fstype
, vswp
->vsw_name
);
445 if (copyout(&lsb
, ubp
, sizeof (lsb
)))
451 cstatat64(int fd
, char *name
, struct stat64
*sb
, int follow
, int flags
)
457 int estale_retry
= 0;
459 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
461 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
462 return (set_errno(error
));
463 error
= cstat64(vp
, sb
, flags
, cred
);
467 if (error
== ESTALE
&&
468 fs_need_estale_retry(estale_retry
++))
470 return (set_errno(error
));
477 #if defined(_SYSCALL32_IMPL)
480 * 64-bit kernel, 32-bit applications, 64-bit file offsets.
482 * We'd really like to call the "native" stat calls for these ones,
483 * but the problem is that the 64-bit ABI defines the 'stat64' structure
484 * differently from the way the 32-bit ABI defines it.
487 static int cstatat64_32(int, char *, struct stat64_32
*, int, int);
488 static int cstat64_32(vnode_t
*, struct stat64_32
*, int, cred_t
*);
491 fstat64_32(int fd
, struct stat64_32
*sb
)
493 FSTAT_BODY(fd
, sb
, cstat64_32
)
497 fstatat64_32(int fd
, char *name
, struct stat64_32
*sb
, int flags
)
503 return (fstat64_32(fd
, sb
));
505 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
506 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
508 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
510 return (cstatat64_32(fd
, name
, sb
, followflag
, csflags
));
514 cstat64_32(vnode_t
*vp
, struct stat64_32
*ubp
, int flag
, cred_t
*cr
)
517 struct stat64_32 lsb
;
520 dev32_t st_dev
, st_rdev
;
522 vattr
.va_mask
= AT_STAT
| AT_NBLOCKS
| AT_BLKSIZE
| AT_SIZE
;
523 if (error
= fop_getattr(vp
, &vattr
, flag
, cr
, NULL
))
526 if (!cmpldev(&st_dev
, vattr
.va_fsid
) ||
527 !cmpldev(&st_rdev
, vattr
.va_rdev
) ||
528 TIMESPEC_OVERFLOW(&(vattr
.va_atime
)) ||
529 TIMESPEC_OVERFLOW(&(vattr
.va_mtime
)) ||
530 TIMESPEC_OVERFLOW(&(vattr
.va_ctime
)))
533 bzero(&lsb
, sizeof (lsb
));
535 lsb
.st_ino
= vattr
.va_nodeid
;
536 lsb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
537 lsb
.st_nlink
= vattr
.va_nlink
;
538 lsb
.st_uid
= vattr
.va_uid
;
539 lsb
.st_gid
= vattr
.va_gid
;
540 lsb
.st_rdev
= st_rdev
;
541 lsb
.st_size
= vattr
.va_size
;
542 TIMESPEC_TO_TIMESPEC32(&(lsb
.st_atim
), &(vattr
.va_atime
));
543 TIMESPEC_TO_TIMESPEC32(&(lsb
.st_mtim
), &(vattr
.va_mtime
));
544 TIMESPEC_TO_TIMESPEC32(&(lsb
.st_ctim
), &(vattr
.va_ctime
));
545 lsb
.st_blksize
= vattr
.va_blksize
;
546 lsb
.st_blocks
= vattr
.va_nblocks
;
547 if (vp
->v_vfsp
!= NULL
) {
548 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
549 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
550 (void) strcpy(lsb
.st_fstype
, vswp
->vsw_name
);
552 if (copyout(&lsb
, ubp
, sizeof (lsb
)))
558 cstatat64_32(int fd
, char *name
, struct stat64_32
*sb
, int follow
, int flags
)
564 int estale_retry
= 0;
566 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
568 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
569 return (set_errno(error
));
570 error
= cstat64_32(vp
, sb
, flags
, cred
);
574 if (error
== ESTALE
&&
575 fs_need_estale_retry(estale_retry
++))
577 return (set_errno(error
));
582 #endif /* _SYSCALL32_IMPL */