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

📄 tarstream.cc

📁 本人收集整理的一份c/c++跨平台网络库
💻 CC
📖 第 1 页 / 共 2 页
字号:
  ASSERT(NULL != error);  ASSERT(M_WRITE == mode_);  ASSERT(NB_FILE_HEADER == next_block_);  ASSERT(BLOCK_SIZE == block_pos_);  ASSERT(NULL == current_);  ASSERT(0 == current_bytes_);  std::string pathname, link, linked_name, magic, mversion;  size_t file_size, modify_time, unused, checksum;  size_t block_data = 0;  ReadFieldS(block_data, 100, &pathname);  ReadFieldN(block_data, 8,   &unused);  // mode  ReadFieldN(block_data, 8,   &unused);  // owner uid  ReadFieldN(block_data, 8,   &unused);  // owner gid  ReadFieldN(block_data, 12,  &file_size);  ReadFieldN(block_data, 12,  &modify_time);  ReadFieldN(block_data, 8,   &checksum);  if (checksum == 0)     block_data -= 8; // back-compatiblity   ReadFieldS(block_data, 1,   &link);  ReadFieldS(block_data, 100, &linked_name);  // name of linked file  ReadFieldS(block_data, 6,   &magic);  ReadFieldS(block_data, 2,   &mversion);  if (pathname.empty())    return SR_EOS;  std::string user, group, dev_major, dev_minor, prefix;  if (magic == "ustar" || magic == "ustar ") {    ReadFieldS(block_data, 32, &user);    ReadFieldS(block_data, 32, &group);    ReadFieldS(block_data, 8, &dev_major);    ReadFieldS(block_data, 8, &dev_minor);    ReadFieldS(block_data, 155, &prefix);    pathname = prefix + pathname;  }  // Rest of the block must be empty  StreamResult result = ProcessEmptyBlock(block_data, error);  if (SR_SUCCESS != result) {    return result;  }  Pathname archive_path(pathname);  archive_path.SetFolderDelimiter('/');  archive_path.Normalize();  bool is_folder = archive_path.filename().empty();  if (is_folder) {    ASSERT(NB_FILE_HEADER == next_block_);    ASSERT(0 == file_size);  } else if (file_size > 0) {    // We assign current_bytes_ because we must skip over the upcoming data    // segments, regardless of whether we want to write them.    next_block_ = NB_DATA;    current_bytes_ = file_size;  }  if (!CheckFilter(archive_path.pathname())) {    // If it's a directory, we will ignore it and all children by nature of    // filter prefix matching.  If it is a file, we will ignore it because    // current_ is NULL.    return SR_SUCCESS;  }  // Sanity checks:  // 1) No .. path segments  if (archive_path.pathname().find("../") != std::string::npos) {    LOG_F(LS_WARNING) << "Skipping path with .. entry: "                      << archive_path.pathname();    return SR_SUCCESS;  }  // 2) No drive letters  if (archive_path.pathname().find(':') != std::string::npos) {    LOG_F(LS_WARNING) << "Skipping path with drive letter: "                      << archive_path.pathname();    return SR_SUCCESS;  }  // 3) No absolute paths  if (archive_path.pathname().find("//") != std::string::npos) {    LOG_F(LS_WARNING) << "Skipping absolute path: "                      << archive_path.pathname();    return SR_SUCCESS;  }  Pathname local_path(root_folder_);  local_path.AppendPathname(archive_path.pathname());  local_path.Normalize();  if (is_folder) {    if (!Filesystem::CreateFolder(local_path)) {      LOG_F(LS_WARNING) << "Couldn't create folder: " << local_path.pathname();      *error = 0; // TODO      return SR_ERROR;    }  } else {    FileStream* stream = new FileStream;    if (!stream->Open(local_path.pathname().c_str(), "wb")) {      LOG_F(LS_WARNING) << "Couldn't create file: " << local_path.pathname();      *error = 0; // TODO      delete stream;      return SR_ERROR;    }    if (file_size > 0) {      current_ = stream;    } else {      stream->Close();      delete stream;    }  }  SignalNextEntry(archive_path.filename(), current_bytes_);     return SR_SUCCESS;}StreamResult TarStream::ProcessNextEntry(const DirectoryIterator *data, int *error) {  ASSERT(M_READ == mode_);  ASSERT(NB_FILE_HEADER == next_block_);  ASSERT(BLOCK_SIZE == block_pos_);  ASSERT(NULL == current_);  ASSERT(0 == current_bytes_);  if (data->IsDirectory() &&      (data->Name() == "." || data->Name() == ".."))    return SR_SUCCESS;  Pathname archive_path;  archive_path.SetFolder(subfolder_);  if (data->IsDirectory()) {    archive_path.AppendFolder(data->Name());  } else {    archive_path.SetFilename(data->Name());  }  archive_path.SetFolderDelimiter('/');  archive_path.Normalize();  if (!CheckFilter(archive_path.pathname()))    return SR_SUCCESS;  if (archive_path.pathname().length() > 255) {    // Cannot send a file name longer than 255 (yet)    return SR_ERROR;  }  Pathname local_path(root_folder_);  local_path.AppendPathname(archive_path.pathname());  local_path.Normalize();  if (data->IsDirectory()) {    // Note: the NULL handle indicates that we need to open the folder next     // time.    find_.push_front(NULL);    subfolder_ = archive_path.pathname();  } else {    FileStream* stream = new FileStream;    if (!stream->Open(local_path.pathname().c_str(), "rb")) {      // TODO: Should this be an error?      LOG_F(LS_WARNING) << "Couldn't open file: " << local_path.pathname();      delete stream;      return SR_SUCCESS;    }    current_ = stream;    current_bytes_ = data->FileSize();  }  time_t modify_time = data->FileModifyTime();  std::string pathname = archive_path.pathname();  std::string magic, user, group, dev_major, dev_minor, prefix;    std::string name = pathname;  bool ustar = false;  if (name.length() > 100) {    ustar = true;    // Put last 100 characters into the name, and rest in prefix    size_t path_length = pathname.length();    prefix = pathname.substr(0, path_length - 100);    name = pathname.substr(path_length - 100);  }  size_t block_data = 0;  memset(block_, 0, BLOCK_SIZE);  WriteFieldS(block_data, 100, name.c_str());  WriteFieldS(block_data, 8,   data->IsDirectory() ? "777" : "666");   // mode  WriteFieldS(block_data, 8,   "5");   // owner uid  WriteFieldS(block_data, 8,   "5");   // owner gid  WriteFieldN(block_data, 12,  current_bytes_);  WriteFieldN(block_data, 12,  modify_time);  WriteFieldS(block_data, 8, "        "); // Checksum. To be filled in later.  WriteFieldS(block_data, 1,   data->IsDirectory() ? "5" : "0");  // link indicator (0 == normal file, 5 == directory)  WriteFieldS(block_data, 100, "");   // name of linked file  if (ustar) {    WriteFieldS(block_data, 6,   "ustar");    WriteFieldS(block_data, 2,   "");    WriteFieldS(block_data, 32,  user.c_str());    WriteFieldS(block_data, 32,  group.c_str());    WriteFieldS(block_data, 8,   dev_major.c_str());    WriteFieldS(block_data, 8,   dev_minor.c_str());    WriteFieldS(block_data, 155, prefix.c_str());  }  // Rest of the block must be empty  StreamResult result = ProcessEmptyBlock(block_data, error);  WriteChecksum();  block_pos_ = 0;  if (current_bytes_ > 0) {    next_block_ = data->IsDirectory() ? NB_FILE_HEADER : NB_DATA;  }  SignalNextEntry(archive_path.filename(), current_bytes_);  return result;}void TarStream::WriteChecksum() {  unsigned int sum = 0;  for (int i = 0; i < BLOCK_SIZE; i++)     sum += static_cast<unsigned char>(block_[i]);  sprintf(block_ + 148, "%06o", sum); }bool TarStream::CheckFilter(const std::string& pathname) {  if (filters_.empty())    return true;  // pathname is allowed when there is a filter which:  // A) Equals name  // B) Matches a folder prefix of name  for (size_t i=0; i<filters_.size(); ++i) {    const std::string& filter = filters_[i];    // Make sure the filter is a prefix of name    if (_strnicmp(pathname.c_str(), filter.data(), filter.length()) != 0)      continue;    // If the filter is not a directory, must match exactly    if (!Pathname::IsFolderDelimiter(filter[filter.length()-1])        && (filter.length() != pathname.length()))      continue;    return true;  }  return false;}void TarStream::WriteFieldN(size_t& pos, size_t max_len, size_t numeric_field) {  WriteFieldF(pos, max_len, "%.*o", max_len - 1, numeric_field);}void TarStream::WriteFieldS(size_t& pos, size_t max_len,                          const char* string_field) {  ASSERT(pos + max_len <= BLOCK_SIZE);  size_t len = strlen(string_field);  size_t use_len = _min(len, max_len);  memcpy(block_ + pos, string_field, use_len);  pos += max_len;}void TarStream::WriteFieldF(size_t& pos, size_t max_len,                          const char* format, ...) {  va_list args;  va_start(args, format);  char buffer[BLOCK_SIZE];  vsprintfn(buffer, ARRAY_SIZE(buffer), format, args);  WriteFieldS(pos, max_len, buffer);  va_end(args);}void TarStream::ReadFieldN(size_t& pos, size_t max_len, size_t* numeric_field) {  ASSERT(NULL != numeric_field);  std::string buffer;  ReadFieldS(pos, max_len, &buffer);  int value;  if (!buffer.empty() && (1 == sscanf(buffer.c_str(), "%o", &value))) {    *numeric_field = value;  } else {    *numeric_field = 0;  }}void TarStream::ReadFieldS(size_t& pos, size_t max_len,                           std::string* string_field) {  ASSERT(NULL != string_field);  ASSERT(pos + max_len <= BLOCK_SIZE);  size_t value_len = utils_base::strlenn(block_ + pos, max_len);  string_field->assign(block_ + pos, value_len);  ASSERT(talk_base::memory_check(block_ + pos + value_len,                                 0,                                 max_len - value_len));  pos += max_len;}

⌨️ 快捷键说明

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