⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 getcwd.c

📁 T-kernel 的extension源代码
💻 C
字号:
/* *---------------------------------------------------------------------- *    T-Kernel / Standard Extension * *    Copyright (C) 2006 by Ken Sakamura. All rights reserved. *    T-Kernel / Standard Extension is distributed  *      under the T-License for T-Kernel / Standard Extension. *---------------------------------------------------------------------- * *    Version:   1.00.00 *    Released by T-Engine Forum(http://www.t-engine.org) at 2006/8/11. * *---------------------------------------------------------------------- *//* *	@(#)getcwd.c (seio)  * */#include <basic.h>#include <tk/tkernel.h>#include <seio/unistd.h>#include <seio/sys/types.h>#include <seio/sys/stat.h>#include <seio/dirent.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include "sfimport.h"IMPORT DIR* opendir( const char *path );IMPORT struct dirent* readdir( DIR *dp );IMPORT int closedir( DIR *dp );struct pathbuf {	B	*buf;		/* Buffer for storing path name */	size_t	bufsz;		/* Size of "buf" (0 when a fixed length is specified) */	B	*cp;		/* Current position */	B	*ep;		/* Termination position */};#define	EXBUFSZ		256U	/* Extended unit (byte count) of the buffer for storing path name *//* ------------------------------------------------------------------------ *//* * Path name currently being stored */#define	cupdir(pb)		( (pb)->buf )/* * The save and restoring of the current path name */#define	saveupdir(pb)		( (pb)->cp - (pb)->buf )#define	restoreupdir(pb, n)	( *((pb)->cp = (pb)->buf + (n)) = '\0' )#define SIZE_2_CHK	2U	/* size check *//* * Initialize the buffer for creating the path name of parent dirtectory */static void initupdir( struct pathbuf *pb ){	pb->buf = NULL;	pb->bufsz = 0;	pb->cp = NULL;	pb->ep = NULL;}/* * Create the path name to trace a parent directory *	Add "name" to the behind the path name. *	Return the pointer referring to the path name character-string to return value. *	Return "NULL" when error occurs. */static char* updir( struct pathbuf *pb, const char *name, size_t len ){	size_t	sz;	B	*p;	sz = (size_t)(pb->ep - pb->cp);	if ( (len + 1U) > sz ) {		/* +1 is the length for '\0' at the termination */		/* Buffer expansion */		sz = (((len + 1U) - sz + (EXBUFSZ-1U)) / EXBUFSZ) * EXBUFSZ;		p = realloc(pb->buf, pb->bufsz + sz);		if ( p == NULL ) {			return NULL;		}		pb->bufsz += sz;		pb->cp = p + (pb->cp - pb->buf);		pb->ep = p + pb->bufsz;		pb->buf = p;	}	/* Connect "name " with backward */	memcpy(pb->cp, name, len);	pb->cp += len;	*pb->cp = '\0';	return pb->buf;}/* ------------------------------------------------------------------------ *//* * Prepare the buffer for creating the path name of current directory *	Fix the size of buffer when "buf != NULL". *	Use "buf" to buffer and set "size " to the size. *	Allocate the buffer with "malloc()" when "buf == NULL". *	Ignore "size". *	Return the pointer referring to path name-string to return value. *	Return "NULL" when error occurs. */static char* initcwdir( struct pathbuf *pb, char *buf, size_t size ){	B	*p;	if ( buf == NULL ) {		/* Allocate the buffer with "malloc()". */		p = malloc(EXBUFSZ);		if ( p == NULL ) {			return NULL;		}		pb->buf = p;		pb->bufsz = EXBUFSZ;		pb->cp = p + EXBUFSZ;		pb->ep = p;	} else {		/* Fix the buffer */		if ( size < SIZE_2_CHK ) {			errno = ( size == 0U )? EINVAL: ERANGE;			return NULL;		}		pb->buf = buf;		pb->bufsz = 0;		pb->cp = buf + size;		pb->ep = buf;	}	*--pb->cp = '\0';	return pb->cp;}/* * Add "name" to the path name of current directory *	Insert '/' before the path name and add "name" *	Length of "len" is that of "name" (excluding '\0'). *	Return the pointer referring to path name-string to the return value. *	Return "NULL" when error occurs. */static char* cwdir( struct pathbuf *pb, const char *name, size_t len ){	size_t	sz, n;	B	*p;	/* Constantly allocate the space for one character so that the '/' at the top of path name can * be added  */	sz = (size_t)(pb->cp - pb->ep);	n = 1;				/* Space for the '/' at the top */	if ( *pb->cp != '\0' ) {		n += 1U;	/* Space for the delimiter '/' (unecessary for termination) */	}	if ( (len + n) > sz ) {		if ( pb->bufsz == 0U ) {			/* Error occurs when it is the buffer fixed length */			errno = ERANGE;			return NULL;		}		/* Buffer expansion */		sz = (((len + n) - sz + (EXBUFSZ-1U)) / EXBUFSZ) * EXBUFSZ;		p = realloc(pb->buf, pb->bufsz + sz);		if ( p == NULL ) {			return NULL;		}		/* Move the content of buffer to backward, and make room for the front */		memmove(p + sz, p, (size_t)pb->bufsz);		pb->cp = p + sz + (pb->cp - pb->buf);		pb->ep = p;		pb->buf = p;		pb->bufsz += sz;	}	/* Delimit with '/' , connect "name" with front */	if ( *pb->cp != '\0' ) {		*--pb->cp = '/';	/* '/' is unnecessary for the termination of path name */	}	pb->cp -= len;	memcpy(pb->cp, name, len);	return pb->cp;}/* * Fix the path name of current directory *	Attach '/' with the top of path name, and make an adjustment so that the path name can *      be stored from the top of buffer. *	Return the pointer referring to path name-string to return value. */static char* fixcwdir( struct pathbuf *pb ){	/* The size of buffer is being adjusted so that the  '/' at the top can be certainly inserted */	*--pb->cp = '/';	if ( pb->cp != pb->buf ) {		char *sp = pb->cp;		char *dp = pb->buf;		while ( (*(dp++) = *(sp++)) != '\0' ) {			;		}	}	return pb->buf;}/* ------------------------------------------------------------------------ *//* * Get the absolute path name of current directory *	In the case of "buf != NULL", "size" is the size of the array indicated by "buf", and *      error occurs when the path name exceeds the "size" byte (including the termination of *      character-string '\0').In the case of "buf == NULL", the "size" is ignored, and the *      buffer of necessary size for storing path name is obtained by "malloc()" and is set *      as "buf".The absolute path name of current directory is stored in "buf",and the "buf" *      is retuned to return value. *	Return "NULL" to return value when error occurs. */EXPORT char* getcwd( char *buf, size_t size ){	struct pathbuf	upd, cwd;	struct stat	sb;	dev_t		dev, root_dev;	ino_t		ino, root_ino;	DIR		*dir = NULL;	struct dirent	*de;	W		save_errno;	W		n;	W		same_dev;	save_errno = errno;	errno = 0;	/* Prepare the buffer for storing the path name of current directory */	if ( initcwdir(&cwd, buf, size) == NULL ) {		return NULL;	}	/* Prepare the buffer for storing the path name to trace parent directory */	initupdir(&upd);	if ( updir(&upd, ".", 1) == NULL ) {		goto err_ret;	}	/* Root directory */	if ( stat("/", &sb) < 0 ) {		goto err_ret;	}	root_dev = sb.st_dev;	root_ino = sb.st_ino;	/* Search the path name from current directory toward root directory */	for ( ;; ) {		if ( stat(cupdir(&upd), &sb) < 0 ) {			goto err_ret;		}		dev = sb.st_dev;		ino = sb.st_ino;		/* Complete the search when the pat matches the root directory */		if (( ino == root_ino )&&( dev == root_dev )) {			break;		}		/* Go to next level of directory */		if ( updir(&upd, "/..", 3) == NULL ) {			goto err_ret;		}		/* Search in the parent directory */		dir = opendir(cupdir(&upd));		if ( dir == NULL ) {			goto err_ret;		}		if ( fstat(dirfd(dir), &sb) < 0 ) {			goto err_ret;		}		same_dev = ( sb.st_dev == dev );		for ( ;; ) {			de = readdir(dir);			if ( de == NULL ) {				goto not_exist;			}			/* OK if it matches "ino" when the identical file system is used */			if ( same_dev != 0 ) {				if ( de->d_fileno == ino ) {					break;				}				continue;			}			/* Exclude "." and ".." */			if (( de->d_name[0] == '.' )&&( (de->d_name[1] == '\0' )			  ||((de->d_name[1] == '.' )&&( de->d_name[2] == '\0'))) ) {				continue;			}			/* Also check the consistensy with the file system when different file system is used */			n = saveupdir(&upd);			if (( updir(&upd, "/", 1) == NULL )			  ||( updir(&upd, de->d_name, de->d_namlen) == NULL )) {			  	goto err_ret;			}			if ( lstat(cupdir(&upd), &sb) < 0 ) {				goto err_ret;			}			restoreupdir(&upd, n);			if (( sb.st_dev == dev )&&( sb.st_ino == ino )) {				break;			}		}		/* Connect the found directory name */		if ( cwdir(&cwd, de->d_name, de->d_namlen) == NULL ) {			goto err_ret;		}		(void)closedir(dir);		dir = NULL;	}	free(upd.buf);	errno = save_errno;	return fixcwdir(&cwd);not_exist:	if ( errno == 0 ) {		errno = ENOENT;	}err_ret:	if ( dir != NULL ) {		(void)closedir(dir);	}	if ( cwd.bufsz > 0U ) {		free(cwd.buf);	}	if ( upd.buf != NULL ) {		free(upd.buf);	}	return NULL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -