您的位置:首页 > 其它

glibc源码分析之stat系列函数

2017-08-14 19:58 841 查看
glibc中stat系列函数有stat,fstat,lstat。它们都是系统调用的封装函数。

关于stat的系统调用有oldstat(18),oldfstat(28),oldlstat(84),stat(106),lstat(107),fstat(108),stat64(195),lstat64(196),fstat64(197)。oldstat系列系统调用被stat系列系统调用替代了。stat系列系统调用用于获取文件属性,文件属性为32位,而stat64系列系统调用则用于获取文件属性,文件属性是64位。所以stat系列系统调用不能获取长度超过32位的文件的属性。

stat,fstat,lstat函数在封装是都是使用stat64系列系统调用,而不是使用stat系列系统调用。

查看stat函数的源码:

#undef stat
int
attribute_hidden
__stat (const char *file, struct stat *buf)
{
return __xstat (_STAT_VER, file, buf);
}

weak_hidden_alias (__stat, stat)


函数__stat调用了__xstat 函数。而__xstat 函数定义在sysdeps/unix/sysv/linux/i386/xstat.c文件中。

int
__xstat (int vers, const char *name, struct stat *buf)
{
int result;

if (vers == _STAT_VER_KERNEL)
return INLINE_SYSCALL (stat, 2, name, buf);

{
struct stat64 buf64;

INTERNAL_SYSCALL_DECL (err);
result = INTERNAL_SYSCALL (stat64, err, 2, name, &buf64);
if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result, err)))
return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result,
err));
else
return __xstat32_conv (vers, &buf64, buf);
}
}
hidden_def (__xstat)
weak_alias (__xstat, _xstat);


如果参数vers 等于_STAT_VER_KERNEL,则直接调用stat系统调用。显然,__stat传入的参数是_STAT_VER。

__xstat 函数首先调用stat64系统调用,获取了文件属性。然后,判断返回值是否出错,如果是则返回-1,并设置errno。如果执行正确,则将文件属性转化为32位,并返回0。

文件属性转换源码:

int
__xstat32_conv (int vers, struct stat64 *kbuf, struct stat *buf)
{
switch (vers)
{
case _STAT_VER_LINUX:
{

buf->st_dev = kbuf->st_dev;
#ifdef _HAVE_STAT___PAD1
buf->__pad1 = 0;
#endif
#ifdef _HAVE_STAT64___ST_INO
# if !__ASSUME_ST_INO_64_BIT
if (kbuf->st_ino == 0)
buf->st_ino = kbuf->__st_ino;
else
# endif
{
buf->st_ino = kbuf->st_ino;
if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino)
&& buf->st_ino != kbuf->st_ino)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
}
#else
buf->st_ino = kbuf->st_ino;
if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino)
&& buf->st_ino != kbuf->st_ino)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
#endif
buf->st_mode = kbuf->st_mode;
buf->st_nlink = kbuf->st_nlink;
buf->st_uid = kbuf->st_uid;
buf->st_gid = kbuf->st_gid;
buf->st_rdev = kbuf->st_rdev;
#ifdef _HAVE_STAT___PAD2
buf->__pad2 = 0;
#endif
buf->st_size = kbuf->st_size;
/* Check for overflow.  */
if (sizeof (buf->st_size) != sizeof (kbuf->st_size)
&& buf->st_size != kbuf->st_size)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
buf->st_blksize = kbuf->st_blksize;
buf->st_blocks = kbuf->st_blocks;
/* Check for overflow.  */
if (sizeof (buf->st_blocks) != sizeof (kbuf->st_blocks)
&& buf->st_blocks != kbuf->st_blocks)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
#ifdef _HAVE_STAT_NSEC
buf->st_atim.tv_sec = kbuf->st_atim.tv_sec;
buf->st_atim.tv_nsec = kbuf->st_atim.tv_nsec;
buf->st_mtim.tv_sec = kbuf->st_mtim.tv_sec;
buf->st_mtim.tv_nsec = kbuf->st_mtim.tv_nsec;
buf->st_ctim.tv_sec = kbuf->st_ctim.tv_sec;
buf->st_ctim.tv_nsec = kbuf->st_ctim.tv_nsec;
#else
buf->st_atime = kbuf->st_atime;
buf->st_mtime = kbuf->st_mtime;
buf->st_ctime = kbuf->st_ctime;
#endif

#ifdef _HAVE_STAT___UNUSED1
buf->__glibc_reserved1 = 0;
#endif
#ifdef _HAVE_STAT___UNUSED2
buf->__glibc_reserved2 = 0;
#endif
#ifdef _HAVE_STAT___UNUSED3
buf->__glibc_reserved3 = 0;
#endif
#ifdef _HAVE_STAT___UNUSED4
buf->__glibc_reserved4 = 0;
#endif
#ifdef _HAVE_STAT___UNUSED5
buf->__glibc_reserved5 = 0;
#endif
}
break;

/* If struct stat64 is different from struct stat then
_STAT_VER_KERNEL does not make sense.  */
case _STAT_VER_KERNEL:
default:
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
}

return 0;
}


#define _STAT_VER_LINUX     3
#define _STAT_VER       _STAT_VER_LINUX /* The one defined below.  */


fstat函数源码:

#undef fstat
#undef __fstat
int
attribute_hidden
__fstat (int fd, struct stat *buf)
{
return __fxstat (_STAT_VER, fd, buf);
}

weak_hidden_alias (__fstat, fstat)


__fstat函数调用了__fxstat 函数。而__fxstat 函数定义在sysdeps/unix/sysv/linux/i386/fxstat.c文件中。

int
__fxstat (int vers, int fd, struct stat *buf)
{
int result;

if (vers == _STAT_VER_KERNEL)
return INLINE_SYSCALL (fstat, 2, fd, buf);

{
struct stat64 buf64;

INTERNAL_SYSCALL_DECL (err);
result = INTERNAL_SYSCALL (fstat64, err, 2, fd, &buf64);
if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result, err)))
return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result,
err));
else
return __xstat32_conv (vers, &buf64, buf);
}
}

hidden_def (__fxstat)
weak_alias (__fxstat, _fxstat);


__fxstat 函数调用过程类似于__xstat函数。

lstat函数源码:

#undef lstat
#undef __lstat
int
attribute_hidden
__lstat (const char *file, struct stat *buf)
{
return __lxstat (_STAT_VER, file, buf);
}

weak_hidden_alias (__lstat, lstat)


__lstat函数调用了__fxstat 函数。而__lxstat 函数定义在sysdeps/unix/sysv/linux/i386/lxstat.c文件中。

int
__lxstat (int vers, const char *name, struct stat *buf)
{
int result;

if (vers == _STAT_VER_KERNEL)
return INLINE_SYSCALL (lstat, 2, name, buf);

{
struct stat64 buf64;

INTERNAL_SYSCALL_DECL (err);
result = INTERNAL_SYSCALL (lstat64, err, 2, name, &buf64);
if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result, err)))
return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result,
err));
else
return __xstat32_conv (vers, &buf64, buf);
}
}

hidden_def (__lxstat)
weak_alias (__lxstat, _lxstat);


__lxstat 函数调用过程类似于__xstat函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: