VError XMacFileSystemNotification::StartWatchingForChanges( const VFolder &inFolder, VFileSystemNotifier::EventKind inKindFilter, VFileSystemNotifier::IEventHandler *inHandler, sLONG inLatency )
{
	// We need to get the folder's path into an array for us to pass along to the OS call.
	VString posixPathString;
	inFolder.GetPath( posixPathString, FPS_POSIX);

	VStringConvertBuffer buffer( posixPathString, VTC_UTF_8);
	std::string posixPath( buffer.GetCPointer());

	CFStringRef pathRef = posixPathString.MAC_RetainCFStringCopy();
	CFArrayRef pathArray = CFArrayCreate( NULL, (const void **)&pathRef, 1, NULL );
	
	FSEventStreamContext context = { 0 };
	
	// The latency the user passed us is expressed in milliseconds, but the OS call requires the latency to be
	// expressed in seconds.
	CFTimeInterval latency = (inLatency / 1000.0);
	
	// Now we can make our change data object
	XMacChangeData *data = new XMacChangeData( inFolder.GetPath(), posixPath, inKindFilter, VTask::GetCurrent(), inHandler, this);
	context.info = data;
	data->fStreamRef = FSEventStreamCreate( NULL, &FSEventCallback, &context, pathArray, kFSEventStreamEventIdSinceNow, latency, kFSEventStreamCreateFlagNone );
	if (data->fStreamRef == NULL)
	{
		CFRelease( pathArray );
		CFRelease( pathRef );
		ReleaseRefCountable( &data);
		return MAKE_NATIVE_VERROR( errno );
	}
	
	// We also need to take an initial snapshot of the directory for us to compare again
	CreateDirectorySnapshot( posixPath, data->fSnapshot, true );
	
	// Now we can add the data object we just made to our list
	fOwner->PushChangeData( data);

	// Next, we can schedule this to run on the main event loop
	FSEventStreamScheduleWithRunLoop( data->fStreamRef, CFRunLoopGetMain(), kCFRunLoopDefaultMode );

	CFRelease( pathArray );
	CFRelease( pathRef );

	// Now that we've scheduled the stream to run on a helper thread, all that is left is to
	// start executing the stream
	VError err;
	if (FSEventStreamStart( data->fStreamRef ))
	{
		err = VE_OK;
	}
	else
	{
		err = MAKE_NATIVE_VERROR( errno );
	}
	ReleaseRefCountable( &data);
	
	return err;
}
//static
VError XLinuxFileDesc::CreateFile(const char* inPath, FileCreateOptions inCreateOpts)
{
	////////////////////////////////////////////////////////////////////////////////
	//
	// I'm pretty sure it doesn't behave in the same way than the windows platform.
	// (the share and overwrite behavior might be different)
	//
	////////////////////////////////////////////////////////////////////////////////

	//utiliser open helper

	int openFlags=0;
	
	if(inCreateOpts & FCR_Overwrite)
		openFlags|=O_RDONLY|O_CREAT;					//CREATE_ALWAYS ?
	else
		openFlags|=O_RDONLY|O_CREAT|O_EXCL;				//CREATE_NEW
	
	mode_t modeFlags=644;	//jmo - todo : virer ca !
	int fd=open(const_cast<char*>(inPath), openFlags, modeFlags);
	
	if(fd<0)
		return MAKE_NATIVE_VERROR(errno);
	
	close(fd);
	
	return VE_OK;
}
VError XWinFolder::Move( const VFolder& inNewParent, VFolder** outFolder ) const
{
	XBOX::VString name;
	VFilePath newPath( inNewParent.GetPath() );
	
	DWORD winErr;
	if (newPath.IsValid())
	{
		VString name;
		fOwner->GetName(name);
		newPath.ToSubFolder(name);

		XWinFullPath oldWinPath( fOwner->GetPath() );
		XWinFullPath newWinPath( newPath );
		
		winErr = ::MoveFileW( oldWinPath, newWinPath) ? 0 : ::GetLastError();
	}
	else
	{
		winErr = ERROR_INVALID_NAME;
	}

	if (outFolder)
	{
		*outFolder = (winErr == 0) ? new VFolder( newPath) : NULL;
	}
	
	return MAKE_NATIVE_VERROR( winErr);
}
VError XWinFolder::Rename( const VString& inName, VFolder** outFile ) const
{
	VFilePath newPath( fOwner->GetPath() );
	newPath.SetName( inName );
	
	DWORD winErr;
	if (newPath.IsValid())
	{
		XWinFullPath oldWinPath( fOwner->GetPath() );
		XWinFullPath newWinPath( newPath );
		
		winErr = ::MoveFileW( oldWinPath, newWinPath ) ? 0 : ::GetLastError();
	}
	else
	{
		winErr = ERROR_INVALID_NAME;
	}

	if (outFile)
	{
		*outFile = (winErr == 0) ? new VFolder( newPath) : NULL;
	}
	
	return MAKE_NATIVE_VERROR( winErr);
}
VError XLinuxFileDesc::GetSize(sLONG8 *outSize) const
{
	//There are two easy ways to implement this function : lseek and fstat.
	//Both are easy and should work. I choose lseek in an arbitrary way.

	//Utiliser stat helper !

	if(!IsValid())
		return VE_INVALID_PARAMETER;

	sLONG8 pos=0;
	sLONG8 end=0;

	VError verr=GetPos(&pos);
	
	if(verr==VE_OK)
		verr=SetPos(0, END);
	else
		return MAKE_NATIVE_VERROR(errno);

	if(verr==VE_OK)
		verr=GetPos(&end);
	
	if(verr==VE_OK)
	{
		*outSize=end;
		verr=SetPos(pos, SET);
	}

	xbox_assert(verr==VE_OK);	//We should always be able to restore seek ptr

    return verr;
}
示例#6
0
VError PathBuffer::InitWithCwd()
{
    if(getcwd(fPath, sizeof(fPath))==NULL)
        return MAKE_NATIVE_VERROR(errno);

    return VE_OK;
}
VError XWinFolder::GetTimeAttributes( VTime* outLastModification, VTime* outCreationTime, VTime* outLastAccess ) const
{
	WIN32_FILE_ATTRIBUTE_DATA info;
	SYSTEMTIME stime;

	XWinFullPath path( fOwner->GetPath());
	DWORD winErr = ::GetFileAttributesExW( path, GetFileExInfoStandard, &info) ? 0 : ::GetLastError();

	if (winErr == 0)
	{
		if ( outLastModification )
		{
			::FileTimeToSystemTime( &info.ftLastWriteTime, &stime);
			outLastModification->FromUTCTime( stime.wYear, stime.wMonth, stime.wDay, stime.wHour, stime.wMinute, stime.wSecond, stime.wMilliseconds );
		}
		if ( outCreationTime )
		{
			::FileTimeToSystemTime( &info.ftCreationTime, &stime);
			outCreationTime->FromUTCTime( stime.wYear, stime.wMonth, stime.wDay, stime.wHour, stime.wMinute, stime.wSecond, stime.wMilliseconds );
		}
		if ( outLastAccess )
		{
			::FileTimeToSystemTime( &info.ftLastAccessTime, &stime);
			outLastAccess->FromUTCTime( stime.wYear, stime.wMonth, stime.wDay, stime.wHour, stime.wMinute, stime.wSecond, stime.wMilliseconds );
		}
	}

	return MAKE_NATIVE_VERROR( winErr);
}
示例#8
0
VError MapHelper::Map(FileDescSystemRef inFd, VSize inSize)
{
    fSize=inSize;
    fAddr=mmap(fPreferedAddr, fSize, fProt, fFlags, inFd, fOffset);

    return (fAddr!=MAP_FAILED) ? VE_OK : MAKE_NATIVE_VERROR(errno);
}
示例#9
0
VError XLinuxFileDesc::Flush() const
{
	if(!IsValid())
		return VE_INVALID_PARAMETER;

	VTaskLock locker(&fMutex);
	return (::fsync(fFd) == 0) ? VE_OK : MAKE_NATIVE_VERROR(errno);
}
VError XWinFolder::MoveToTrash() const
{
	// don't use XWinFullPath because SHFileOperation fails on any path prefixed with "\\?\".
	
	// the path parameter is actually a paths list and must be double null terminated.
	// so one must copy the path in a temp buffer.
	UniChar *path = (UniChar*) calloc( fOwner->GetPath().GetPath().GetLength() + 2, sizeof( UniChar));
	if (path == NULL)
		return MAKE_NATIVE_VERROR( ERROR_NOT_ENOUGH_MEMORY);
	
	wcscpy( path, fOwner->GetPath().GetPath().GetCPointer());
	
	SHFILEOPSTRUCTW  info;
	memset( &info, 0, sizeof(info));

	info.fFlags |= FOF_SILENT;				// don't report progress
	info.fFlags |= FOF_NOERRORUI;			// don't report errors
	info.fFlags |= FOF_NOCONFIRMATION;		// don't confirm delete
	info.fFlags |= FOF_ALLOWUNDO;			// move to recycle bin
	info.fFlags |= FOF_NOCONFIRMMKDIR;
	info.fFlags |= FOF_RENAMEONCOLLISION; 
	info.wFunc = FO_DELETE;                   // required: delete operation
	info.pTo = NULL;                          // must be NULL
	info.pFrom = path; 

	VError err;
	int result = SHFileOperationW( &info);
	if (result != 0)
	{
		// unfortunately, GetLastError() is unusable here.
		// and the result code is poorly documented.
		switch( result)
		{
			case 0x7C /*DE_INVALIDFILES*/:	err = MAKE_NATIVE_VERROR( ERROR_PATH_NOT_FOUND); break;
			default:				err = MAKE_NATIVE_VERROR( ERROR_INVALID_PARAMETER); break;
		}
	}
	else
	{
		err = VE_OK;
	}
	
	free( path);
	
	return err;
}
VError XWinFolder::Delete() const
{
	XWinFullPath path( fOwner->GetPath() );

	DWORD winErr = ::RemoveDirectoryW( path) ? 0 : ::GetLastError();

	return MAKE_NATIVE_VERROR( winErr);
}
VError XWinFolder::SetAttributes( DWORD inAttrb) const
{
	XWinFullPath path( fOwner->GetPath() );

	DWORD winErr = ::SetFileAttributesW( path, inAttrb) ? 0 : ::GetLastError();

	return MAKE_NATIVE_VERROR( winErr);
}
示例#13
0
VError MkdirHelper::MakeDir(const PathBuffer& inPath) const
{
    mode_t modeFlags=PERM_755;

    int res=mkdir(inPath.GetPath(), modeFlags);

    return (res==0) ? VE_OK : MAKE_NATIVE_VERROR(errno);
}
VError XWinFolder::Create() const
{
	XWinFullPath path( fOwner->GetPath() );

	// NULL= no security attributes
	DWORD winErr = ::CreateDirectoryW( path, NULL) ? 0 : ::GetLastError();
	
	return MAKE_NATIVE_VERROR( winErr);
}
VError XWinFolder::GetAttributes( DWORD *outAttrb ) const
{
	XWinFullPath path( fOwner->GetPath() );
    *outAttrb = ::GetFileAttributesW(path);

	DWORD winErr = (*outAttrb != INVALID_FILE_ATTRIBUTES ) ? 0 : ::GetLastError();

	return MAKE_NATIVE_VERROR( winErr);
}
示例#16
0
VError PathBuffer::InitWithUniqTmpDir()
{
    int n=snprintf(fPath, sizeof(fPath), "/tmp/Wakanda_XXXXXX");	//A path template with 6 'X' - no more, no less !
    xbox_assert(n>0);

    if(mkdtemp(fPath)==NULL)   //Create the directory and replace the 'X' with the actual path
        return MAKE_NATIVE_VERROR(errno);

    return VE_OK;
}
示例#17
0
VError StatHelper::Stat(FileDescSystemRef fd)
{
    int res=fstat(fd, &fStat);

    if(res!=0)
        return MAKE_NATIVE_VERROR(errno);

    fDoesExist=true;			//We are sure that the file exists

    return VE_OK;
}
VError XLinuxFileDesc::Flush() const
{
	if(!IsValid())
		return VE_INVALID_PARAMETER;

	int res=fsync(fFd);

	if(res<0)
		return MAKE_NATIVE_VERROR(errno);

	return VE_OK;
}
示例#19
0
VError XWinFolder::GetVolumeFreeSpace(sLONG8 *outFreeBytes, bool inWithQuotas ) const
{
	VFilePath filePath( fOwner->GetPath() );
	
	XWinFullPath path( filePath);
		
	uLONG8 freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes;
	DWORD winErr = ::GetDiskFreeSpaceExW( path, (PULARGE_INTEGER) &freeBytesAvailable, (PULARGE_INTEGER) &totalNumberOfBytes, (PULARGE_INTEGER) &totalNumberOfFreeBytes) ? 0 : ::GetLastError();

	if (winErr == 0)
		*outFreeBytes = inWithQuotas ? freeBytesAvailable : totalNumberOfFreeBytes;
	
	return MAKE_NATIVE_VERROR( winErr);
}
示例#20
0
VError StatHelper::Stat(const PathBuffer& inPath)
{
    int res=(fFlags&followLinks) ? stat(inPath.GetPath(), &fStat) : lstat(inPath.GetPath(), &fStat);

    if(res==ENOENT || res==ENOTDIR)
        fDoesNotExist=true;		//We are sure that the file doesn't exists

    if(res!=0)
        return MAKE_NATIVE_VERROR(errno);

    fDoesExist=true;			//We are sure that the file exists

    if(fFlags&withFileSystemStats)
    {
        //I put stats on file systems here because they are obtained through a file of the fs.
        res=statfs(inPath.GetPath(), &fFsStat);

        if(res!=0)
            return MAKE_NATIVE_VERROR(errno);
    }

    return VE_OK;
}
示例#21
0
VError PathBuffer::RealPath(PathBuffer* outBuf) const
{
    if(outBuf==NULL)
        return VE_INVALID_PARAMETER;


    //2nd arg MUST refer to a buffer capable of storing at least PATH_MAX characters
    char* res=realpath(fPath, outBuf->fPath);

    if(res==NULL)
        return MAKE_NATIVE_VERROR(errno);

    return VE_OK;
}
示例#22
0
VError PathBuffer::ReadLink(PathBuffer* outBuf) const
{
    if(outBuf==NULL)
        return VE_INVALID_PARAMETER;

    ssize_t n=readlink(fPath, outBuf->fPath, sizeof(outBuf->fPath));	//Doesn't put a trailing 0

    if(n==-1)
        return MAKE_NATIVE_VERROR(errno);

    if(n==sizeof(outBuf->fPath))
        return VE_INVALID_PARAMETER;	//The target path is longer than PATH_MAX ? It shouldn't be possible !

    return VE_OK;
}
示例#23
0
VError TouchHelper::Touch(const PathBuffer& inPath, VTime inAccessTime, VTime inModificationTime) const
{
    struct utimbuf buf;
    memset(&buf, 0, sizeof(buf));

    buf.actime=XBoxToUnixTime(inAccessTime);
    buf.modtime=XBoxToUnixTime(inModificationTime);

    int res=utime(inPath.GetPath(), &buf);

    if(res<0)
        return MAKE_NATIVE_VERROR(errno);

    return VE_OK;
}
VError XWinFolder::GetVolumeCapacity (sLONG8 *outTotalBytes ) const
{
VFilePath filePath( fOwner->GetPath() );
	filePath.ToParent();
	
	XWinFullPath path( filePath);
		
	uLONG8 freeBytesAvailable = 0, totalNumberOfBytes = 0, totalNumberOfFreeBytes = 0;
	DWORD winErr = ::GetDiskFreeSpaceExW( path, (PULARGE_INTEGER) &freeBytesAvailable, (PULARGE_INTEGER) &totalNumberOfBytes, (PULARGE_INTEGER) &totalNumberOfFreeBytes) ? 0 : ::GetLastError();

	if (winErr == 0)
		*outTotalBytes = totalNumberOfBytes;
	
	return MAKE_NATIVE_VERROR( winErr);

}
示例#25
0
VError XLinuxFileDesc::GetData(void *outData, VSize &ioCount, sLONG8 inOffset, bool inFromStart) const
{
	if(!IsValid())
		return VE_INVALID_PARAMETER;

	VTaskLock locker(&fMutex);
	VError verr = SetPosFromStartWL(fFd, inOffset, inFromStart);

	if (verr!=VE_OK)
	{
		ioCount=0;	//According to win implementation
		return verr;
	}

	ssize_t n=0;
	ssize_t count=0;
	ssize_t bytes=ioCount;

	do
	{
		if((n=read(fFd, (char*)(outData)+count, bytes-count))<0)
		{
			if(errno==EINTR)
				continue;
			else
			{
				verr=MAKE_NATIVE_VERROR(errno);
				break;
			}
		}

		count+=n;
	}
	while(n!=0);

    //Callers expect impl. to fail if it can not fill the data buffer...
    //As a result callers fail if impl. succeed ;) So let's simulate an error !
    if(bytes>count)
        verr=VE_STREAM_EOF;

	ioCount=count;

	return verr;
}
示例#26
0
VError XLinuxFile::Move(const VFilePath& inDestinationPath, VFileSystem *inDestinationFileSystem, VFile** outFile, FileCopyOptions /*inOptions*/) const
{
	VFilePath dstPath(inDestinationPath);

	if (dstPath.IsFolder())
	{
		VStr255 name;					//jmo - todo : NAME_MAX ?
		fOwner->GetName(name);
		dstPath.SetFileName(name);
	}

	PathBuffer pathBuffer;
	pathBuffer.Init(dstPath);

	//First we try to rename the file...
	VError verr;
	{
		RenameHelper rnmHlp;
		verr=rnmHlp.Rename(fPath, pathBuffer);
	}

	//If Rename() fails because src and dst are not on the same fs, we try a Copy()
	if(verr!=VE_OK && IS_NATIVE_VERROR(verr) && NATIVE_ERRCODE_FROM_VERROR(verr)==EXDEV)
	{
		CopyHelper cpHlp;
		verr = cpHlp.Copy(fPath, pathBuffer);

		// it's a move not a copy, so one must delete the source after a sucessful copy
		if (verr == VE_OK)
		{
			int res=unlink(fPath.GetPath());
			verr = (res==0) ? VE_OK :  MAKE_NATIVE_VERROR(errno);
		}
	}

	if (outFile != NULL)
	{
		*outFile = (verr == VE_OK) ? new VFile( dstPath, inDestinationFileSystem) : NULL;
	}

	return verr;
}
VError XWinFolder::SetTimeAttributes( const VTime *inLastModification, const VTime *inCreationTime, const VTime *inLastAccess ) const
{
	WIN32_FILE_ATTRIBUTE_DATA info;
	SYSTEMTIME lastModification;
	SYSTEMTIME creationTime;
	SYSTEMTIME lastAccess;

	XWinFullPath path( fOwner->GetPath());
	DWORD winErr = ::GetFileAttributesExW( path, GetFileExInfoStandard, &info) ? 0 : ::GetLastError();

	if (winErr == 0)
	{
		if ( inLastModification )
		{
			inLastModification->GetUTCTime( (sWORD&)lastModification.wYear, (sWORD&)lastModification.wMonth, (sWORD&)lastModification.wDay, (sWORD&)lastModification.wHour, (sWORD&)lastModification.wMinute, (sWORD&)lastModification.wSecond, (sWORD&)lastModification.wMilliseconds);
			::SystemTimeToFileTime( &lastModification, &info.ftLastWriteTime );
		}
		if ( inCreationTime )
		{
			inCreationTime->GetUTCTime( (sWORD&)creationTime.wYear, (sWORD&)creationTime.wMonth, (sWORD&)creationTime.wDay, (sWORD&)creationTime.wHour, (sWORD&)creationTime.wMinute, (sWORD&)creationTime.wSecond, (sWORD&)creationTime.wMilliseconds);
			::SystemTimeToFileTime( &creationTime, &info.ftCreationTime );
		}
		if ( inLastAccess )
		{
			inLastAccess->GetUTCTime( (sWORD&)lastAccess.wYear, (sWORD&)lastAccess.wMonth, (sWORD&)lastAccess.wDay, (sWORD&)lastAccess.wHour, (sWORD&)lastAccess.wMinute, (sWORD&)lastAccess.wSecond, (sWORD&)lastAccess.wMilliseconds);
			::SystemTimeToFileTime( &lastAccess, &info.ftLastAccessTime );
		}
		HANDLE fileHandle = ::CreateFileW(path, FILE_WRITE_ATTRIBUTES , 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
		if ( fileHandle != INVALID_HANDLE_VALUE )
		{
			winErr = ::SetFileTime( fileHandle, &info.ftCreationTime, &info.ftLastAccessTime, &info.ftLastWriteTime ) ? 0 : ::GetLastError();
			::CloseHandle( fileHandle);
		}
		else
		{
			winErr = ::GetLastError();
		}
	}

	return MAKE_NATIVE_VERROR( winErr);
}
VError XLinuxFileDesc::SetPos(sLONG8 inOffset, Whence inWhence, sLONG8* outLastPos) const
{
	//Warning : If we set the cursor past the end of the file and then write data, we may create
	//          hole in the file... This is ok but it might be confusing  : the size reported by
	//          ls may be greater than the sum of allocated blocks. Bytes in holes are read as 0.

	if(!IsValid())
		return VE_INVALID_PARAMETER;

	int whence;
	
	switch(inWhence)
	{
	case SET :
		whence=SEEK_SET;
		break;
		
	case CUR :
		whence=SEEK_CUR;
		break;

	case END:
		whence=SEEK_END;
		break;

	default :
		xbox_assert(0);
		return VE_INVALID_PARAMETER;
	}

	off_t res=lseek(fFd, inOffset, whence);

	if(res<0)
		return MAKE_NATIVE_VERROR(errno);

    if(outLastPos!=NULL)
        *outLastPos=res;

    return VE_OK;
}
示例#29
0
VError XLinuxFileDesc::PutData(const void *inData, VSize& ioCount, sLONG8 inOffset, bool inFromStart) const
{
	if (!IsValid())
		return VE_INVALID_PARAMETER;

	VTaskLock locker(&fMutex);
	VError verr = SetPosFromStartWL(fFd, inOffset, inFromStart);

	if (verr!=VE_OK)
	{
		ioCount=0;	//According to win implementation
		return verr;
	}

	ssize_t n=0;
	ssize_t count=0;
	ssize_t bytes=ioCount;

	do
	{
		if((n=write(fFd, (char*)(inData)+count, bytes-count))<0)
		{
			if(errno==EINTR)
				continue;
			else
			{
				verr=MAKE_NATIVE_VERROR(errno);
				break;
			}
		}

		count+=n;
	}
	while(bytes-count>0);

	ioCount=count;

	return verr;
}
示例#30
0
VError CreateHelper::Create(const PathBuffer& inPath) const
{
    //I'm pretty sure it doesn't behave in the same way than the windows platform.
    //(the share and overwrite behavior might be different)

    int openFlags=0;

    if(fCreateOpts & FCR_Overwrite)
        openFlags|=O_RDONLY|O_CREAT;					//CREATE_ALWAYS ?
    else
        openFlags|=O_RDONLY|O_CREAT|O_EXCL;				//CREATE_NEW

    mode_t modeFlags=PERM_644;
    int fd=open(const_cast<char*>(inPath.GetPath()), openFlags, modeFlags);

    if(fd<0)
        return MAKE_NATIVE_VERROR(errno);

    close(fd);

    return VE_OK;
}