/*

BeLock.c - implementation of Fido-style message bases lock BeOS library.

 bases lock BeOS library.

This code is written by Siarzhuk Zharski <imker@gmx.li> for free and
can be used for any purposes in any form without any warranties.

*/
#include <stdio.h>
#include <errno.h>

#include "be_lock.h"

static const char rcsid[]="$Id$";

static status_t look_for_port(int file_handle, bool b_create, port_id *port_id_ptr)
{
  status_t status = B_OK;
  struct stat st = {0};
  char name[B_OS_NAME_LENGTH] = {0};
  
  if(fstat(file_handle, &st))
    return B_IO_ERROR;

  sprintf(name, "FidoLock:%08X:%08X", st.st_dev, st.st_ino);
  
  *port_id_ptr = find_port(name);
  if(*port_id_ptr == B_NAME_NOT_FOUND)
  {
    if(b_create)
    {
      *port_id_ptr = create_port(1, name);
      if(*port_id_ptr == B_BAD_VALUE || *port_id_ptr == B_NO_MORE_PORTS)
        status = *port_id_ptr;
    }
    else
      status = B_NAME_NOT_FOUND;
  }
  else // already have such lock ...
    status = B_BUSY;
  return status; 
}
 
status_t beos_lock(int file_handle)
{
  port_id pid = 0;
  return look_for_port(file_handle, true, &pid);
}

status_t beos_unlock(int file_handle)
{
  port_id pid = 0;
  status_t status = look_for_port(file_handle, false, &pid);
  if(status == B_BUSY)
    status = delete_port(pid);
  return status;
}

#define IMPLEMENT_BEOS_FUNC(_FUNC_NAME, _FUNC)\
status_t _FUNC_NAME(FILE *handle)             \
{                                             \
  int file_handle = fileno(handle);           \
  if(file_handle == -1)                       \
    return B_IO_ERROR;                        \
  return _FUNC(file_handle);                  \
}                                             \

IMPLEMENT_BEOS_FUNC(beos_flock, beos_lock)
IMPLEMENT_BEOS_FUNC(beos_funlock, beos_unlock)

#define IMPLEMENT_BE_FUNC(_FUNC_NAME, _HANDLE_TYPE, _FUNC)\
int _FUNC_NAME(_HANDLE_TYPE handle)\
{                                           \
  int ret_value = 0;                        \
  status_t status = _FUNC(handle);          \
  if(status != B_OK)                        \
  {                                         \
    errno = status;                         \
    ret_value = -1;                         \
  }                                         \
  return ret_value;                         \
}                                           \
 
IMPLEMENT_BE_FUNC(be_lock, int, beos_lock)
IMPLEMENT_BE_FUNC(be_unlock, int, beos_unlock)
IMPLEMENT_BE_FUNC(be_flock, FILE *, beos_flock)
IMPLEMENT_BE_FUNC(be_funlock, FILE *, beos_funlock)