
// This file is part of the AspectC++ compiler 'ac++'.
// Copyright (C) 1999-2003  The 'ac++' developers (see aspectc.org)
//
// This program is free software;  you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
// MA  02111-1307  USA

#include "ACModelFile.h"

#include <algorithm>
#include <assert.h>
#include <fcntl.h>
#include <string.h>

#ifdef _MSC_VER
# include <direct.h>
# include <string>
#else
# include <unistd.h>
# include <dirent.h>
#endif // _MSC_VER

#ifdef WIN32
# include <io.h>
# include <windows.h>
#endif // WIN32

ACModelFile::ACModelFile(const std::string &filename) : filename_(filename), fd_(-1) {
#if defined(WIN32)
  std::replace(filename_.begin(), filename_.end(), '/', '\\');
#endif
}

bool ACModelFile::lock() {
  assert(fd_ != -1);
#if defined(__GLIBC__)
  flock lock;
  memset(&lock, 0, sizeof lock);
  lock.l_type = F_WRLCK;
  lock.l_whence = SEEK_SET;
  if (fcntl(fd_, F_SETLKW, &lock) == -1)
    return false;
#endif 
  return true;
}

// Create and lock the repository file if it does not exist.
// If it exists, open it for writing, get an exclusive lock and
// truncate it.
bool ACModelFile::create(int mode) {
  assert(fd_ == -1);
  int flags = O_CREAT | O_WRONLY | O_TRUNC;
#if defined(WIN32)
  flags |= O_BINARY;
#endif
  fd_ = ::open(filename_.c_str(), flags, mode);
  return fd_ != -1 && lock();
}

// Open and lock the file for exclusive read-only access
bool ACModelFile::open() {
  assert(fd_ == -1);
  int flags = O_RDWR;
#if defined(WIN32)
  flags |= O_BINARY;
#endif
  fd_ = ::open(filename_.c_str(), flags);
  return fd_ != -1 && lock();
}

// Unlock and close the file
bool ACModelFile::close() {
  assert(fd_ != -1);
  bool result = true;
#if defined(__GLIBC__)
  flock lock;
  memset(&lock, 0, sizeof lock);
  lock.l_type = F_UNLCK;
  lock.l_whence = SEEK_SET;
  if (fcntl(fd_, F_SETLKW, &lock) == -1) {
    result = false;
  }
#endif
  if (::close(fd_) == -1)
    result = false;
  fd_ = -1;
  return result;
}
