📄 osutil.cxx
字号:
/*
* osutil.cxx
*
* Operating System classes implementation
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* $Log: osutil.cxx,v $
* Revision 1.48 1999/08/17 07:37:36 robertj
* Fixed inlines so are inlined for optimised version
*
* Revision 1.47 1999/06/28 09:28:02 robertj
* Portability issues, especially n BeOS (thanks Yuri!)
*
* Revision 1.46 1999/06/26 08:21:12 robertj
* Fixed bug in PFilePath::SetType finding dots outside of file name in path.
*
* Revision 1.45 1999/06/14 08:39:57 robertj
* Added PConsoleChannel class for access to stdin/stdout/stderr
*
* Revision 1.44 1999/06/09 04:08:46 robertj
* Added support for opening stdin/stdout/stderr as PFile objects.
*
* Revision 1.43 1999/02/22 13:26:53 robertj
* BeOS port changes.
*
* Revision 1.42 1998/12/12 01:06:24 robertj
* Fixed off by one error in month on FreeBSD platform
*
* Revision 1.41 1998/11/30 21:51:43 robertj
* New directory structure.
*
* Revision 1.40 1998/11/26 11:54:16 robertj
* Fixed error return on PFile::GetInfo
*
* Revision 1.39 1998/11/24 09:39:09 robertj
* FreeBSD port.
*
* Revision 1.38 1998/11/10 13:00:52 robertj
* Fixed strange problems with readdir_r usage.
*
* Revision 1.37 1998/11/06 04:44:46 robertj
* Solaris compatibility
*
* Revision 1.36 1998/11/05 12:03:13 robertj
* Fixed solaris compatibility and Linux warning on readdir_r function.
*
* Revision 1.35 1998/11/05 09:05:55 craigs
* Changed directory routines to use reenttrant functions, and added PDirectory::GetParent
*
* Revision 1.34 1998/09/24 07:39:49 robertj
* Removed file that only had #pragma implmentation for PTextFile and nothing else.
*
* Revision 1.33 1998/09/24 04:12:12 robertj
* Added open software license.
*
*/
#define _OSUTIL_CXX
#pragma implementation "timer.h"
#pragma implementation "pdirect.h"
#pragma implementation "file.h"
#pragma implementation "textfile.h"
#pragma implementation "conchan.h"
#pragma implementation "ptime.h"
#pragma implementation "timeint.h"
#pragma implementation "filepath.h"
#pragma implementation "lists.h"
#pragma implementation "pstring.h"
#pragma implementation "dict.h"
#pragma implementation "array.h"
#pragma implementation "object.h"
#pragma implementation "contain.h"
#if defined(P_LINUX)
#define _REENTRANT
#elif defined(P_SOLARIS)
#define _POSIX_PTHREAD_SEMANTICS
#endif
#include <ptlib.h>
#include <fcntl.h>
#include <time.h>
#if !defined(P_VXWORKS) // added by Jurjan
#include <sys/time.h>
#endif
#include <ctype.h>
#if defined(P_LINUX)
#include <mntent.h>
#include <sys/vfs.h>
#define P_HAS_READDIR_R
#if (__GNUC_MINOR__ < 7)
#include <localeinfo.h>
#else
#define P_USE_LANGINFO
#endif
#elif defined(P_FREEBSD)
#define P_USE_STRFTIME
#include <sys/param.h>
#include <sys/mount.h>
#elif defined(P_HPUX9)
#define P_USE_LANGINFO
#elif defined(P_SOLARIS)
#define P_HAS_READDIR_R
#define P_USE_LANGINFO
#include <sys/timeb.h>
#include <sys/statvfs.h>
#include <sys/mnttab.h>
#elif defined(P_SUN4)
#include <sys/timeb.h>
#elif defined (P_VXWORKS) // added by Jurjan
#include <time.h>
#include <sys/stat.h>
#include <private/stdioP.h>
#include <u_Lib.h>
#define P_USE_STRFTIME
#endif
#ifdef P_USE_LANGINFO
#include <langinfo.h>
#endif
#define LINE_SIZE_STEP 100
#define DEFAULT_FILE_MODE (S_IRUSR|S_IWUSR|S_IROTH|S_IRGRP)
#if !P_USE_INLINES
#include <ptlib/osutil.inl>
#include <ptlib/ptlib.inl>
#endif
#ifdef P_SUN4
extern "C" {
int on_exit(void (*f)(void), caddr_t);
int atexit(void (*f)(void))
{
return on_exit(f, 0);
}
static char *tzname[2] = { "STD", "DST" };
};
#endif
#define new PNEW
static PString CanonicaliseDirectory (const PString & path)
{
PString canonical_path;
PString slash("/");
// if the path does not start with a slash, then the current directory
// must be prepended
if (path.IsEmpty() || path[0] != '/') {
char *p = getcwd(canonical_path.GetPointer(P_MAX_PATH), P_MAX_PATH);
PAssertOS (p != NULL);
}
// if the path doesn't end in a slash, add one
if (canonical_path[canonical_path.GetLength()-1] != '/')
canonical_path += slash;
const char * ptr = path;
const char * end;
for (;;) {
// ignore slashes
while (*ptr == '/' && *ptr != '\0')
ptr++;
// finished if end of string
if (*ptr == '\0')
break;
// collect non-slash characters
end = ptr;
while (*end != '/' && *end != '\0')
end++;
// make a string out of the element
PString element(ptr, end - ptr);
if (element == "..") {
PINDEX last_char = canonical_path.GetLength()-1;
if (last_char > 0)
canonical_path = canonical_path.Left(canonical_path.FindLast('/', last_char-1)+1);
} else if (element == "." || element == "") {
} else {
canonical_path += element;
canonical_path += slash;
}
ptr = end;
}
return canonical_path;
}
static PString CanonicaliseFilename(const PString & filename)
{
PINDEX p;
PString dirname;
// if there is a slash in the string, extract the dirname
if ((p = filename.FindLast('/')) != P_MAX_INDEX) {
dirname = filename(0,p);
while (filename[p] == '/')
p++;
} else
p = 0;
return CanonicaliseDirectory(dirname) + filename(p, P_MAX_INDEX);
}
PInt64 PString::AsInt64(unsigned base) const
{
#if defined(P_SOLARIS) || defined(__BEOS__)
char * dummy;
return strtoll(theArray, &dummy, base);
#elif defined (P_VXWORKS)
char * dummy;
return strtol(theArray, &dummy, base);
#else
return strtoq(theArray, &dummy, base);
#endif
}
PUInt64 PString::AsUnsigned64(unsigned base) const
{
#if defined(P_SOLARIS) || defined(__BEOS__)
char * dummy;
return strtoull(theArray, &dummy, base);
#elif defined (P_VXWORKS)
char * dummy;
return strtoul(theArray, &dummy, base);
#else
return strtouq(theArray, &dummy, base);
#endif
}
///////////////////////////////////////////////////////////////////////////////
//
// timer
PTimeInterval PTimer::Tick()
{
#if defined(P_VXWORKS) // added by Jurjan
struct timespec ts;
clock_gettime(0, &ts);
// printf("total: %ld\n", ((ts.tv_sec * 10000) + (ts.tv_nsec/100000L)));
return (int)(ts.tv_sec * 10000) + (ts.tv_nsec/100000L);
// return ts.tv_nsec;
#else
struct timeval tv;
::gettimeofday (&tv, NULL);
return (PInt64)(tv.tv_sec) * 1000 + tv.tv_usec/1000L;
#endif
}
///////////////////////////////////////////////////////////////////////////////
//
// PDirectory
//
void PDirectory::CopyContents(const PDirectory & d)
{
if (d.entryInfo == NULL)
entryInfo = NULL;
else {
entryInfo = new PFileInfo;
*entryInfo = *d.entryInfo;
}
directory = NULL;
entryBuffer = NULL;
}
void PDirectory::Close()
{
if (directory != NULL) {
PAssert(closedir(directory) == 0, POperatingSystemError);
directory = NULL;
}
if (entryBuffer != NULL) {
free(entryBuffer);
entryBuffer = NULL;
}
if (entryInfo != NULL) {
delete entryInfo;
entryInfo = NULL;
}
}
void PDirectory::Construct ()
{
directory = NULL;
entryBuffer = NULL;
entryInfo = NULL;
PString::operator =(CanonicaliseDirectory(*this));
}
BOOL PDirectory::Open(int ScanMask)
{
if (directory != NULL)
Close();
scanMask = ScanMask;
if ((directory = opendir(theArray)) == NULL)
return FALSE;
entryBuffer = (struct dirent *)malloc(sizeof(struct dirent) + P_MAX_PATH);
entryInfo = new PFileInfo;
if (Next())
return TRUE;
Close();
return FALSE;
}
BOOL PDirectory::Next()
{
if (directory == NULL)
return FALSE;
do {
do {
struct dirent * entryPtr;
entryBuffer->d_name[0] = '\0';
#ifdef P_HAS_READDIR_R
if (::readdir_r(directory, entryBuffer, &entryPtr) != 0)
return FALSE;
if (entryPtr != entryBuffer)
return FALSE;
#else
if ((entryPtr = readdir(directory)) == NULL)
return FALSE;
*entryBuffer = *entryPtr;
strcpy(entryBuffer->d_name, entryPtr->d_name);
#endif
} while (strcmp(entryBuffer->d_name, "." ) == 0 || strcmp(entryBuffer->d_name, "..") == 0);
PAssert(PFile::GetInfo(*this+entryBuffer->d_name, *entryInfo), POperatingSystemError);
if (scanMask == PFileInfo::AllPermissions)
return TRUE;
} while ((entryInfo->type & scanMask) == 0);
return TRUE;
}
BOOL PDirectory::IsSubDir() const
{
if (entryInfo == NULL)
return FALSE;
return entryInfo->type == PFileInfo::SubDirectory;
}
BOOL PDirectory::Restart(int newScanMask)
{
scanMask = newScanMask;
if (directory != NULL)
rewinddir(directory);
return TRUE;
}
PString PDirectory::GetEntryName() const
{
if (entryBuffer == NULL)
return PString();
return entryBuffer->d_name;
}
BOOL PDirectory::GetInfo(PFileInfo & info) const
{
info = *entryInfo;
return TRUE;
}
BOOL PDirectory::Create(const PString & p, int perm)
{
#if defined(P_VXWORKS) // added by Jurjan
PAssert(!p.IsEmpty(), "attempt to create dir with empty name");
PString str = p.Left(p.GetLength()-1);
return mkdir((char *)(const char *)str) == OK;
#else
PAssert(!p.IsEmpty(), "attempt to create dir with empty name");
PString str = p.Left(p.GetLength()-1);
return mkdir(str, perm) == 0;
#endif
}
BOOL PDirectory::Remove(const PString & p)
{
#if defined(P_VXWORKS) // added by Jurjan
PAssert(!p.IsEmpty(), "attempt to remove dir with empty name");
PString str = p.Left(p.GetLength()-1);
return rmdir((char *)(const char *)str) == 0;
#else
PAssert(!p.IsEmpty(), "attempt to remove dir with empty name");
PString str = p.Left(p.GetLength()-1);
return rmdir(str) == 0;
#endif
}
PString PDirectory::GetVolume() const
{
PString volume;
// struct stat status;
#if defined(P_VXWORKS) // added by Jurjan
// if (stat((char *)(const char *)operator+("."), &status) != -1) {
// dev_t my_dev = status.st_dev;
#else
if (stat(operator+("."), &status) != -1) {
dev_t my_dev = status.st_dev;
#endif
#if defined(P_LINUX)
FILE * fp = setmntent(MOUNTED, "r");
if (fp != NULL) {
struct mntent * mnt;
while ((mnt = getmntent(fp)) != NULL) {
if (stat(mnt->mnt_dir, &status) != -1 && status.st_dev == my_dev) {
volume = mnt->mnt_fsname;
break;
}
}
}
endmntent(fp);
#elif defined(P_SOLARIS)
FILE * fp = fopen("/etc/mnttab", "r");
if (fp != NULL) {
struct mnttab mnt;
while (getmntent(fp, &mnt) == 0) {
if (stat(mnt.mnt_mountp, &status) != -1 && status.st_dev == my_dev) {
volume = mnt.mnt_special;
break;
}
}
}
fclose(fp);
#elif defined(P_FREEBSD)
struct statfs * mnt;
int count = getmntinfo(&mnt, MNT_NOWAIT);
for (int i = 0; i < count; i++) {
if (stat(mnt[i].f_mntonname, &status) != -1 && status.st_dev == my_dev) {
volume = mnt[i].f_mntfromname;
break;
}
}
#elif defined (P_VXWORKS)
PAssertAlways("GetVolume() not implemented on VxWorks");
return "";
#else
#warning Platform requires implemetation of GetVolume()
#endif
return volume;
}
BOOL PDirectory::GetVolumeSpace(PInt64 & total, PInt64 & free, DWORD & clusterSize) const
{
#if defined(P_LINUX) || defined(P_FREEBSD)
struct statfs fs;
if (statfs(operator+("."), &fs) == -1)
return FALSE;
clusterSize = fs.f_bsize;
total = fs.f_blocks*(PInt64)fs.f_bsize;
free = fs.f_bavail*(PInt64)fs.f_bsize;
return TRUE;
#elif defined(P_SOLARIS)
struct statvfs buf;
if (statvfs(operator+("."), &buf) != 0)
return FALSE;
clusterSize = buf.f_frsize;
total = buf.f_blocks * buf.f_frsize;
free = buf.f_bfree * buf.f_frsize;
return TRUE;
#elif defined (P_VXWORKS)
PAssertAlways("GetVolumeSpace nor implemeted on VxWorks");
return FALSE;
#else
#warning Platform requires implemetation of GetVolumeSpace()
return FALSE;
#endif
}
PDirectory PDirectory::GetParent() const
{
if (IsRoot())
return *this;
return *this + "..";
}
///////////////////////////////////////////////////////////////////////////////
//
// PFile
//
void PFile::SetFilePath(const PString & newName)
{
PINDEX p;
if ((p = newName.FindLast('/')) == P_MAX_INDEX)
path = CanonicaliseDirectory("") + newName;
else
path = CanonicaliseDirectory(newName(0,p)) + newName(p+1, P_MAX_INDEX);
}
BOOL PFile::Open(OpenMode mode, int opt)
{
Close();
clear();
#ifndef P_VXWORKS
if (path.IsEmpty()) {
char * tmp = tempnam(NULL, "PWL");
PAssert(tmp != NULL, POperatingSystemError);
path = PString(tmp);
runtime_free(tmp);
}
int oflags = 0;
switch (mode) {
case ReadOnly :
oflags |= O_RDONLY;
if (opt == ModeDefault)
opt = MustExist;
break;
case WriteOnly :
oflags |= O_WRONLY;
if (opt == ModeDefault)
opt = Create|Truncate;
break;
case ReadWrite :
oflags |= O_RDWR;
if (opt == ModeDefault)
opt = Create;
break;
default :
PAssertAlways(PInvalidParameter);
}
if ((opt&Create) != 0)
oflags |= O_CREAT;
if ((opt&Exclusive) != 0)
oflags |= O_EXCL;
if ((opt&Truncate) != 0)
oflags |= O_TRUNC;
removeOnClose = opt & Temporary;
if (!ConvertOSError(os_handle = ::open(path, oflags, DEFAULT_FILE_MODE)))
return FALSE;
#if defined(P_VXWORKS)
return ConvertOSError(::u_fcntl(os_handle, F_SETFD, 1));
#else
return ConvertOSError(::fcntl(os_handle, F_SETFD, 1));
#endif
#else // vxworks
PAssertAlways("osutil: Access");
return FALSE;
#endif
}
BOOL PFile::SetLength(off_t len)
{
return ConvertOSError(ftruncate(GetHandle(), len));
}
BOOL PFile::Rename(const PFilePath & oldname, const PString & newname, BOOL force)
{
if (newname.Find('/') != P_MAX_INDEX) {
errno = EINVAL;
return FALSE;
}
if (rename(oldname, oldname.GetPath() + newname) == 0)
return TRUE;
if (!force || errno == ENOENT || !Exists(newname))
return FALSE;
if (!Remove(newname, TRUE))
return FALSE;
return rename(oldname, oldname.GetPath() + newname) == 0;
}
BOOL PFile::Move(const PFilePath & oldname, const PFilePath & newname, BOOL force)
{
PFilePath from = oldname.GetDirectory() + oldname.GetFileName();
PFilePath to = newname.GetDirectory() + newname.GetFileName();
if (rename(from, to) == 0)
return TRUE;
if (errno == EXDEV)
return Copy(from, to, force) && Remove(from);
if (force && errno == EEXIST)
if (Remove(to, TRUE))
if (rename(from, to) == 0)
return TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -