239 lines
5.0 KiB
C
239 lines
5.0 KiB
C
/* Copyright 2000 by Abacus Research and
|
|
* Development, Inc. All rights reserved.
|
|
*/
|
|
|
|
#if !defined (OMIT_RCSID_STRINGS)
|
|
char ROMlib_rcsid_lockrange[] =
|
|
"$Id: lockrange.c 63 2004-12-24 18:19:43Z ctm $";
|
|
#endif
|
|
|
|
/*
|
|
* The semantics of MacOS's LockRange routine requires that we make a
|
|
* distinction between lock attempts that fail due to ourselves having
|
|
* already locked a byte versus someone else having locked a byte. On
|
|
* Windows (where we're first implementing this functionality), no such
|
|
* distinction is made. As such, we need to keep track of which bytes
|
|
* have been locked by ourselves. Additionally, the Win32 API cautions
|
|
* the programmer to not close a file that has pending locks. Most likely
|
|
* all recent implementations of Win32 don't really care, since it would
|
|
* be kind of insane for them to do something freakish if someone were
|
|
* to close a file with some bytes locked, but since we're keeping track
|
|
* of the locks we've made, it makes sense to unlock, just in case.
|
|
*
|
|
* Locking is considered sufficiently rare that we use a slow data structure
|
|
* to store our locks.
|
|
*/
|
|
|
|
#include "rsys/common.h"
|
|
|
|
#include "MemoryMgr.h"
|
|
|
|
#include "rsys/lockunlock.h"
|
|
|
|
typedef struct
|
|
{
|
|
int fd;
|
|
uint32 start_byte;
|
|
uint32 count;
|
|
}
|
|
lock_entry_t;
|
|
|
|
PRIVATE lock_entry_t *entries;
|
|
PRIVATE int n_entries;
|
|
|
|
PRIVATE void
|
|
delete_entry (lock_entry_t *entry)
|
|
{
|
|
size_t n_bytes;
|
|
|
|
--n_entries;
|
|
n_bytes = (entries + n_entries - entry) * sizeof *entries;
|
|
if (n_bytes)
|
|
memmove (entry, &entry[1], n_bytes);
|
|
}
|
|
|
|
|
|
PUBLIC OSErr
|
|
ROMlib_fd_clear_locks_after_open (int fd, boolean_t be_surprised_p)
|
|
{
|
|
int i;
|
|
int n_removed;
|
|
OSErr retval;
|
|
|
|
retval = noErr;
|
|
n_removed = 0;
|
|
for (i = 0; i < n_entries; ++i)
|
|
{
|
|
if (entries[i].fd == fd)
|
|
{
|
|
if (be_surprised_p)
|
|
warning_unexpected ("fd = %d, start_byte = %d, count = %d",
|
|
fd, entries[i].start_byte, entries[i].count);
|
|
delete_entry (&entries[i]);
|
|
++n_removed;
|
|
--i;
|
|
}
|
|
}
|
|
if (n_removed)
|
|
{
|
|
typeof (entries) new_entries;
|
|
|
|
new_entries = realloc (entries, n_entries * sizeof *entries);
|
|
if (new_entries)
|
|
entries = new_entries;
|
|
else
|
|
retval = memFullErr;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
PUBLIC OSErr
|
|
ROMlib_fd_release_locks_for_close (int fd)
|
|
{
|
|
OSErr err;
|
|
OSErr retval;
|
|
int i;
|
|
|
|
retval = noErr;
|
|
for (i = 0; i < n_entries; ++i)
|
|
{
|
|
if (entries[i].fd == fd)
|
|
{
|
|
err = ROMlib_lockunlockrange (fd, entries[i].start_byte,
|
|
entries[i].count, unlock);
|
|
if (err && retval == noErr)
|
|
retval = err;
|
|
}
|
|
}
|
|
|
|
err = ROMlib_fd_clear_locks_after_open (fd, FALSE);
|
|
if (err && retval == noErr)
|
|
retval = err;
|
|
|
|
return retval;
|
|
}
|
|
|
|
PUBLIC OSErr
|
|
ROMlib_fd_add_range (int fd, uint32 start_byte, uint32 count)
|
|
{
|
|
OSErr retval;
|
|
|
|
if (!count)
|
|
retval = noErr;
|
|
else
|
|
{
|
|
typeof (entries) new_entries;
|
|
|
|
new_entries = realloc (entries, (n_entries + 1) * sizeof *entries);
|
|
if (!new_entries)
|
|
{
|
|
retval = afpNoMoreLocks;
|
|
warning_unexpected ("fd = %d, start_byte = %d, count = %d",
|
|
fd, start_byte, count);
|
|
}
|
|
else
|
|
{
|
|
entries = new_entries;
|
|
entries[n_entries].fd = fd;
|
|
entries[n_entries].start_byte = start_byte;
|
|
entries[n_entries].count = count;
|
|
++n_entries;
|
|
retval = noErr;
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
PUBLIC OSErr
|
|
ROMlib_fd_range_overlap (int fd, uint32 start_byte, uint32 count)
|
|
{
|
|
OSErr retval;
|
|
|
|
retval = noErr;
|
|
if (count)
|
|
{
|
|
uint32 stop_byte;
|
|
int i;
|
|
|
|
stop_byte = start_byte + count;
|
|
if (stop_byte < start_byte)
|
|
stop_byte = ~0;
|
|
for (i = 0; i < n_entries; ++i)
|
|
{
|
|
if (entries[i].fd == fd)
|
|
{
|
|
uint32 entries_stop_byte;
|
|
|
|
entries_stop_byte = entries[i].start_byte + entries[i].count;
|
|
if (entries_stop_byte < entries[i].start_byte)
|
|
entries_stop_byte = ~0;
|
|
|
|
if (entries[i].start_byte < start_byte)
|
|
{
|
|
if (entries_stop_byte > start_byte)
|
|
retval = afpRangeOverlap;
|
|
}
|
|
else if (entries[i].start_byte > start_byte)
|
|
{
|
|
if (stop_byte > entries[i].start_byte)
|
|
retval = afpRangeOverlap;
|
|
}
|
|
else
|
|
retval = afpRangeOverlap;
|
|
}
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
PRIVATE lock_entry_t *
|
|
find_fd_start_count_helper (int fd, uint32 start_byte, uint32 count)
|
|
{
|
|
int i;
|
|
lock_entry_t *retval;
|
|
|
|
retval = NULL;
|
|
for (i = 0; !retval && i < n_entries; ++i)
|
|
{
|
|
if (entries[i].fd == fd && entries[i].start_byte == start_byte)
|
|
{
|
|
if (entries[i].count == count) /* perhaps we should check to
|
|
see if both of them run past
|
|
maxuint */
|
|
retval = &entries[i];
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
PUBLIC OSErr
|
|
ROMlib_find_fd_start_count (int fd, uint32 start_byte, uint32 count)
|
|
{
|
|
OSErr retval;
|
|
|
|
retval = find_fd_start_count_helper (fd, start_byte, count)
|
|
? noErr : afpRangeNotLocked;
|
|
|
|
return retval;
|
|
}
|
|
|
|
PUBLIC OSErr
|
|
ROMlib_fd_remove_range (int fd, uint32 start_byte, uint32 count)
|
|
{
|
|
OSErr retval;
|
|
lock_entry_t *entry;
|
|
|
|
entry = find_fd_start_count_helper (fd, start_byte, count);
|
|
if (!entry)
|
|
retval = afpRangeNotLocked;
|
|
else
|
|
{
|
|
delete_entry (entry);
|
|
retval = noErr;
|
|
}
|
|
|
|
return retval;
|
|
}
|