#define _CRT_SECURE_NO_DEPRECATE #include <windows.h> #pragma warning(push) #pragma warning(disable : 4267 4244) #include <clientapi.h> #pragma warning( pop ) #include "filewriter.h" #include "fs_filesys.h" FsFileSys::FsFileSys(FileSysType inType, long long inFileSize) : mFileWriter(NULL), mFileSize(inFileSize) { type = inType; if ((type & FST_MASK) == FST_GUNZIP) { mZStream.zalloc = Z_NULL; mZStream.zfree = Z_NULL; mZStream.opaque = Z_NULL; mZStream.avail_in = 0; mZStream.next_in = Z_NULL; mZStreamState = inflateInit2(&mZStream, 47); } } FsFileSys::~FsFileSys() { } void FsFileSys::Open(FileOpenMode inMode, Error* ioError) { #ifdef _DEBUG printf("Open(%d), type = %d, path = %s\n", inMode, type, Name()); #endif if (inMode == FOM_READ) { ioError->Set(E_FATAL, "Attempt to open a FileSys object in unsupported read mode, aborting."); return; } else if (inMode == FOM_WRITE) { mFileWriter = FileWriter::GetFileWriter(Name(), mFileSize); if (mFileWriter && !mFileWriter->IsAborting() && !mFileWriter->Open()) ioError->Sys(inMode == FOM_READ ? "open for read" : "open for write", Name()); } } void FsFileSys::Write(const char* inBuffer, int inLen, Error* ioError) { #ifdef _DEBUG printf("Write(%4d), type = %d, path = %s\n", inLen, type, Name()); #endif if (!mFileWriter || mFileWriter->IsAborting() || inLen <= 0) return; if ((type & FST_MASK) == FST_GUNZIP) { if (mZStreamState != Z_OK) return; // z_stream is broken, no point in continuing mZStream.avail_in = inLen; mZStream.next_in = (Bytef*) inBuffer; } while (inLen > 0) { int have = 0; unsigned char* out_buf; int out_len_remaining; mFileWriter->GetWriteBuffer(out_buf, out_len_remaining); if ((type & FST_MASK) == FST_GUNZIP) { mZStream.avail_out = out_len_remaining; mZStream.next_out = out_buf; mZStreamState = inflate(&mZStream, Z_SYNC_FLUSH); if ((mZStreamState != Z_OK) && (mZStreamState != Z_STREAM_END)) { ioError->Set(E_WARN, mZStream.msg); return; } have = out_len_remaining - mZStream.avail_out; inLen = mZStream.avail_in; } else if ((type & FST_MASK) == FST_TEXT) { while (inLen > 0 && (out_len_remaining - have) > 1) { char c = *inBuffer++; if (c == '\n') { *out_buf++ = '\r'; *out_buf++ = '\n'; have += 2; } else { *out_buf++ = c; ++have; } --inLen; } } else { // Not sure what to do, just do a straight copy for now have = (inLen < out_len_remaining) ? inLen : out_len_remaining; ::memcpy(out_buf, inBuffer, have); inBuffer += have; inLen -= have; } if (!mFileWriter->ReleaseWriteBuffer(out_len_remaining - have)) ioError->Sys("write", Name()); if (mFileWriter->GetReadCallback()) mFileWriter->GetReadCallback()(have); } } int FsFileSys::Read(char* outBuf, int inLen, Error* ioError) { #ifdef _DEBUG printf("Read(%4d) type = %d, path = %s\n", inLen, type, Name()); #endif ioError->Set(E_FATAL, "Attempt to use the unimplemented FileSys::Read() function, aborting."); return 0; } void FsFileSys::Close(Error* ioError) { #ifdef _DEBUG printf("Close(), type = %d, path = %s\n", type, Name()); #endif if (!mFileWriter || mFileWriter->IsAborting()) return; if ((type & FST_MASK) == FST_GUNZIP) { if (inflateEnd(&mZStream) != Z_OK) ioError->Set(E_WARN, mZStream.msg); } if (!mFileWriter->Close()) ioError->Sys("close", Name()); } int FsFileSys::Stat() { #ifdef _DEBUG printf("Stat(), type = %d, path = %s\n", type, Name()); #endif int stat = 0; WIN32_FILE_ATTRIBUTE_DATA file_info; if (::GetFileAttributesEx(Name(), GetFileExInfoStandard, (void*) &file_info)) { stat |= FSF_EXISTS; if ((file_info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) stat |= FSF_WRITEABLE; if (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) stat |= FSF_DIRECTORY; if (file_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) stat |= FSF_SYMLINK; if (file_info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) stat |= FSF_HIDDEN; if ((file_info.nFileSizeHigh == 0) && (file_info.nFileSizeLow == 0)) stat |= FSF_EMPTY; } return stat; } int FsFileSys::StatModTime() { #ifdef _DEBUG printf("StatModTime(), type = %d, path = %s\n", type, Name()); #endif WIN32_FILE_ATTRIBUTE_DATA file_info; if (::GetFileAttributesEx(Name(), GetFileExInfoStandard, (void*) &file_info)) { LONGLONG ft = file_info.ftLastWriteTime.dwHighDateTime; ft <<= 32; ft += file_info.ftLastWriteTime.dwLowDateTime; ft /= 10000000; ft -= 11644473600; return (int) ft; } return 0; } void FsFileSys::Truncate(Error* ioError) { #ifdef _DEBUG printf("Truncate(), type = %d, path = %s\n", type, Name()); #endif ioError->Set(E_FATAL, "Attempt to use the unimplemented FileSys::Truncate() function, aborting."); } void FsFileSys::Unlink(Error* ioError) { #ifdef _DEBUG printf("Unlink(), type = %d, path = %s\n", type, Name()); #endif if (mFileWriter) { if (mFileWriter->IsAborting()) return; mFileWriter->Finish(); } bool is_readonly = !(Stat() & FSF_WRITEABLE); if (is_readonly) Chmod(FPM_RW, ioError); if (::DeleteFile(Name()) == 0) { if (is_readonly) Chmod(FPM_RO, ioError); ioError->Sys("unlink", Name()); } } void FsFileSys::Rename(FileSys* inTarget, Error* ioError) { #ifdef _DEBUG printf("Rename(%s), type = %d, path = %s\n", inTarget->Name(), type, Name()); #endif if (mFileWriter) { if (mFileWriter->IsAborting()) return; mFileWriter->Finish(); } int res = -1; int attempt = 0; bool target_is_readonly = false; while (attempt < 10 && res != 0) { int target_stat = inTarget->Stat(); if (target_stat & FSF_EXISTS) { target_is_readonly = !(target_stat & FSF_WRITEABLE); if (target_is_readonly) inTarget->Chmod(FPM_RW, ioError); ::DeleteFile(inTarget->Name()); } res = ::rename(Name(), inTarget->Name()); if (res != 0) Sleep(1000); ++attempt; } if (res != 0) { if (target_is_readonly) inTarget->Chmod(FPM_RO, ioError); Unlink(ioError); printf("File rename() failed after 10 attempts.\n"); ioError->Sys("rename", inTarget->Name()); } else path = *(inTarget->Path()); } void FsFileSys::Chmod(FilePerm inPerms, Error* ioError) { #ifdef _DEBUG printf("Chmod(%d), type = %d, path = %s\n", inPerms, type, Name()); #endif if (mFileWriter) { if (mFileWriter->IsAborting()) return; mFileWriter->Finish(); } DWORD attr = ::GetFileAttributes(Name()); if (inPerms == FPM_RO) attr |= FILE_ATTRIBUTE_READONLY; else if (inPerms == FPM_RW) attr &= ~FILE_ATTRIBUTE_READONLY; if (::SetFileAttributes(Name(), attr) == 0) ioError->Sys("chmod", Name()); else perms = inPerms; } void FsFileSys::ChmodTime(Error* ioError) { #ifdef _DEBUG printf("ChmodTime(), type = %d, path = %s\n", type, Name()); #endif ioError->Set(E_FATAL, "Attempt to use the unimplemented FileSys::ChmodTime() function, aborting."); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#4 | 6451 | Frank Compagner |
- Now fully support unicode & utf-16 files - Improved accuracy of P4fsV progress bar - Added logging to help in remote debugging |
||
#3 | 6420 | Frank Compagner |
A number of improvements: - p4fs now supports the global -s (scripted output) option. - p4fs and P4fsV now support the modtime client option. - P4CHARSET is now correctly handled (though no full Unicode support yet). - Increased the maximum command line length for p4fs to the Windows maximum 32768. - Improved error handling. - Fixed a crash when cancelling a sync using the async or multithreaded writers. - P4fsV progressbar now behaves well when passing more than one filespec - P4fsV will now offer the option to overwrite any locally changed (but not checked out) files when it finds these during a sync (cannot clobber ...). - Made the P4fsV error dialog resizeable. - P4fsV Windows layout fixed so it works properly with all Windows style setings. - Ooh, and prettier icons too. |
||
#2 | 6280 | Frank Compagner | Added support for +w filetype | ||
#1 | 6187 | Frank Compagner | Added p4fs project |