Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv3426/libntfs
Modified Files:
attrib.c bitmap.c disk_io.c mft.c volume.c
Log Message:
Commit of current state of development including locking a la kernel.
This doesn't work on user space (semaphores don't work).
Just want to have it committed. Will take out locking / modify it where
necessary to use pthreads ASAP.
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -U2 -r1.8 -r1.9
--- attrib.c 2001/04/02 02:04:37 1.8
+++ attrib.c 2001/04/05 20:14:45 1.9
@@ -27,9 +27,9 @@
#include <stdlib.h>
+#include "volume.h"
#include "attrib.h"
#include "mft.h"
#include "endians.h"
#include "disk_io.h"
-#include "volume.h"
#include "unistr.h"
#include "support.h"
@@ -530,5 +530,6 @@
run_list decompress_run_list(const ATTR_RECORD *attr)
{
- __s64 vcn, lcn; /* Current vcn and lcn, respectively. */
+ VCN vcn; /* Current vcn. */
+ LCN lcn; /* Current lcn. */
__s64 deltaxcn; /* Change in [vl]cn. */
run_list rl = NULL; /* The output run_list. */
@@ -669,17 +670,23 @@
}
-__s64 vcn_to_lcn(const run_list rl, const __s64 vcn)
+LCN vcn_to_lcn(const run_list rl, const VCN vcn)
{
int i = 0;
- if (!rl || vcn < 0)
- return -EINVAL;
- if (!rl[0].length || vcn < rl[0].vcn)
- return -ENOENT;
+ if (!rl || vcn < 0) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (!rl[0].length || vcn < rl[0].vcn) {
+ errno = ENOENT;
+ return 0;
+ }
+ errno = 0;
do {
if (vcn < rl[++i].vcn)
return rl[i-1].lcn + (vcn - rl[i-1].vcn);
} while (rl[i].length);
- return -ENOENT;
+ errno = ENOENT;
+ return 0;
}
Index: bitmap.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/bitmap.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -U2 -r1.2 -r1.3
--- bitmap.c 2001/04/03 22:42:42 1.2
+++ bitmap.c 2001/04/05 20:14:45 1.3
@@ -32,5 +32,6 @@
*/
-inline void ntfs_set_bit(__u8 *bitmap, const __u64 bit, const __u8 new_value)
+__inline__ void ntfs_set_bit(__u8 *bitmap, const __u64 bit,
+ const __u8 new_value)
{
if (!bitmap || new_value > 1)
@@ -42,5 +43,5 @@
}
-inline char ntfs_get_bit(const __u8 *bitmap, const __u64 bit)
+__inline__ char ntfs_get_bit(const __u8 *bitmap, const __u64 bit)
{
if (!bitmap)
@@ -49,5 +50,5 @@
}
-inline char ntfs_get_and_set_bit(__u8 *bitmap, const __u64 bit,
+__inline__ char ntfs_get_and_set_bit(__u8 *bitmap, const __u64 bit,
const __u8 new_value)
{
Index: disk_io.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/disk_io.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -U2 -r1.8 -r1.9
--- disk_io.c 2001/04/03 22:42:42 1.8
+++ disk_io.c 2001/04/05 20:14:45 1.9
@@ -280,6 +280,7 @@
const MFT_REFERENCE *mref, const int count)
{
- __u64 br, m;
- __s64 lcn, ofs;
+ __u64 br, ofs;
+ LCN lcn;
+ VCN m;
if (!vol || !mrec)
Index: mft.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/mft.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -U2 -r1.3 -r1.4
--- mft.c 2001/04/03 23:38:34 1.3
+++ mft.c 2001/04/05 20:14:45 1.4
@@ -33,5 +33,4 @@
if (!b || !is_mft_recordp(b))
return 0;
-
/* Get the number of used bytes and return it. */
return le32_to_cpu(b->bytes_in_use);
@@ -41,11 +40,222 @@
{
ntfs_volume *v = mentry->m_vol;
-
+ down_write(&mentry->m_sem);
down_write(&v->mft_entries_sem);
- list_add(&mentry->m_dirty_list, &v->dirty_mft_entries);
+ list_add_tail(&mentry->m_dirty_list, &v->dirty_mft_entries);
v->nr_dirty_mft_entries++;
up_write(&v->mft_entries_sem);
+ up_write(&mentry->m_sem);
+}
+
+__inline__ mft_entry *__allocate_mft_entry(void)
+{
+ mft_entry *me = (mft_entry *)malloc(sizeof(mft_entry));
+ if (!me)
+ return NULL;
+ memset(me, 0, sizeof(mft_entry));
+ init_rwsem(&me->m_rec_sem);
+ init_rwsem(&me->m_sem);
+ INIT_LIST_HEAD(me->m_list);
+ INIT_LIST_HEAD(me->m_dirty_list);
+ return me;
+}
+
+__inline__ int __free_mft_entry(mft_entry *me)
+{
+ down_read(&me->m_sem);
+ if (atomic_read(me->count) || MftEntryDirty(me) || MftEntryMapped(me)) {
+ up_read(&me->m_sem);
+ return -EBUSY;
+ }
+ up_read(&me->m_sem);
+ down_write(&me->m_sem);
+ /* Just making sure nobody else is holding the semaphore... */
+ down_up(&me->m_sem);
+ free(me);
+ return 0;
+}
+
+int __map_mft_entry(mft_entry *me)
+{
+ VCN mref;
+ LCN lcn;
+ __u64 ofs;
+ MFT_RECORD *mrec;
+ int i;
+
+ if (MftEntryMapped(me))
+ return 0;
+ mref = (VCN)(*(__u64*)me->m_ref & MFT_REFERENCE_MASK_CPU);
+ mrec = (MFT_RECORD*)malloc(vol->mft_record_size);
+ if (!mrec)
+ goto err_ret_errno;
+ /* Size of mft record != size of cluster thus need to work with
+ * offsets into clusters. */
+ if (vol->mft_records_per_cluster) {
+ lcn = vcn_to_lcn(vol->mft_runlist,
+ mref / vol->mft_records_per_cluster);
+ /* FIXME: Change "/" above and "%" below to ">>" and "&"
+ respectively! */
+ ofs = mref % vol->mft_records_per_cluster;
+ ofs <<= vol->mft_record_size_bits;
+ } else {
+ lcn = vcn_to_lcn(vol->mft_runlist,
+ mref * vol->clusters_per_mft_record);
+ /* FIXME: Change "*" above to "<<"! */
+ ofs = 0;
+ }
+ if (lcn < 0)
+ goto err_ret_errno;
+ down_write(&me->m_mrec_sem);
+ i = mst_pread(vol->fd, (__u8*)mrec, vol->mft_record_size, 1,
+ (lcn << vol->cluster_size_bits) + ofs);
+ up_write(&me->m_mrec_sem);
+ if (i != 1) {
+ if (i == -1)
+ goto err_ret_errno;
+ return -EIO;
+ }
+ down_write(&me->m_sem);
+ me->m_rec = mrec;
+ SetMftEntryMapped(me);
+ up_write(&me->m_sem);
+ return 0;
+err_ret_errno:
+ return -errno;
+}
+
+int __unmap_mft_entry(mft_entry *me)
+{
+ int err;
+
+ if (atomic_read(&me->m_count))
+ return -EBUSY;
+ down_write(&me->m_sem);
+ if (!test_and_clear_bit(ME_mapped, &me->m_flags)) {
+ up_write(&me->m_sem);
+ return 0;
+ }
+ if (MftEntryDirty(me)) {
+ if (err = flush_mft_entry(me))
+ goto err_up_ret;
+ if (MftEntryDirty(me)) {
+ err = -EBUSY;
+ goto err_up_ret;
+ }
+ }
+ down_write(&me->m_rec_sem);
+ free(me->m_rec);
+ up_write(&me->m_rec_sem);
+ up_write(&me->m_sem);
+ return 0;
+err_up_ret:
+ up_write(&me->m_sem);
+ return err;
+}
+
+int flush_mft_entry(const mft_entry *me)
+{
+ VCN mref;
+ LCN lcn;
+ __u64 ofs;
+ MFT_RECORD *mrec;
+ __u32 i;
+
+ if (!MftEntryMapped(me))
+ return 0;
+ mref = (VCN)(*(__u64*)me->m_ref & MFT_REFERENCE_MASK_CPU);
+ /* Size of mft record != size of cluster thus need to work with offsets
+ * into clusters. */
+ if (vol->mft_records_per_cluster) {
+ lcn = vcn_to_lcn(vol->mft_runlist,
+ mref / vol->mft_records_per_cluster);
+ /* FIXME: Change "/" above and "%" below to ">>" and "&"
+ respectively! */
+ ofs = mref % vol->mft_records_per_cluster;
+ ofs <<= vol->mft_record_size_bits;
+ } else {
+ lcn = vcn_to_lcn(vol->mft_runlist,
+ m * vol->clusters_per_mft_record);
+ /* FIXME: Change "*" above to "<<"! */
+ ofs = 0;
+ }
+ if (lcn < 0)
+ return -errno;
+ down_write(&me->m_rec_sem);
+ i = mst_pwrite(vol->fd, me->m_rec, vol->mft_record_size,
+ (lcn << vol->cluster_size_bits) + ofs);
+ up_write(&me->m_rec_sem);
+ if (i != vol->mft_record_size) {
+ if (i == -1)
+ goto err_ret_errno;
+ return -EIO;
+ }
+ ClearMftEntryDirty(me);
+ return 0;
+err_ret_errno:
+ return -errno;
+}
+
+int insert_mft_entry(ntfs_volume *vol, mft_entry *me, MFT_REFERENCE mref,
+ MFT_RECORD *mrec, int dirty)
+{
+ struct list_head *tmp;
+ mft_entry *m;
+
+ *(__u64*)&me->m_ref = mref;
+ me->m_vol = vol;
+ if (mrec) {
+ me->m_rec = mrec;
+ SetMftEntryMapped(me);
+ } else
+ __map_mft_entry(me);
+ down_write(&vol->mft_entries_sem);
+ list_for_each(tmp, &vol->mft_entries) {
+ m = list_entry(tmp, mft_entry, m_list);
+ if ((__u64)m->m_ref & MFT_REFERENCE_MASK_CPU <
+ (__u64)me->m_ref & MFT_REFERENCE_MASK_CPU)
+ continue;
+ if (m->m_ref == me->m_ref) {
+ up_write(&vol->mft_entries_sem);
+ return -EEXIST; /* BUG()! */
+ }
+ __list_add(&me->m_list, &tmp->m_list->prev, &tmp->m_list);
+ break;
+ }
+ vol->nr_mft_entries++;
+ if (mrec && dirty) {
+ down_write(&me->m_sem);
+ SetMftEntryDirty(me);
+ list_add_tail(&me->m_dirty_list, &vol->dirty_mft_entries);
+ up_write(&me->m_sem);
+ vol->nr_dirty_mft_entries++;
+ }
+ up_write(&vol->mft_entries_sem);
+ return 0;
+}
+
+int remove_mft_entry(mft_entry *me)
+{
+ ntfs_volume *vol = me->m_vol;
- return;
+ if (atomic_read(me->count))
+ return -EBUSY;
+ if (MftEntryDirty(me))
+ flush_mft_entry(me);
+ down_write(&vol->mft_entries_sem);
+ if (atomic_read(me->count)) {
+ up_write(&vol->mft_entries_sem);
+ return -EBUSY;
+ }
+ list_del(&me->m_list);
+ vol->nr_mft_entries--;
+ up_write(&vol->mft_entries_sem);
+ down_write(&me->m_rec_sem);
+ free(me->m_rec);
+ up_write(&me->m_rec_sem);
+ down_write(&me->m_sem);
+ up_write(&me->m_sem);
+ free(me);
+ return 0;
}
Index: volume.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/volume.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -U2 -r1.8 -r1.9
--- volume.c 2001/04/02 02:04:37 1.8
+++ volume.c 2001/04/05 20:14:45 1.9
@@ -185,4 +185,22 @@
vol->clusters_per_mft_record);
#endif
+ /* Initialize files and mft records lists and associated variables. */
+ INIT_LIST_HEAD(vol->open_files);
+ INIT_LIST_HEAD(vol->closed_files);
+ vol->max_files = 1000;
+ init_rwsem(&vol->files_sem);
+ INIT_LIST_HEAD(vol->mft_entries);
+ INIT_LIST_HEAD(vol->dirty_mft_entries);
+ init_rwsem(&vol->mft_entries_sem);
+ /* Note: No locking needed until we return from this function. */
+ /*if (!(me = __allocate_mft_entry())) {
+ int eo = errno;
+ puts(FAILED);
+ errno = eo;
+ perror("Error allocating mft entry.");
+ errno = eo;
+ goto error_exit;
+ }
+ */
/* Start with $Mft. */
printf("Loading $Mft... ");
|