Merge illumos-gate
[unleashed.git] / kernel / syscall / stat.c
blob7cec1115e3965eb1596a33f7fd8e80f5d08ab974
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
42 #include <sys/cred.h>
43 #include <sys/systm.h>
44 #include <sys/errno.h>
45 #include <sys/fcntl.h>
46 #include <sys/pathname.h>
47 #include <sys/stat.h>
48 #include <sys/vfs.h>
49 #include <sys/vnode.h>
50 #include <sys/mode.h>
51 #include <sys/file.h>
52 #include <sys/proc.h>
53 #include <sys/uio.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
60 * to fop_getattr
63 static int
64 cstatat_getvp(int fd, char *name, int follow, vnode_t **vp, cred_t **cred)
66 vnode_t *startvp;
67 file_t *fp;
68 int error;
69 cred_t *cr;
70 int estale_retry = 0;
72 *vp = NULL;
75 * Only return EFAULT for fstatat when fd == AT_FDCWD && name == NULL
78 if (fd == AT_FDCWD) {
79 startvp = NULL;
80 cr = CRED();
81 crhold(cr);
82 } else {
83 char startchar;
85 if (copyin(name, &startchar, sizeof (char)))
86 return (EFAULT);
87 if (startchar != '/') {
88 if ((fp = getf(fd)) == NULL) {
89 return (EBADF);
91 startvp = fp->f_vnode;
92 cr = fp->f_cred;
93 crhold(cr);
94 VN_HOLD(startvp);
95 releasef(fd);
96 } else {
97 startvp = NULL;
98 cr = CRED();
99 crhold(cr);
102 *cred = cr;
104 lookup:
105 if (error = lookupnameat(name, UIO_USERSPACE, follow, NULLVPP,
106 vp, startvp)) {
107 if ((error == ESTALE) &&
108 fs_need_estale_retry(estale_retry++))
109 goto lookup;
110 if (startvp != NULL)
111 VN_RELE(startvp);
112 crfree(cr);
113 return (error);
115 if (startvp != NULL)
116 VN_RELE(startvp);
118 return (0);
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) \
135 file_t *fp; \
136 int error; \
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); \
143 releasef(fd); \
144 if (error) \
145 return (set_errno(error)); \
146 return (0); \
149 static inline int
150 fstat(int fd, struct stat *sb)
152 FSTAT_BODY(fd, sb, cstat)
156 fstatat(int fd, char *name, struct stat *sb, int flags)
158 int followflag;
159 int csflags;
161 if (name == NULL)
162 return (fstat(fd, sb));
164 followflag = (flags & AT_SYMLINK_NOFOLLOW);
165 csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
166 if (followflag == 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)
177 static int
178 cstat(vnode_t *vp, struct stat *ubp, int flag, cred_t *cr)
180 struct vfssw *vswp;
181 struct stat sb;
182 vattr_t vattr;
183 int error;
185 vattr.va_mask = VATTR_STAT | VATTR_NBLOCKS | VATTR_BLKSIZE | VATTR_SIZE;
186 if ((error = fop_getattr(vp, &vattr, flag, cr, NULL)) != 0)
187 return (error);
188 #ifdef _ILP32
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;
210 #endif /* _ILP32 */
211 if (vattr.va_size > MAXOFF_T || vattr.va_nblocks > LONG_MAX ||
212 vattr.va_nodeid > ULONG_MAX)
213 return (EOVERFLOW);
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)))
235 return (EFAULT);
236 return (0);
239 static int
240 cstatat(int fd, char *name, struct stat *sb, int follow, int flags)
242 vnode_t *vp;
243 int error;
244 cred_t *cred;
245 int link_follow;
246 int estale_retry = 0;
248 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
249 lookup:
250 if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
251 return (set_errno(error));
252 error = cstat(vp, sb, flags, cred);
253 crfree(cred);
254 VN_RELE(vp);
255 if (error != 0) {
256 if (error == ESTALE &&
257 fs_need_estale_retry(estale_retry++))
258 goto lookup;
259 return (set_errno(error));
261 return (0);
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 *);
272 static inline int
273 fstat32(int fd, struct stat32 *sb)
275 FSTAT_BODY(fd, sb, cstat32)
279 fstatat32(int fd, char *name, struct stat32 *sb, int flags)
281 int followflag;
282 int csflags;
284 if (name == NULL)
285 return (fstat32(fd, sb));
287 followflag = (flags & AT_SYMLINK_NOFOLLOW);
288 csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
289 if (followflag == 0)
290 csflags |= ATTR_REAL; /* flag for procfs lookups */
292 return (cstatat32(fd, name, sb, followflag, csflags));
295 static int
296 cstat32(vnode_t *vp, struct stat32 *ubp, int flag, struct cred *cr)
298 struct vfssw *vswp;
299 struct stat32 sb;
300 vattr_t vattr;
301 int error;
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))
306 return (error);
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)))
324 return (EOVERFLOW);
326 bzero(&sb, sizeof (sb));
327 sb.st_dev = st_dev;
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)))
346 return (EFAULT);
347 return (0);
350 static int
351 cstatat32(int fd, char *name, struct stat32 *sb, int follow, int flags)
353 vnode_t *vp;
354 int error;
355 cred_t *cred;
356 int link_follow;
357 int estale_retry = 0;
359 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
360 lookup:
361 if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
362 return (set_errno(error));
363 error = cstat32(vp, sb, flags, cred);
364 crfree(cred);
365 VN_RELE(vp);
366 if (error != 0) {
367 if (error == ESTALE &&
368 fs_need_estale_retry(estale_retry++))
369 goto lookup;
370 return (set_errno(error));
372 return (0);
375 #endif /* _SYSCALL32_IMPL */
377 #if defined(_ILP32)
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 *);
387 static inline int
388 fstat64(int fd, struct stat64 *sb)
390 FSTAT_BODY(fd, sb, cstat64)
394 fstatat64(int fd, char *name, struct stat64 *sb, int flags)
396 int followflag;
397 int csflags;
399 if (name == NULL)
400 return (fstat64(fd, sb));
402 followflag = (flags & AT_SYMLINK_NOFOLLOW);
403 csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
404 if (followflag == 0)
405 csflags |= ATTR_REAL; /* flag for procfs lookups */
407 return (cstatat64(fd, name, sb, followflag, csflags));
410 static int
411 cstat64(vnode_t *vp, struct stat64 *ubp, int flag, cred_t *cr)
413 struct vfssw *vswp;
414 struct stat64 lsb;
415 vattr_t vattr;
416 int error;
418 vattr.va_mask = VATTR_STAT | VATTR_NBLOCKS | VATTR_BLKSIZE | VATTR_SIZE;
419 if (error = fop_getattr(vp, &vattr, flag, cr, NULL))
420 return (error);
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)))
442 return (EFAULT);
443 return (0);
446 static int
447 cstatat64(int fd, char *name, struct stat64 *sb, int follow, int flags)
449 vnode_t *vp;
450 int error;
451 cred_t *cred;
452 int link_follow;
453 int estale_retry = 0;
455 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
456 lookup:
457 if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
458 return (set_errno(error));
459 error = cstat64(vp, sb, flags, cred);
460 crfree(cred);
461 VN_RELE(vp);
462 if (error != 0) {
463 if (error == ESTALE &&
464 fs_need_estale_retry(estale_retry++))
465 goto lookup;
466 return (set_errno(error));
468 return (0);
471 #endif /* _ILP32 */
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 *);
486 static inline int
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)
495 int followflag;
496 int csflags;
498 if (name == NULL)
499 return (fstat64_32(fd, sb));
501 followflag = (flags & AT_SYMLINK_NOFOLLOW);
502 csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
503 if (followflag == 0)
504 csflags |= ATTR_REAL; /* flag for procfs lookups */
506 return (cstatat64_32(fd, name, sb, followflag, csflags));
509 static int
510 cstat64_32(vnode_t *vp, struct stat64_32 *ubp, int flag, cred_t *cr)
512 struct vfssw *vswp;
513 struct stat64_32 lsb;
514 vattr_t vattr;
515 int error;
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))
520 return (error);
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)))
527 return (EOVERFLOW);
529 bzero(&lsb, sizeof (lsb));
530 lsb.st_dev = st_dev;
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)))
549 return (EFAULT);
550 return (0);
553 static int
554 cstatat64_32(int fd, char *name, struct stat64_32 *sb, int follow, int flags)
556 vnode_t *vp;
557 int error;
558 cred_t *cred;
559 int link_follow;
560 int estale_retry = 0;
562 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
563 lookup:
564 if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
565 return (set_errno(error));
566 error = cstat64_32(vp, sb, flags, cred);
567 crfree(cred);
568 VN_RELE(vp);
569 if (error != 0) {
570 if (error == ESTALE &&
571 fs_need_estale_retry(estale_retry++))
572 goto lookup;
573 return (set_errno(error));
575 return (0);
578 #endif /* _SYSCALL32_IMPL */