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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* Copyright (c) 1988 AT&T */ 30 /* All Rights Reserved */ 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 "synonyms.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 static void 81 seekdir64(DIR *dirp, off64_t loc) 82 { 83 private_DIR *pdirp = (private_DIR *)(uintptr_t)dirp; 84 dirent64_t *dp64; 85 off64_t off = 0; 86 87 lmutex_lock(&pdirp->dd_lock); 88 if (lseek64(dirp->dd_fd, 0, SEEK_CUR) != 0) { 89 dp64 = (dirent64_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 90 /* was converted by readdir and needs to be reversed */ 91 if (dp64->d_ino == (ino64_t)-1) { 92 dirent_t *dp32; 93 94 dp32 = (dirent_t *)((uintptr_t)dp64 + sizeof (ino64_t)); 95 dp64->d_ino = (ino64_t)dp32->d_ino; 96 dp64->d_off = (off64_t)dp32->d_off; 97 dp64->d_reclen = (unsigned short)(dp32->d_reclen + 98 ((char *)&dp64->d_off - (char *)dp64)); 99 } 100 off = dp64->d_off; 101 } 102 if (off != loc) { 103 dirp->dd_loc = 0; 104 (void) lseek64(dirp->dd_fd, loc, SEEK_SET); 105 dirp->dd_size = 0; 106 107 /* 108 * Save seek offset in d_off field, in case telldir 109 * follows seekdir with no intervening call to readdir 110 */ 111 ((dirent64_t *)(uintptr_t)&dirp->dd_buf[0])->d_off = loc; 112 } 113 lmutex_unlock(&pdirp->dd_lock); 114 } 115 116 void 117 seekdir(DIR *dirp, long loc) 118 { 119 seekdir64(dirp, (off64_t)loc); 120 } 121 122 #endif /* _LP64 */ 123