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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 33 * seekdir -- C library extension routine 34 */ 35 36 #include <sys/feature_tests.h> 37 38 #if !defined(_LP64) 39 #pragma weak _seekdir64 = seekdir64 40 #endif 41 #pragma weak _seekdir = seekdir 42 43 #include "lint.h" 44 #include "libc.h" 45 #include <mtlib.h> 46 #include <dirent.h> 47 #include <fcntl.h> 48 #include <unistd.h> 49 50 #ifdef _LP64 51 52 void 53 seekdir(DIR *dirp, long loc) 54 { 55 private_DIR *pdirp = (private_DIR *)dirp; 56 dirent_t *dp; 57 off_t off = 0; 58 59 lmutex_lock(&pdirp->dd_lock); 60 if (lseek(dirp->dd_fd, 0, SEEK_CUR) != 0) { 61 dp = (dirent_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 62 off = dp->d_off; 63 } 64 if (off != loc) { 65 dirp->dd_loc = 0; 66 (void) lseek(dirp->dd_fd, loc, SEEK_SET); 67 dirp->dd_size = 0; 68 69 /* 70 * Save seek offset in d_off field, in case telldir 71 * follows seekdir with no intervening call to readdir 72 */ 73 ((dirent_t *)(uintptr_t)&dirp->dd_buf[0])->d_off = loc; 74 } 75 lmutex_unlock(&pdirp->dd_lock); 76 } 77 78 #else /* _LP64 */ 79 80 /* 81 * Note: Instead of making this function static, we reduce it to local 82 * scope in the mapfile. That allows the linker to prevent it from 83 * appearing in the .SUNW_dynsymsort section. 84 */ 85 void 86 seekdir64(DIR *dirp, off64_t loc) 87 { 88 private_DIR *pdirp = (private_DIR *)(uintptr_t)dirp; 89 dirent64_t *dp64; 90 off64_t off = 0; 91 92 lmutex_lock(&pdirp->dd_lock); 93 if (lseek64(dirp->dd_fd, 0, SEEK_CUR) != 0) { 94 dp64 = (dirent64_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 95 /* was converted by readdir and needs to be reversed */ 96 if (dp64->d_ino == (ino64_t)-1) { 97 dirent_t *dp32; 98 99 dp32 = (dirent_t *)((uintptr_t)dp64 + sizeof (ino64_t)); 100 dp64->d_ino = (ino64_t)dp32->d_ino; 101 dp64->d_off = (off64_t)dp32->d_off; 102 dp64->d_reclen = (unsigned short)(dp32->d_reclen + 103 ((char *)&dp64->d_off - (char *)dp64)); 104 } 105 off = dp64->d_off; 106 } 107 if (off != loc) { 108 dirp->dd_loc = 0; 109 (void) lseek64(dirp->dd_fd, loc, SEEK_SET); 110 dirp->dd_size = 0; 111 112 /* 113 * Save seek offset in d_off field, in case telldir 114 * follows seekdir with no intervening call to readdir 115 */ 116 ((dirent64_t *)(uintptr_t)&dirp->dd_buf[0])->d_off = loc; 117 } 118 lmutex_unlock(&pdirp->dd_lock); 119 } 120 121 void 122 seekdir(DIR *dirp, long loc) 123 { 124 seekdir64(dirp, (off64_t)(uint32_t)loc); 125 } 126 127 #endif /* _LP64 */ 128