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>
56 #include <sys/fs_subr.h>
59 * Get the vp to be stated and the cred to be used for the call
64 cstatat_getvp(int fd
, char *name
, int follow
, vnode_t
**vp
, cred_t
**cred
)
75 * Only return EFAULT for fstatat when fd == AT_FDCWD && name == NULL
85 if (copyin(name
, &startchar
, sizeof (char)))
87 if (startchar
!= '/') {
88 if ((fp
= getf(fd
)) == NULL
) {
91 startvp
= fp
->f_vnode
;
105 if (error
= lookupnameat(name
, UIO_USERSPACE
, follow
, NULLVPP
,
107 if ((error
== ESTALE
) &&
108 fs_need_estale_retry(estale_retry
++))
122 * Native syscall interfaces:
124 * N-bit kernel, N-bit applications, N-bit file offsets
127 static int cstatat(int, char *, struct stat
*, int, int);
128 static int cstat(vnode_t
*vp
, struct stat
*, int, cred_t
*);
131 * fstat can and should be fast, do an inline implementation here.
133 #define FSTAT_BODY(fd, sb, statfn) \
138 if (fd == AT_FDCWD) \
139 return (set_errno(EFAULT)); \
140 if ((fp = getf(fd)) == NULL) \
141 return (set_errno(EBADF)); \
142 error = statfn(fp->f_vnode, sb, 0, fp->f_cred); \
145 return (set_errno(error)); \
150 fstat(int fd
, struct stat
*sb
)
152 FSTAT_BODY(fd
, sb
, cstat
)
156 fstatat(int fd
, char *name
, struct stat
*sb
, int flags
)
162 return (fstat(fd
, sb
));
164 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
165 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
167 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
169 return (cstatat(fd
, name
, sb
, followflag
, csflags
));
173 * Common code for stat(), lstat(), and fstat().
174 * (32-bit kernel, 32-bit applications, 32-bit files)
175 * (64-bit kernel, 64-bit applications, 64-bit files)
178 cstat(vnode_t
*vp
, struct stat
*ubp
, int flag
, cred_t
*cr
)
185 vattr
.va_mask
= VATTR_STAT
| VATTR_NBLOCKS
| VATTR_BLKSIZE
| VATTR_SIZE
;
186 if ((error
= fop_getattr(vp
, &vattr
, flag
, cr
, NULL
)) != 0)
190 * (32-bit kernel, 32-bit applications, 32-bit files)
191 * NOTE: 32-bit kernel maintains a 64-bit unsigend va_size.
193 * st_size of devices (VBLK and VCHR special files) is a special case.
194 * POSIX does not define size behavior for special files, so the
195 * following Solaris specific behavior is not a violation. Solaris
196 * returns the size of the device.
198 * For compatibility with 32-bit programs which happen to do stat() on
199 * a (mknod) bigger than 2GB we suppress the large file EOVERFLOW and
200 * instead we return the value MAXOFF32_T (LONG_MAX).
202 * 32-bit applications that care about the size of devices should be
203 * built 64-bit or use a large file interface (lfcompile(5) or lf64(5)).
205 if ((vattr
.va_size
> MAXOFF32_T
) &&
206 ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))) {
207 /* OVERFLOW | UNKNOWN_SIZE */
208 vattr
.va_size
= MAXOFF32_T
;
211 if (vattr
.va_size
> MAXOFF_T
|| vattr
.va_nblocks
> LONG_MAX
||
212 vattr
.va_nodeid
> ULONG_MAX
)
215 bzero(&sb
, sizeof (sb
));
216 sb
.st_dev
= vattr
.va_fsid
;
217 sb
.st_ino
= (ino_t
)vattr
.va_nodeid
;
218 sb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
219 sb
.st_nlink
= vattr
.va_nlink
;
220 sb
.st_uid
= vattr
.va_uid
;
221 sb
.st_gid
= vattr
.va_gid
;
222 sb
.st_rdev
= vattr
.va_rdev
;
223 sb
.st_size
= (off_t
)vattr
.va_size
;
224 sb
.st_atim
= vattr
.va_atime
;
225 sb
.st_mtim
= vattr
.va_mtime
;
226 sb
.st_ctim
= vattr
.va_ctime
;
227 sb
.st_blksize
= vattr
.va_blksize
;
228 sb
.st_blocks
= (blkcnt_t
)vattr
.va_nblocks
;
229 if (vp
->v_vfsp
!= NULL
) {
230 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
231 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
232 (void) strcpy(sb
.st_fstype
, vswp
->vsw_name
);
234 if (copyout(&sb
, ubp
, sizeof (sb
)))
240 cstatat(int fd
, char *name
, struct stat
*sb
, int follow
, int flags
)
246 int estale_retry
= 0;
248 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
250 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
251 return (set_errno(error
));
252 error
= cstat(vp
, sb
, flags
, cred
);
256 if (error
== ESTALE
&&
257 fs_need_estale_retry(estale_retry
++))
259 return (set_errno(error
));
264 #if defined(_SYSCALL32_IMPL)
267 * 64-bit kernel, 32-bit applications, 32-bit file offsets
269 static int cstatat32(int, char *, struct stat32
*, int, int);
270 static int cstat32(vnode_t
*, struct stat32
*, int, cred_t
*);
273 fstat32(int fd
, struct stat32
*sb
)
275 FSTAT_BODY(fd
, sb
, cstat32
)
279 fstatat32(int fd
, char *name
, struct stat32
*sb
, int flags
)
285 return (fstat32(fd
, sb
));
287 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
288 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
290 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
292 return (cstatat32(fd
, name
, sb
, followflag
, csflags
));
296 cstat32(vnode_t
*vp
, struct stat32
*ubp
, int flag
, struct cred
*cr
)
302 dev32_t st_dev
, st_rdev
;
304 vattr
.va_mask
= VATTR_STAT
| VATTR_NBLOCKS
| VATTR_BLKSIZE
| VATTR_SIZE
;
305 if (error
= fop_getattr(vp
, &vattr
, flag
, cr
, NULL
))
308 /* devices are a special case, see comments in cstat */
309 if ((vattr
.va_size
> MAXOFF32_T
) &&
310 ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))) {
311 /* OVERFLOW | UNKNOWN_SIZE */
312 vattr
.va_size
= MAXOFF32_T
;
315 /* check for large values */
316 if (!cmpldev(&st_dev
, vattr
.va_fsid
) ||
317 !cmpldev(&st_rdev
, vattr
.va_rdev
) ||
318 vattr
.va_size
> MAXOFF32_T
||
319 vattr
.va_nblocks
> INT32_MAX
||
320 vattr
.va_nodeid
> UINT32_MAX
||
321 TIMESPEC_OVERFLOW(&(vattr
.va_atime
)) ||
322 TIMESPEC_OVERFLOW(&(vattr
.va_mtime
)) ||
323 TIMESPEC_OVERFLOW(&(vattr
.va_ctime
)))
326 bzero(&sb
, sizeof (sb
));
328 sb
.st_ino
= (ino32_t
)vattr
.va_nodeid
;
329 sb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
330 sb
.st_nlink
= vattr
.va_nlink
;
331 sb
.st_uid
= vattr
.va_uid
;
332 sb
.st_gid
= vattr
.va_gid
;
333 sb
.st_rdev
= st_rdev
;
334 sb
.st_size
= (off32_t
)vattr
.va_size
;
335 TIMESPEC_TO_TIMESPEC32(&(sb
.st_atim
), &(vattr
.va_atime
));
336 TIMESPEC_TO_TIMESPEC32(&(sb
.st_mtim
), &(vattr
.va_mtime
));
337 TIMESPEC_TO_TIMESPEC32(&(sb
.st_ctim
), &(vattr
.va_ctime
));
338 sb
.st_blksize
= vattr
.va_blksize
;
339 sb
.st_blocks
= (blkcnt32_t
)vattr
.va_nblocks
;
340 if (vp
->v_vfsp
!= NULL
) {
341 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
342 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
343 (void) strcpy(sb
.st_fstype
, vswp
->vsw_name
);
345 if (copyout(&sb
, ubp
, sizeof (sb
)))
351 cstatat32(int fd
, char *name
, struct stat32
*sb
, int follow
, int flags
)
357 int estale_retry
= 0;
359 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
361 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
362 return (set_errno(error
));
363 error
= cstat32(vp
, sb
, flags
, cred
);
367 if (error
== ESTALE
&&
368 fs_need_estale_retry(estale_retry
++))
370 return (set_errno(error
));
375 #endif /* _SYSCALL32_IMPL */
380 * 32-bit kernel, 32-bit applications, 64-bit file offsets.
382 * These routines are implemented differently on 64-bit kernels.
384 static int cstatat64(int, char *, struct stat64
*, int, int);
385 static int cstat64(vnode_t
*, struct stat64
*, int, cred_t
*);
388 fstat64(int fd
, struct stat64
*sb
)
390 FSTAT_BODY(fd
, sb
, cstat64
)
394 fstatat64(int fd
, char *name
, struct stat64
*sb
, int flags
)
400 return (fstat64(fd
, sb
));
402 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
403 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
405 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
407 return (cstatat64(fd
, name
, sb
, followflag
, csflags
));
411 cstat64(vnode_t
*vp
, struct stat64
*ubp
, int flag
, cred_t
*cr
)
418 vattr
.va_mask
= VATTR_STAT
| VATTR_NBLOCKS
| VATTR_BLKSIZE
| VATTR_SIZE
;
419 if (error
= fop_getattr(vp
, &vattr
, flag
, cr
, NULL
))
422 bzero(&lsb
, sizeof (lsb
));
423 lsb
.st_dev
= vattr
.va_fsid
;
424 lsb
.st_ino
= vattr
.va_nodeid
;
425 lsb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
426 lsb
.st_nlink
= vattr
.va_nlink
;
427 lsb
.st_uid
= vattr
.va_uid
;
428 lsb
.st_gid
= vattr
.va_gid
;
429 lsb
.st_rdev
= vattr
.va_rdev
;
430 lsb
.st_size
= vattr
.va_size
;
431 lsb
.st_atim
= vattr
.va_atime
;
432 lsb
.st_mtim
= vattr
.va_mtime
;
433 lsb
.st_ctim
= vattr
.va_ctime
;
434 lsb
.st_blksize
= vattr
.va_blksize
;
435 lsb
.st_blocks
= vattr
.va_nblocks
;
436 if (vp
->v_vfsp
!= NULL
) {
437 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
438 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
439 (void) strcpy(lsb
.st_fstype
, vswp
->vsw_name
);
441 if (copyout(&lsb
, ubp
, sizeof (lsb
)))
447 cstatat64(int fd
, char *name
, struct stat64
*sb
, int follow
, int flags
)
453 int estale_retry
= 0;
455 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
457 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
458 return (set_errno(error
));
459 error
= cstat64(vp
, sb
, flags
, cred
);
463 if (error
== ESTALE
&&
464 fs_need_estale_retry(estale_retry
++))
466 return (set_errno(error
));
473 #if defined(_SYSCALL32_IMPL)
476 * 64-bit kernel, 32-bit applications, 64-bit file offsets.
478 * We'd really like to call the "native" stat calls for these ones,
479 * but the problem is that the 64-bit ABI defines the 'stat64' structure
480 * differently from the way the 32-bit ABI defines it.
483 static int cstatat64_32(int, char *, struct stat64_32
*, int, int);
484 static int cstat64_32(vnode_t
*, struct stat64_32
*, int, cred_t
*);
487 fstat64_32(int fd
, struct stat64_32
*sb
)
489 FSTAT_BODY(fd
, sb
, cstat64_32
)
493 fstatat64_32(int fd
, char *name
, struct stat64_32
*sb
, int flags
)
499 return (fstat64_32(fd
, sb
));
501 followflag
= (flags
& AT_SYMLINK_NOFOLLOW
);
502 csflags
= (flags
& _AT_TRIGGER
? ATTR_TRIGGER
: 0);
504 csflags
|= ATTR_REAL
; /* flag for procfs lookups */
506 return (cstatat64_32(fd
, name
, sb
, followflag
, csflags
));
510 cstat64_32(vnode_t
*vp
, struct stat64_32
*ubp
, int flag
, cred_t
*cr
)
513 struct stat64_32 lsb
;
516 dev32_t st_dev
, st_rdev
;
518 vattr
.va_mask
= VATTR_STAT
| VATTR_NBLOCKS
| VATTR_BLKSIZE
| VATTR_SIZE
;
519 if (error
= fop_getattr(vp
, &vattr
, flag
, cr
, NULL
))
522 if (!cmpldev(&st_dev
, vattr
.va_fsid
) ||
523 !cmpldev(&st_rdev
, vattr
.va_rdev
) ||
524 TIMESPEC_OVERFLOW(&(vattr
.va_atime
)) ||
525 TIMESPEC_OVERFLOW(&(vattr
.va_mtime
)) ||
526 TIMESPEC_OVERFLOW(&(vattr
.va_ctime
)))
529 bzero(&lsb
, sizeof (lsb
));
531 lsb
.st_ino
= vattr
.va_nodeid
;
532 lsb
.st_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
533 lsb
.st_nlink
= vattr
.va_nlink
;
534 lsb
.st_uid
= vattr
.va_uid
;
535 lsb
.st_gid
= vattr
.va_gid
;
536 lsb
.st_rdev
= st_rdev
;
537 lsb
.st_size
= vattr
.va_size
;
538 TIMESPEC_TO_TIMESPEC32(&(lsb
.st_atim
), &(vattr
.va_atime
));
539 TIMESPEC_TO_TIMESPEC32(&(lsb
.st_mtim
), &(vattr
.va_mtime
));
540 TIMESPEC_TO_TIMESPEC32(&(lsb
.st_ctim
), &(vattr
.va_ctime
));
541 lsb
.st_blksize
= vattr
.va_blksize
;
542 lsb
.st_blocks
= vattr
.va_nblocks
;
543 if (vp
->v_vfsp
!= NULL
) {
544 vswp
= &vfssw
[vp
->v_vfsp
->vfs_fstype
];
545 if (vswp
->vsw_name
&& *vswp
->vsw_name
)
546 (void) strcpy(lsb
.st_fstype
, vswp
->vsw_name
);
548 if (copyout(&lsb
, ubp
, sizeof (lsb
)))
554 cstatat64_32(int fd
, char *name
, struct stat64_32
*sb
, int follow
, int flags
)
560 int estale_retry
= 0;
562 link_follow
= (follow
== AT_SYMLINK_NOFOLLOW
) ? NO_FOLLOW
: FOLLOW
;
564 if (error
= cstatat_getvp(fd
, name
, link_follow
, &vp
, &cred
))
565 return (set_errno(error
));
566 error
= cstat64_32(vp
, sb
, flags
, cred
);
570 if (error
== ESTALE
&&
571 fs_need_estale_retry(estale_retry
++))
573 return (set_errno(error
));
578 #endif /* _SYSCALL32_IMPL */