mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +00:00
Added a branch of linux-ntfs based on kernel 2.6.0test11, this can be used as a FOUNDATION for building a STABLE read/write ntfs driver. check out http://linux-ntfs.sf.net for details on this driver.
svn path=/trunk/; revision=6860
This commit is contained in:
parent
f0d7ce034e
commit
8a1c4241be
29 changed files with 15739 additions and 0 deletions
802
reactos/drivers/fs/ntfs/linux-ntfs/ChangeLog
Normal file
802
reactos/drivers/fs/ntfs/linux-ntfs/ChangeLog
Normal file
|
@ -0,0 +1,802 @@
|
|||
ToDo:
|
||||
- Find and fix bugs.
|
||||
- Enable NFS exporting of NTFS.
|
||||
- Implement aops->set_page_dirty() in order to take control of buffer
|
||||
dirtying. Not having it means if page_has_buffers(), all buffers
|
||||
will be dirtied with the page. And if not they won't be. That is
|
||||
fine for the moment but will break once we enable metadata updates.
|
||||
- Implement sops->dirty_inode() to implement {a,m,c} time updates and
|
||||
such things.
|
||||
- Implement sops->write_inode().
|
||||
- In between ntfs_prepare/commit_write, need exclusion between
|
||||
simultaneous file extensions. Need perhaps an NInoResizeUnderway()
|
||||
flag which we can set in ntfs_prepare_write() and clear again in
|
||||
ntfs_commit_write(). Just have to be careful in readpage/writepage,
|
||||
as well as in truncate, that we play nice... We might need to have
|
||||
a data_size field in the ntfs_inode to store the real attribute
|
||||
length. Also need to be careful with initialized_size extention in
|
||||
ntfs_prepare_write. Basically, just be _very_ careful in this code...
|
||||
OTOH, perhaps i_sem, which is held accross generic_file_write is
|
||||
sufficient for synchronisation here. We then just need to make sure
|
||||
ntfs_readpage/writepage/truncate interoperate properly with us.
|
||||
|
||||
2.1.5 - Fix minor bug in attribute list attribute handling.
|
||||
|
||||
- Fix bug in attribute list handling. Actually it is not as much a bug
|
||||
as too much protection in that we were not allowing attribute lists
|
||||
which waste space on disk while Windows XP clearly allows it and in
|
||||
fact creates such attribute lists so our driver was failing.
|
||||
- Update NTFS documentation ready for 2.6 kernel release.
|
||||
|
||||
2.1.4 - Reduce compiler requirements.
|
||||
|
||||
- Remove all uses of unnamed structs and unions in the driver to make
|
||||
old and newer gcc versions happy. Makes it a bit uglier IMO but at
|
||||
least people will stop hassling me about it.
|
||||
|
||||
2.1.3 - Important bug fixes in corner cases.
|
||||
|
||||
- super.c::parse_ntfs_boot_sector(): Correct the check for 64-bit
|
||||
clusters. (Philipp Thomas)
|
||||
- attrib.c::load_attribute_list(): Fix bug when initialized_size is a
|
||||
multiple of the block_size but not the cluster size. (Szabolcs
|
||||
Szakacsits <szaka@sienet.hu>)
|
||||
|
||||
2.1.2 - Important bug fixes aleviating the hangs in statfs.
|
||||
|
||||
- Fix buggy free cluster and free inode determination logic.
|
||||
|
||||
2.1.1 - Minor updates.
|
||||
|
||||
- Add handling for initialized_size != data_size in compressed files.
|
||||
- Reduce function local stack usage from 0x3d4 bytes to just noise in
|
||||
fs/ntfs/upcase.c. (Randy Dunlap <rddunlap@osdl.ord>)
|
||||
- Remove compiler warnings for newer gcc.
|
||||
|
||||
2.1.0 - First steps towards write support: implement file overwrite.
|
||||
|
||||
- Add configuration option for developmental write support with an
|
||||
appropriately scary configuration help text.
|
||||
- Initial implementation of fs/ntfs/aops.c::ntfs_writepage() and its
|
||||
helper fs/ntfs/aops.c::ntfs_write_block(). This enables mmap(2) based
|
||||
overwriting of existing files on ntfs. Note: Resident files are
|
||||
only written into memory, and not written out to disk at present, so
|
||||
avoid writing to files smaller than about 1kiB.
|
||||
- Initial implementation of fs/ntfs/aops.c::ntfs_prepare_write(), its
|
||||
helper fs/ntfs/aops.c::ntfs_prepare_nonresident_write() and their
|
||||
counterparts, fs/ntfs/aops.c::ntfs_commit_write(), and
|
||||
fs/ntfs/aops.c::ntfs_commit_nonresident_write(), respectively. Also,
|
||||
add generic_file_write() to the ntfs file operations (fs/ntfs/file.c).
|
||||
This enables write(2) based overwriting of existing files on ntfs.
|
||||
Note: As with mmap(2) based overwriting, resident files are only
|
||||
written into memory, and not written out to disk at present, so avoid
|
||||
writing to files smaller than about 1kiB.
|
||||
- Implement ->truncate (fs/ntfs/inode.c::ntfs_truncate()) and
|
||||
->setattr() (fs/ntfs/inode.c::ntfs_setattr()) inode operations for
|
||||
files with the purpose of intercepting and aborting all i_size
|
||||
changes which we do not support yet. ntfs_truncate() actually only
|
||||
emits a warning message but AFAICS our interception of i_size changes
|
||||
elsewhere means ntfs_truncate() never gets called for i_size changes.
|
||||
It is only called from generic_file_write() when we fail in
|
||||
ntfs_prepare_{,nonresident_}write() in order to discard any
|
||||
instantiated buffers beyond i_size. Thus i_size is not actually
|
||||
changed so our warning message is enough. Unfortunately it is not
|
||||
possible to easily determine if i_size is being changed or not hence
|
||||
we just emit an appropriately worded error message.
|
||||
|
||||
2.0.25 - Small bug fixes and cleanups.
|
||||
|
||||
- Unlock the page in an out of memory error code path in
|
||||
fs/ntfs/aops.c::ntfs_read_block().
|
||||
- If fs/ntfs/aops.c::ntfs_read_page() is called on an uptodate page,
|
||||
just unlock the page and return. (This can happen due to ->writepage
|
||||
clearing PageUptodate() during write out of MstProtected()
|
||||
attributes.
|
||||
- Remove leaked write code again.
|
||||
|
||||
2.0.24 - Cleanups.
|
||||
|
||||
- Treat BUG_ON() as ASSERT() not VERIFY(), i.e. do not use side effects
|
||||
inside BUG_ON(). (Adam J. Richter)
|
||||
- Split logical OR expressions inside BUG_ON() into individual BUG_ON()
|
||||
calls for improved debugging. (Adam J. Richter)
|
||||
- Add errors flag to the ntfs volume state, accessed via
|
||||
NVol{,Set,Clear}Errors(vol).
|
||||
- Do not allow read-write remounts of read-only volumes with errors.
|
||||
- Clarify comment for ntfs file operation sendfile which was added by
|
||||
Christoph Hellwig a while ago (just using generic_file_sendfile())
|
||||
to say that ntfs ->sendfile is only used for the case where the
|
||||
source data is on the ntfs partition and the destination is
|
||||
somewhere else, i.e. nothing we need to concern ourselves with.
|
||||
- Add generic_file_write() as our ntfs file write operation.
|
||||
|
||||
2.0.23 - Major bug fixes (races, deadlocks, non-i386 architectures).
|
||||
|
||||
- Massive internal locking changes to mft record locking. Fixes lock
|
||||
recursion and replaces the mrec_lock read/write semaphore with a
|
||||
mutex. Also removes the now superfluous mft_count. This fixes several
|
||||
race conditions and deadlocks, especially in the future write code.
|
||||
- Fix ntfs over loopback for compressed files by adding an
|
||||
optimization barrier. (gcc was screwing up otherwise ?)
|
||||
- Miscellaneous cleanups all over the code and a fix or two in error
|
||||
handling code paths.
|
||||
Thanks go to Christoph Hellwig for pointing out the following two:
|
||||
- Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs().
|
||||
- Fix ntfs_free() for ia64 and parisc by checking for VMALLOC_END, too.
|
||||
|
||||
2.0.22 - Cleanups, mainly to ntfs_readdir(), and use C99 initializers.
|
||||
|
||||
- Change fs/ntfs/dir.c::ntfs_reddir() to only read/write ->f_pos once
|
||||
at entry/exit respectively.
|
||||
- Use C99 initializers for structures.
|
||||
- Remove unused variable blocks from fs/ntfs/aops.c::ntfs_read_block().
|
||||
|
||||
2.0.21 - Check for, and refuse to work with too large files/directories/volumes.
|
||||
|
||||
- Limit volume size at mount time to 2TiB on architectures where
|
||||
unsigned long is 32-bits (fs/ntfs/super.c::parse_ntfs_boot_sector()).
|
||||
This is the most we can do without overflowing the 32-bit limit of
|
||||
the block device size imposed on us by sb_bread() and sb_getblk()
|
||||
for the time being.
|
||||
- Limit file/directory size at open() time to 16TiB on architectures
|
||||
where unsigned long is 32-bits (fs/ntfs/file.c::ntfs_file_open() and
|
||||
fs/ntfs/dir.c::ntfs_dir_open()). This is the most we can do without
|
||||
overflowing the page cache page index.
|
||||
|
||||
2.0.20 - Support non-resident directory index bitmaps, fix page leak in readdir.
|
||||
|
||||
- Move the directory index bitmap to use an attribute inode instead of
|
||||
having special fields for it inside the ntfs inode structure. This
|
||||
means that the index bitmaps now use the page cache for i/o, too,
|
||||
and also as a side effect we get support for non-resident index
|
||||
bitmaps for free.
|
||||
- Simplify/cleanup error handling in fs/ntfs/dir.c::ntfs_readdir() and
|
||||
fix a page leak that manifested itself in some cases.
|
||||
- Add fs/ntfs/inode.c::ntfs_put_inode(), which we need to release the
|
||||
index bitmap inode on the final iput().
|
||||
|
||||
2.0.19 - Fix race condition, improvements, and optimizations in i/o interface.
|
||||
|
||||
- Apply block optimization added to fs/ntfs/aops.c::ntfs_read_block()
|
||||
to fs/ntfs/compress.c::ntfs_file_read_compressed_block() as well.
|
||||
- Drop the "file" from ntfs_file_read_compressed_block().
|
||||
- Rename fs/ntfs/aops.c::ntfs_enb_buffer_read_async() to
|
||||
ntfs_end_buffer_async_read() (more like the fs/buffer.c counterpart).
|
||||
- Update ntfs_end_buffer_async_read() with the improved logic from
|
||||
its updated counterpart fs/buffer.c::end_buffer_async_read(). Apply
|
||||
further logic improvements to better determine when we set PageError.
|
||||
- Update submission of buffers in fs/ntfs/aops.c::ntfs_read_block() to
|
||||
check for the buffers being uptodate first in line with the updated
|
||||
fs/buffer.c::block_read_full_page(). This plugs a small race
|
||||
condition.
|
||||
|
||||
2.0.18 - Fix race condition in reading of compressed files.
|
||||
|
||||
- There was a narrow window between checking a buffer head for being
|
||||
uptodate and locking it in ntfs_file_read_compressed_block(). We now
|
||||
lock the buffer and then check whether it is uptodate or not.
|
||||
|
||||
2.0.17 - Cleanups and optimizations - shrinking the ToDo list.
|
||||
|
||||
- Modify fs/ntfs/inode.c::ntfs_read_locked_inode() to return an error
|
||||
code and update callers, i.e. ntfs_iget(), to pass that error code
|
||||
up instead of just using -EIO.
|
||||
- Modifications to super.c to ensure that both mount and remount
|
||||
cannot set any write related options when the driver is compiled
|
||||
read-only.
|
||||
- Optimize block resolution in fs/ntfs/aops.c::ntfs_read_block() to
|
||||
cache the current run list element. This should improve performance
|
||||
when reading very large and/or very fragmented data.
|
||||
|
||||
2.0.16 - Convert access to $MFT/$BITMAP to attribute inode API.
|
||||
|
||||
- Fix a stupid bug introduced in 2.0.15 where we were unmapping the
|
||||
wrong inode in fs/ntfs/inode.c::ntfs_attr_iget().
|
||||
- Fix debugging check in fs/ntfs/aops.c::ntfs_read_block().
|
||||
- Convert $MFT/$BITMAP access to attribute inode API and remove all
|
||||
remnants of the ugly mftbmp address space and operations hack. This
|
||||
means we finally have only one readpage function as well as only one
|
||||
async io completion handler. Yey! The mft bitmap is now just an
|
||||
attribute inode and is accessed from vol->mftbmp_ino just as if it
|
||||
were a normal file. Fake inodes rule. (-:
|
||||
|
||||
2.0.15 - Fake inodes based attribute i/o via the pagecache, fixes and cleanups.
|
||||
|
||||
- Fix silly bug in fs/ntfs/super.c::parse_options() which was causing
|
||||
remounts to fail when the partition had an entry in /etc/fstab and
|
||||
the entry specified the nls= option.
|
||||
- Apply same macro magic used in fs/ntfs/inode.h to fs/ntfs/volume.h to
|
||||
expand all the helper functions NVolFoo(), NVolSetFoo(), and
|
||||
NVolClearFoo().
|
||||
- Move copyright statement from driver initialisation message to
|
||||
module description (fs/super.c). This makes the initialisation
|
||||
message fit on one line and fits in better with rest of kernel.
|
||||
- Update fs/ntfs/attrib.c::map_run_list() to work on both real and
|
||||
attribute inodes, and both for files and directories.
|
||||
- Implement fake attribute inodes allowing all attribute i/o to go via
|
||||
the page cache and to use all the normal vfs/mm functionality:
|
||||
- Add ntfs_attr_iget() and its helper ntfs_read_locked_attr_inode()
|
||||
to fs/ntfs/inode.c.
|
||||
- Add needed cleanup code to ntfs_clear_big_inode().
|
||||
- Merge address space operations for files and directories (aops.c),
|
||||
now just have ntfs_aops:
|
||||
- Rename:
|
||||
end_buffer_read_attr_async() -> ntfs_end_buffer_read_async(),
|
||||
ntfs_attr_read_block() -> ntfs_read_block(),
|
||||
ntfs_file_read_page() -> ntfs_readpage().
|
||||
- Rewrite fs/ntfs/aops.c::ntfs_readpage() to work on both real and
|
||||
attribute inodes, and both for files and directories.
|
||||
- Remove obsolete fs/ntfs/aops.c::ntfs_mst_readpage().
|
||||
|
||||
2.0.14 - Run list merging code cleanup, minor locking changes, typo fixes.
|
||||
|
||||
- Change fs/ntfs/super.c::ntfs_statfs() to not rely on BKL by moving
|
||||
the locking out of super.c::get_nr_free_mft_records() and taking and
|
||||
dropping the mftbmp_lock rw_semaphore in ntfs_statfs() itself.
|
||||
- Bring attribute run list merging code (fs/ntfs/attrib.c) in sync with
|
||||
current userspace ntfs library code. This means that if a merge
|
||||
fails the original run lists are always left unmodified instead of
|
||||
being silently corrupted.
|
||||
- Misc typo fixes.
|
||||
|
||||
2.0.13 - Use iget5_locked() in preparation for fake inodes and small cleanups.
|
||||
|
||||
- Remove nr_mft_bits and the now superfluous union with nr_mft_records
|
||||
from ntfs_volume structure.
|
||||
- Remove nr_lcn_bits and the now superfluous union with nr_clusters
|
||||
from ntfs_volume structure.
|
||||
- Use iget5_locked() and friends instead of conventional iget(). Wrap
|
||||
the call in fs/ntfs/inode.c::ntfs_iget() and update callers of iget()
|
||||
to use ntfs_iget(). Leave only one iget() call at mount time so we
|
||||
don't need an ntfs_iget_mount().
|
||||
- Change fs/ntfs/inode.c::ntfs_new_extent_inode() to take mft_no as an
|
||||
additional argument.
|
||||
|
||||
2.0.12 - Initial cleanup of address space operations following 2.0.11 changes.
|
||||
|
||||
- Merge fs/ntfs/aops.c::end_buffer_read_mst_async() and
|
||||
fs/ntfs/aops.c::end_buffer_read_file_async() into one function
|
||||
fs/ntfs/aops.c::end_buffer_read_attr_async() using NInoMstProtected()
|
||||
to determine whether to apply mst fixups or not.
|
||||
- Above change allows merging fs/ntfs/aops.c::ntfs_file_read_block()
|
||||
and fs/ntfs/aops.c::ntfs_mst_readpage() into one function
|
||||
fs/ntfs/aops.c::ntfs_attr_read_block(). Also, create a tiny wrapper
|
||||
fs/ntfs/aops.c::ntfs_mst_readpage() to transform the parameters from
|
||||
the VFS readpage function prototype to the ntfs_attr_read_block()
|
||||
function prototype.
|
||||
|
||||
2.0.11 - Initial preparations for fake inode based attribute i/o.
|
||||
|
||||
- Move definition of ntfs_inode_state_bits to fs/ntfs/inode.h and
|
||||
do some macro magic (adapted from include/linux/buffer_head.h) to
|
||||
expand all the helper functions NInoFoo(), NInoSetFoo(), and
|
||||
NInoClearFoo().
|
||||
- Add new flag to ntfs_inode_state_bits: NI_Sparse.
|
||||
- Add new fields to ntfs_inode structure to allow use of fake inodes
|
||||
for attribute i/o: type, name, name_len. Also add new state bits:
|
||||
NI_Attr, which, if set, indicates the inode is a fake inode, and
|
||||
NI_MstProtected, which, if set, indicates the attribute uses multi
|
||||
sector transfer protection, i.e. fixups need to be applied after
|
||||
reads and before/after writes.
|
||||
- Rename fs/ntfs/inode.c::ntfs_{new,clear,destroy}_inode() to
|
||||
ntfs_{new,clear,destroy}_extent_inode() and update callers.
|
||||
- Use ntfs_clear_extent_inode() in fs/ntfs/inode.c::__ntfs_clear_inode()
|
||||
instead of ntfs_destroy_extent_inode().
|
||||
- Cleanup memory deallocations in {__,}ntfs_clear_{,big_}inode().
|
||||
- Make all operations on ntfs inode state bits use the NIno* functions.
|
||||
- Set up the new ntfs inode fields and state bits in
|
||||
fs/ntfs/inode.c::ntfs_read_inode() and add appropriate cleanup of
|
||||
allocated memory to __ntfs_clear_inode().
|
||||
- Cleanup ntfs_inode structure a bit for better ordering of elements
|
||||
w.r.t. their size to allow better packing of the structure in memory.
|
||||
|
||||
2.0.10 - There can only be 2^32 - 1 inodes on an NTFS volume.
|
||||
|
||||
- Add check at mount time to verify that the number of inodes on the
|
||||
volume does not exceed 2^32 - 1, which is the maximum allowed for
|
||||
NTFS according to Microsoft.
|
||||
- Change mft_no member of ntfs_inode structure to be unsigned long.
|
||||
Update all users. This makes ntfs_inode->mft_no just a copy of struct
|
||||
inode->i_ino. But we can't just always use struct inode->i_ino and
|
||||
remove mft_no because extent inodes do not have an attached struct
|
||||
inode.
|
||||
|
||||
2.0.9 - Decompression engine now uses a single buffer and other cleanups.
|
||||
|
||||
- Change decompression engine to use a single buffer protected by a
|
||||
spin lock instead of per-CPU buffers. (Rusty Russell)
|
||||
- Do not update cb_pos when handling a partial final page during
|
||||
decompression of a sparse compression block, as the value is later
|
||||
reset without being read/used. (Rusty Russell)
|
||||
- Switch to using the new KM_BIO_SRC_IRQ for atomic kmap()s. (Andrew
|
||||
Morton)
|
||||
- Change buffer size in ntfs_readdir()/ntfs_filldir() to use
|
||||
NLS_MAX_CHARSET_SIZE which makes the buffers almost 1kiB each but
|
||||
it also makes everything safer so it is a good thing.
|
||||
- Miscellaneous minor cleanups to comments.
|
||||
|
||||
2.0.8 - Major updates for handling of case sensitivity and dcache aliasing.
|
||||
|
||||
Big thanks go to Al Viro and other inhabitants of #kernel for investing
|
||||
their time to discuss the case sensitivity and dcache aliasing issues.
|
||||
|
||||
- Remove unused source file fs/ntfs/attraops.c.
|
||||
- Remove show_inodes mount option(s), thus dropping support for
|
||||
displaying of short file names.
|
||||
- Remove deprecated mount option posix.
|
||||
- Restore show_sys_files mount option.
|
||||
- Add new mount option case_sensitive, to determine if the driver
|
||||
treats file names as case sensitive or not. If case sensitive, create
|
||||
file names in the POSIX namespace. Otherwise create file names in the
|
||||
LONG/WIN32 namespace. Note, files remain accessible via their short
|
||||
file name, if it exists.
|
||||
- Remove really dumb logic bug in boot sector recovery code.
|
||||
- Fix dcache aliasing issues wrt short/long file names via changes
|
||||
to fs/ntfs/dir.c::ntfs_lookup_inode_by_name() and
|
||||
fs/ntfs/namei.c::ntfs_lookup():
|
||||
- Add additional argument to ntfs_lookup_inode_by_name() in which we
|
||||
return information about the matching file name if the case is not
|
||||
matching or the match is a short file name. See comments above the
|
||||
function definition for details.
|
||||
- Change ntfs_lookup() to only create dcache entries for the correctly
|
||||
cased file name and only for the WIN32 namespace counterpart of DOS
|
||||
namespace file names. This ensures we have only one dentry per
|
||||
directory and also removes all dcache aliasing issues between short
|
||||
and long file names once we add write support. See comments above
|
||||
function for details.
|
||||
- Fix potential 1 byte overflow in fs/ntfs/unistr.c::ntfs_ucstonls().
|
||||
|
||||
2.0.7 - Minor cleanups and updates for changes in core kernel code.
|
||||
|
||||
- Remove much of the NULL struct element initializers.
|
||||
- Various updates to make compatible with recent kernels.
|
||||
- Remove defines of MAX_BUF_PER_PAGE and include linux/buffer_head.h
|
||||
in fs/ntfs/ntfs.h instead.
|
||||
- Remove no longer needed KERNEL_VERSION checks. We are now in the
|
||||
kernel proper so they are no longer needed.
|
||||
|
||||
2.0.6 - Major bugfix to make compatible with other kernel changes.
|
||||
|
||||
- Initialize the mftbmp address space properly now that there are more
|
||||
fields in the struct address_space. This was leading to hangs and
|
||||
oopses on umount since 2.5.12 because of changes to other parts of
|
||||
the kernel. We probably want a kernel generic init_address_space()
|
||||
function...
|
||||
- Drop BKL from ntfs_readdir() after consultation with Al Viro. The
|
||||
only caller of ->readdir() is vfs_readdir() which holds i_sem during
|
||||
the call, and i_sem is sufficient protection against changes in the
|
||||
directory inode (including ->i_size).
|
||||
- Use generic_file_llseek() for directories (as opposed to
|
||||
default_llseek()) as this downs i_sem instead of the BKL which is
|
||||
what we now need for exclusion against ->f_pos changes considering we
|
||||
no longer take the BKL in ntfs_readdir().
|
||||
|
||||
2.0.5 - Major bugfix. Buffer overflow in extent inode handling.
|
||||
|
||||
- No need to set old blocksize in super.c::ntfs_fill_super() as the
|
||||
VFS does so via invocation of deactivate_super() calling
|
||||
fs->fill_super() calling block_kill_super() which does it.
|
||||
- BKL moved from VFS into dir.c::ntfs_readdir(). (Linus Torvalds)
|
||||
-> Do we really need it? I don't think so as we have exclusion on
|
||||
the directory ntfs_inode rw_semaphore mrec_lock. We mmight have to
|
||||
move the ->f_pos accesses under the mrec_lock though. Check this...
|
||||
- Fix really, really, really stupid buffer overflow in extent inode
|
||||
handling in mft.c::map_extent_mft_record().
|
||||
|
||||
2.0.4 - Cleanups and updates for kernel 2.5.11.
|
||||
|
||||
- Add documentation on how to use the MD driver to be able to use NTFS
|
||||
stripe and volume sets in Linux and generally cleanup documentation
|
||||
a bit.
|
||||
Remove all uses of kdev_t in favour of struct block_device *:
|
||||
- Change compress.c::ntfs_file_read_compressed_block() to use
|
||||
sb_getblk() instead of getblk().
|
||||
- Change super.c::ntfs_fill_super() to use bdev_hardsect_size() instead
|
||||
of get_hardsect_size().
|
||||
- No need to get old blocksize in super.c::ntfs_fill_super() as
|
||||
fs/super.c::get_sb_bdev() already does this.
|
||||
- Set bh->b_bdev instead of bh->b_dev throughout aops.c.
|
||||
|
||||
2.0.3 - Small bug fixes, cleanups, and performance improvements.
|
||||
|
||||
- Remove some dead code from mft.c.
|
||||
- Optimize readpage and read_block functions throughout aops.c so that
|
||||
only initialized blocks are read. Non-initialized ones have their
|
||||
buffer head mapped, zeroed, and set up to date, without scheduling
|
||||
any i/o. Thanks to Al Viro for advice on how to avoid the device i/o.
|
||||
Thanks go to Andrew Morton for spotting the below:
|
||||
- Fix buglet in allocate_compression_buffers() error code path.
|
||||
- Call flush_dcache_page() after modifying page cache page contents in
|
||||
ntfs_file_readpage().
|
||||
- Check for existence of page buffers throughout aops.c before calling
|
||||
create_empty_buffers(). This happens when an I/O error occurs and the
|
||||
read is retried. (It also happens once writing is implemented so that
|
||||
needed doing anyway but I had left it for later...)
|
||||
- Don't BUG_ON() uptodate and/or mapped buffers throughout aops.c in
|
||||
readpage and read_block functions. Reasoning same as above (i.e. I/O
|
||||
error retries and future write code paths.)
|
||||
|
||||
2.0.2 - Minor updates and cleanups.
|
||||
|
||||
- Cleanup: rename mst.c::__post_read_mst_fixup to post_write_mst_fixup
|
||||
and cleanup the code a bit, removing the unused size parameter.
|
||||
- Change default fmask to 0177 and update documentation.
|
||||
- Change attrib.c::get_attr_search_ctx() to return the search context
|
||||
directly instead of taking the address of a pointer. A return value
|
||||
of NULL means the allocation failed. Updated all callers
|
||||
appropriately.
|
||||
- Update to 2.5.9 kernel (preserving backwards compatibility) by
|
||||
replacing all occurences of page->buffers with page_buffers(page).
|
||||
- Fix minor bugs in run list merging, also minor cleanup.
|
||||
- Updates to bootsector layout and mft mirror contents descriptions.
|
||||
- Small bug fix in error detection in unistr.c and some cleanups.
|
||||
- Grow name buffer allocations in unistr.c in aligned mutlipled of 64
|
||||
bytes.
|
||||
|
||||
2.0.1 - Minor updates.
|
||||
|
||||
- Make default umask correspond to documentation.
|
||||
- Improve documentation.
|
||||
- Set default mode to include execute bit. The {u,f,d}mask can be used
|
||||
to take it away if desired. This allows binaries to be executed from
|
||||
a mounted ntfs partition.
|
||||
|
||||
2.0.0 - New version number. Remove TNG from the name. Now in the kernel.
|
||||
|
||||
- Add kill_super, just keeping up with the vfs changes in the kernel.
|
||||
- Repeat some changes from tng-0.0.8 that somehow got lost on the way
|
||||
from the CVS import into BitKeeper.
|
||||
- Begin to implement proper handling of allocated_size vs
|
||||
initialized_size vs data_size (i.e. i_size). Done are
|
||||
mft.c::ntfs_mft_readpage(), aops.c::end_buffer_read_index_async(),
|
||||
and attrib.c::load_attribute_list().
|
||||
- Lock the run list in attrib.c::load_attribute_list() while using it.
|
||||
- Fix memory leak in ntfs_file_read_compressed_block() and generally
|
||||
clean up compress.c a little, removing some uncommented/unused debug
|
||||
code.
|
||||
- Tidy up dir.c a little bit.
|
||||
- Don't bother getting the run list in inode.c::ntfs_read_inode().
|
||||
- Merge mft.c::ntfs_mft_readpage() and aops.c::ntfs_index_readpage()
|
||||
creating aops.c::ntfs_mst_readpage(), improving the handling of
|
||||
holes and overflow in the process and implementing the correct
|
||||
equivalent of ntfs_file_get_block() in ntfs_mst_readpage() itself.
|
||||
I am aiming for correctness at the moment. Modularisation can come
|
||||
later.
|
||||
- Rename aops.c::end_buffer_read_index_async() to
|
||||
end_buffer_read_mst_async() and optimize the overflow checking and
|
||||
handling.
|
||||
- Use the host of the mftbmp address space mapping to hold the ntfs
|
||||
volume. This is needed so the async i/o completion handler can
|
||||
retrieve a pointer to the volume. Hopefully this will not cause
|
||||
problems elsewhere in the kernel... Otherwise will need to use a
|
||||
fake inode.
|
||||
- Complete implementation of proper handling of allocated_size vs
|
||||
initialized_size vs data_size (i.e. i_size) in whole driver.
|
||||
Basically aops.c is now completely rewritten.
|
||||
- Change NTFS driver name to just NTFS and set version number to 2.0.0
|
||||
to make a clear distinction from the old driver which is still on
|
||||
version 1.1.22.
|
||||
|
||||
tng-0.0.8 - 08/03/2002 - Now using BitKeeper, http://linux-ntfs.bkbits.net/
|
||||
|
||||
- Replace bdevname(sb->s_dev) with sb->s_id.
|
||||
- Remove now superfluous new-line characters in all callers of
|
||||
ntfs_debug().
|
||||
- Apply kludge in ntfs_read_inode(), setting i_nlink to 1 for
|
||||
directories. Without this the "find" utility gets very upset which is
|
||||
fair enough as Linux/Unix do not support directory hard links.
|
||||
- Further run list merging work. (Richard Russon)
|
||||
- Backwards compatibility for gcc-2.95. (Richard Russon)
|
||||
- Update to kernel 2.5.5-pre1 and rediff the now tiny patch.
|
||||
- Convert to new file system declaration using ->ntfs_get_sb() and
|
||||
replacing ntfs_read_super() with ntfs_fill_super().
|
||||
- Set s_maxbytes to MAX_LFS_FILESIZE to avoid page cache page index
|
||||
overflow on 32-bit architectures.
|
||||
- Cleanup upcase loading code to use ntfs_(un)map_page().
|
||||
- Disable/reenable preemtion in critical sections of compession engine.
|
||||
- Replace device size determination in ntfs_fill_super() with
|
||||
sb->s_bdev->bd_inode->i_size (in bytes) and remove now superfluous
|
||||
function super.c::get_nr_blocks().
|
||||
- Implement a mount time option (show_inodes) allowing choice of which
|
||||
types of inode names readdir() returns and modify ntfs_filldir()
|
||||
accordingly. There are several parameters to show_inodes:
|
||||
system: system files
|
||||
win32: long file names (including POSIX file names) [DEFAULT]
|
||||
long: same as win32
|
||||
dos: short file names only (excluding POSIX file names)
|
||||
short: same as dos
|
||||
posix: same as both win32 and dos
|
||||
all: all file names
|
||||
Note that the options are additive, i.e. specifying:
|
||||
-o show_inodes=system,show_inodes=win32,show_inodes=dos
|
||||
is the same as specifying:
|
||||
-o show_inodes=all
|
||||
Note that the "posix" and "all" options will show all directory
|
||||
names, BUT the link count on each directory inode entry is set to 1,
|
||||
due to Linux not supporting directory hard links. This may well
|
||||
confuse some userspace applications, since the directory names will
|
||||
have the same inode numbers. Thus it is NOT advisable to use the
|
||||
"posix" or "all" options. We provide them only for completeness sake.
|
||||
- Add copies of allocated_size, initialized_size, and compressed_size to
|
||||
the ntfs inode structure and set them up in
|
||||
inode.c::ntfs_read_inode(). These reflect the unnamed data attribute
|
||||
for files and the index allocation attribute for directories.
|
||||
- Add copies of allocated_size and initialized_size to ntfs inode for
|
||||
$BITMAP attribute of large directories and set them up in
|
||||
inode.c::ntfs_read_inode().
|
||||
- Add copies of allocated_size and initialized_size to ntfs volume for
|
||||
$BITMAP attribute of $MFT and set them up in
|
||||
super.c::load_system_files().
|
||||
- Parse deprecated ntfs driver options (iocharset, show_sys_files,
|
||||
posix, and utf8) and tell user what the new options to use are. Note
|
||||
we still do support them but they will be removed with kernel 2.7.x.
|
||||
- Change all occurences of integer long long printf formatting to hex
|
||||
as printk() will not support long long integer format if/when the
|
||||
div64 patch goes into the kernel.
|
||||
- Make slab caches have stable names and change the names to what they
|
||||
were intended to be. These changes are required/made possible by the
|
||||
new slab cache name handling which removes the length limitation by
|
||||
requiring the caller of kmem_cache_create() to supply a stable name
|
||||
which is then referenced but not copied.
|
||||
- Rename run_list structure to run_list_element and create a new
|
||||
run_list structure containing a pointer to a run_list_element
|
||||
structure and a read/write semaphore. Adapt all users of run lists
|
||||
to new scheme and take and release the lock as needed. This fixes a
|
||||
nasty race as the run_list changes even when inodes are locked for
|
||||
reading and even when the inode isn't locked at all, so we really
|
||||
needed the serialization. We use a semaphore rather than a spinlock
|
||||
as memory allocations can sleep and doing everything GFP_ATOMIC
|
||||
would be silly.
|
||||
- Cleanup read_inode() removing all code checking for lowest_vcn != 0.
|
||||
This can never happen due to the nature of lookup_attr() and how we
|
||||
support attribute lists. If it did happen it would imply the inode
|
||||
being corrupt.
|
||||
- Check for lowest_vcn != 0 in ntfs_read_inode() and mark the inode as
|
||||
bad if found.
|
||||
- Update to 2.5.6-pre2 changes in struct address_space.
|
||||
- Use parent_ino() when accessing d_parent inode number in dir.c.
|
||||
- Import Sourceforge CVS repository into BitKeeper repository:
|
||||
http://linux-ntfs.bkbits.net/ntfs-tng-2.5
|
||||
- Update fs/Makefile, fs/Config.help, fs/Config.in, and
|
||||
Documentation/filesystems/ntfs.txt for NTFS TNG.
|
||||
- Create kernel configuration option controlling whether debugging
|
||||
is enabled or not.
|
||||
- Add the required export of end_buffer_io_sync() from the patches
|
||||
directory to the kernel code.
|
||||
- Update inode.c::ntfs_show_options() with show_inodes mount option.
|
||||
- Update errors mount option.
|
||||
|
||||
tng-0.0.7 - 13/02/2002 - The driver is now feature complete for read-only!
|
||||
|
||||
- Cleanup mft.c and it's debug/error output in particular. Fix a minor
|
||||
bug in mapping of extent inodes. Update all the comments to fit all
|
||||
the recent code changes.
|
||||
- Modify vcn_to_lcn() to cope with entirely unmapped run lists.
|
||||
- Cleanups in compress.c, mostly comments and folding help.
|
||||
- Implement attrib.c::map_run_list() as a generic helper.
|
||||
- Make compress.c::ntfs_file_read_compressed_block() use map_run_list()
|
||||
thus making code shorter and enabling attribute list support.
|
||||
- Cleanup incorrect use of [su]64 with %L printf format specifier in
|
||||
all source files. Type casts to [unsigned] long long added to correct
|
||||
the mismatches (important for architectures which have long long not
|
||||
being 64 bits).
|
||||
- Merge async io completion handlers for directory indexes and $MFT
|
||||
data into one by setting the index_block_size{_bits} of the ntfs
|
||||
inode for $MFT to the mft_record_size{_bits} of the ntfs_volume.
|
||||
- Cleanup aops.c, update comments.
|
||||
- Make ntfs_file_get_block() use map_run_list() so all files now
|
||||
support attribute lists.
|
||||
- Make ntfs_dir_readpage() almost verbatim copy of
|
||||
block_read_full_page() by using ntfs_file_get_block() with only real
|
||||
difference being the use of our own async io completion handler
|
||||
rather than the default one, thus reducing the amount of code and
|
||||
automatically enabling attribute list support for directory indices.
|
||||
- Fix bug in load_attribute_list() - forgot to call brelse in error
|
||||
code path.
|
||||
- Change parameters to find_attr() and lookup_attr(). We no longer
|
||||
pass in the upcase table and its length. These can be gotten from
|
||||
ctx->ntfs_ino->vol->upcase{_len}. Update all callers.
|
||||
- Cleanups in attrib.c.
|
||||
- Implement merging of run lists, attrib.c::merge_run_lists() and its
|
||||
helpers. (Richard Russon)
|
||||
- Attribute lists part 2, attribute extents and multi part run lists:
|
||||
enable proper support for LCN_RL_NOT_MAPPED and automatic mapping of
|
||||
further run list parts via attrib.c::map_run_list().
|
||||
- Tiny endianness bug fix in decompress_mapping_pairs().
|
||||
|
||||
tng-0.0.6 - Encrypted directories, bug fixes, cleanups, debugging enhancements.
|
||||
|
||||
- Enable encrypted directories. (Their index root is marked encrypted
|
||||
to indicate that new files in that directory should be created
|
||||
encrypted.)
|
||||
- Fix bug in NInoBmpNonResident() macro. (Cut and paste error.)
|
||||
- Enable $Extend system directory. Most (if not all) extended system
|
||||
files do not have unnamed data attributes so ntfs_read_inode() had to
|
||||
special case them but that is ok, as the special casing recovery
|
||||
happens inside an error code path so there is zero slow down in the
|
||||
normal fast path. The special casing is done by introducing a new
|
||||
function inode.c::ntfs_is_extended_system_file() which checks if any
|
||||
of the hard links in the inode point to $Extend as being their parent
|
||||
directory and if they do we assume this is an extended system file.
|
||||
- Create a sysctl/proc interface to allow {dis,en}abling of debug output
|
||||
when compiled with -DDEBUG. Default is debug messages to be disabled.
|
||||
To enable them, one writes a non-zero value to /proc/sys/fs/ntfs-debug
|
||||
(if /proc is enabled) or uses sysctl(2) to effect the same (if sysctl
|
||||
interface is enabled). Inspired by old ntfs driver.
|
||||
- Add debug_msgs insmod/kernel boot parameter to set whether debug
|
||||
messages are {dis,en}abled. This is useful to enable debug messages
|
||||
during ntfs initialization and is the only way to activate debugging
|
||||
when the sysctl interface is not enabled.
|
||||
- Cleanup debug output in various places.
|
||||
- Remove all dollar signs ($) from the source (except comments) to
|
||||
enable compilation on architectures whose gcc compiler does not
|
||||
support dollar signs in the names of variables/constants. Attribute
|
||||
types now start with AT_ instead of $ and $I30 is now just I30.
|
||||
- Cleanup ntfs_lookup() and add consistency check of sequence numbers.
|
||||
- Load complete run list for $MFT/$BITMAP during mount and cleanup
|
||||
access functions. This means we now cope with $MFT/$BITMAP being
|
||||
spread accross several mft records.
|
||||
- Disable modification of mft_zone_multiplier on remount. We can always
|
||||
reenable this later on if we really want to, but we will need to make
|
||||
sure we readjust the mft_zone size / layout accordingly.
|
||||
|
||||
tng-0.0.5 - Modernize for 2.5.x and further in line-ing with Al Viro's comments.
|
||||
|
||||
- Use sb_set_blocksize() instead of set_blocksize() and verify the
|
||||
return value.
|
||||
- Use sb_bread() instead of bread() throughout.
|
||||
- Add index_vcn_size{_bits} to ntfs_inode structure to store the size
|
||||
of a directory index block vcn. Apply resulting simplifications in
|
||||
dir.c everywhere.
|
||||
- Fix a small bug somewhere (but forgot what it was).
|
||||
- Change ntfs_{debug,error,warning} to enable gcc to do type checking
|
||||
on the printf-format parameter list and fix bugs reported by gcc
|
||||
as a result. (Richard Russon)
|
||||
- Move inode allocation strategy to Al's new stuff but maintain the
|
||||
divorce of ntfs_inode from struct inode. To achieve this we have two
|
||||
separate slab caches, one for big ntfs inodes containing a struct
|
||||
inode and pure ntfs inodes and at the same time fix some faulty
|
||||
error code paths in ntfs_read_inode().
|
||||
- Show mount options in proc (inode.c::ntfs_show_options()).
|
||||
|
||||
tng-0.0.4 - Big changes, getting in line with Al Viro's comments.
|
||||
|
||||
- Modified (un)map_mft_record functions to be common for read and write
|
||||
case. To specify which is which, added extra parameter at front of
|
||||
parameter list. Pass either READ or WRITE to this, each has the
|
||||
obvious meaning.
|
||||
- General cleanups to allow for easier folding in vi.
|
||||
- attrib.c::decompress_mapping_pairs() now accepts the old run list
|
||||
argument, and invokes attrib.c::merge_run_lists() to merge the old
|
||||
and the new run lists.
|
||||
- Removed attrib.c::find_first_attr().
|
||||
- Implemented loading of attribute list and complete run list for $MFT.
|
||||
This means we now cope with $MFT being spread across several mft
|
||||
records.
|
||||
- Adapt to 2.5.2-pre9 and the changed create_empty_buffers() syntax.
|
||||
- Adapt major/minor/kdev_t/[bk]devname stuff to new 2.5.x kernels.
|
||||
- Make ntfs_volume be allocated via kmalloc() instead of using a slab
|
||||
cache. There are too little ntfs_volume structures at any one time
|
||||
to justify a private slab cache.
|
||||
- Fix bogus kmap() use in async io completion. Now use kmap_atomic().
|
||||
Use KM_BIO_IRQ on advice from IRC/kernel...
|
||||
- Use ntfs_map_page() in map_mft_record() and create ->readpage method
|
||||
for reading $MFT (ntfs_mft_readpage). In the process create dedicated
|
||||
address space operations (ntfs_mft_aops) for $MFT inode mapping. Also
|
||||
removed the now superfluous exports from the kernel core patch.
|
||||
- Fix a bug where kfree() was used insted of ntfs_free().
|
||||
- Change map_mft_record() to take ntfs_inode as argument instead of
|
||||
vfs inode. Dito for unmap_mft_record(). Adapt all callers.
|
||||
- Add pointer to ntfs_volume to ntfs_inode.
|
||||
- Add mft record number and sequence number to ntfs_inode. Stop using
|
||||
i_ino and i_generation for in-driver purposes.
|
||||
- Implement attrib.c::merge_run_lists(). (Richard Russon)
|
||||
- Remove use of proper inodes by extent inodes. Move i_ino and
|
||||
i_generation to ntfs_inode to do this. Apply simplifications that
|
||||
result and remove iget_no_wait(), etc.
|
||||
- Pass ntfs_inode everywhere in the driver (used to be struct inode).
|
||||
- Add reference counting in ntfs_inode for the ntfs inode itself and
|
||||
for the mapped mft record.
|
||||
- Extend mft record mapping so we can (un)map extent mft records (new
|
||||
functions (un)map_extent_mft_record), and so mappings are reference
|
||||
counted and don't have to happen twice if already mapped - just ref
|
||||
count increases.
|
||||
- Add -o iocharset as alias to -o nls for backwards compatibility.
|
||||
- The latest core patch is now tiny. In fact just a single additional
|
||||
export is necessary over the base kernel.
|
||||
|
||||
tng-0.0.3 - Cleanups, enhancements, bug fixes.
|
||||
|
||||
- Work on attrib.c::decompress_mapping_pairs() to detect base extents
|
||||
and setup the run list appropriately using knowledge provided by the
|
||||
sizes in the base attribute record.
|
||||
- Balance the get_/put_attr_search_ctx() calls so we don't leak memory
|
||||
any more.
|
||||
- Introduce ntfs_malloc_nofs() and ntfs_free() to allocate/free a single
|
||||
page or use vmalloc depending on the amount of memory requested.
|
||||
- Cleanup error output. The __FUNCTION__ "(): " is now added
|
||||
automatically. Introduced a new header file debug.h to support this
|
||||
and also moved ntfs_debug() function into it.
|
||||
- Make reading of compressed files more intelligent and especially get
|
||||
rid of the vmalloc_nofs() from readpage(). This now uses per CPU
|
||||
buffers (allocated at first mount with cluster size <= 4kiB and
|
||||
deallocated on last umount with cluster size <= 4kiB), and
|
||||
asynchronous io for the compressed data using a list of buffer heads.
|
||||
Er, we use synchronous io as async io only works on whole pages
|
||||
covered by buffers and not on individual buffer heads...
|
||||
- Bug fix for reading compressed files with sparse compression blocks.
|
||||
|
||||
tng-0.0.2 - Now handles larger/fragmented/compressed volumes/files/dirs.
|
||||
|
||||
- Fixed handling of directories when cluster size exceeds index block
|
||||
size.
|
||||
- Hide DOS only name space directory entries from readdir() but allow
|
||||
them in lookup(). This should fix the problem that Linux doesn't
|
||||
support directory hard links, while still allowing access to entries
|
||||
via their short file name. This also has the benefit of mimicking
|
||||
what Windows users are used to, so it is the ideal solution.
|
||||
- Implemented sync_page everywhere so no more hangs in D state when
|
||||
waiting for a page.
|
||||
- Stop using bforget() in favour of brelse().
|
||||
- Stop locking buffers unnecessarily.
|
||||
- Implemented compressed files (inode->mapping contains uncompressed
|
||||
data, raw compressed data is currently bread() into a vmalloc()ed
|
||||
memory buffer).
|
||||
- Enable compressed directories. (Their index root is marked compressed
|
||||
to indicate that new files in that directory should be created
|
||||
compressed.)
|
||||
- Use vsnprintf rather than vsprintf in the ntfs_error and ntfs_warning
|
||||
functions. (Thanks to Will Dyson for pointing this out.)
|
||||
- Moved the ntfs_inode and ntfs_volume (the former ntfs_inode_info and
|
||||
ntfs_sb_info) out of the common inode and super_block structures and
|
||||
started using the generic_ip and generic_sbp pointers instead. This
|
||||
makes ntfs entirely private with respect to the kernel tree.
|
||||
- Detect compiler version and abort with error message if gcc less than
|
||||
2.96 is used.
|
||||
- Fix bug in name comparison function in unistr.c.
|
||||
- Implement attribute lists part 1, the infrastructure: search contexts
|
||||
and operations, find_external_attr(), lookup_attr()) and make the
|
||||
code use the infrastructure.
|
||||
- Fix stupid buffer overflow bug that became apparent on larger run
|
||||
list containing attributes.
|
||||
- Fix bugs in readdir() that became apparent on larger directories.
|
||||
|
||||
The driver is now really useful and survives the test
|
||||
find . -type f -exec md5sum "{}" \;
|
||||
without any error messages on a over 1GiB sized partition with >16k
|
||||
files on it, including compressed files and directories and many files
|
||||
and directories with attribute lists.
|
||||
|
||||
tng-0.0.1 - The first useful version.
|
||||
|
||||
- Added ntfs_lookup().
|
||||
- Added default upcase generation and handling.
|
||||
- Added compile options to be shown on module init.
|
||||
- Many bug fixes that were "hidden" before.
|
||||
- Update to latest kernel.
|
||||
- Added ntfs_readdir().
|
||||
- Added file operations for mmap(), read(), open() and llseek(). We just
|
||||
use the generic ones. The whole point of going through implementing
|
||||
readpage() methods and where possible get_block() call backs is that
|
||||
this allows us to make use of the generic high level methods provided
|
||||
by the kernel.
|
||||
|
||||
The driver is now actually useful! Yey. (-: It undoubtedly has got bugs
|
||||
though and it doesn't implement accesssing compressed files yet. Also,
|
||||
accessing files with attribute list attributes is not implemented yet
|
||||
either. But for small or simple file systems it should work and allow
|
||||
you to list directories, use stat on directory entries and the file
|
||||
system, open, read, mmap and llseek around in files. A big mile stone
|
||||
has been reached!
|
||||
|
||||
tng-0.0.0 - Initial version tag.
|
||||
|
||||
Initial driver implementation. The driver can mount and umount simple
|
||||
NTFS file systems (i.e. ones without attribute lists in the system
|
||||
files). If the mount fails there might be problems in the error handling
|
||||
code paths, so be warned. Otherwise it seems to be loading the system
|
||||
files nicely and the mft record read mapping/unmapping seems to be
|
||||
working nicely, too. Proof of inode metadata in the page cache and non-
|
||||
resident file unnamed stream data in the page cache concepts is thus
|
||||
complete.
|
||||
|
16
reactos/drivers/fs/ntfs/linux-ntfs/Makefile
Normal file
16
reactos/drivers/fs/ntfs/linux-ntfs/Makefile
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Rules for making the NTFS driver.
|
||||
|
||||
obj-$(CONFIG_NTFS_FS) += ntfs.o
|
||||
|
||||
ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
|
||||
mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
|
||||
|
||||
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.5\"
|
||||
|
||||
ifeq ($(CONFIG_NTFS_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_NTFS_RW),y)
|
||||
EXTRA_CFLAGS += -DNTFS_RW
|
||||
endif
|
1794
reactos/drivers/fs/ntfs/linux-ntfs/aops.c
Normal file
1794
reactos/drivers/fs/ntfs/linux-ntfs/aops.c
Normal file
File diff suppressed because it is too large
Load diff
1721
reactos/drivers/fs/ntfs/linux-ntfs/attrib.c
Normal file
1721
reactos/drivers/fs/ntfs/linux-ntfs/attrib.c
Normal file
File diff suppressed because it is too large
Load diff
106
reactos/drivers/fs/ntfs/linux-ntfs/attrib.h
Normal file
106
reactos/drivers/fs/ntfs/linux-ntfs/attrib.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* attrib.h - Defines for attribute handling in NTFS Linux kernel driver.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2003 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_ATTRIB_H
|
||||
#define _LINUX_NTFS_ATTRIB_H
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "endian.h"
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
|
||||
static inline void init_run_list(run_list *rl)
|
||||
{
|
||||
rl->rl = NULL;
|
||||
init_rwsem(&rl->lock);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||
LCN_RL_NOT_MAPPED = -2,
|
||||
LCN_ENOENT = -3,
|
||||
LCN_EINVAL = -4,
|
||||
} LCN_SPECIAL_VALUES;
|
||||
|
||||
/**
|
||||
* attr_search_context - used in attribute search functions
|
||||
* @mrec: buffer containing mft record to search
|
||||
* @attr: attribute record in @mrec where to begin/continue search
|
||||
* @is_first: if true lookup_attr() begins search with @attr, else after @attr
|
||||
*
|
||||
* Structure must be initialized to zero before the first call to one of the
|
||||
* attribute search functions. Initialize @mrec to point to the mft record to
|
||||
* search, and @attr to point to the first attribute within @mrec (not necessary
|
||||
* if calling the _first() functions), and set @is_first to TRUE (not necessary
|
||||
* if calling the _first() functions).
|
||||
*
|
||||
* If @is_first is TRUE, the search begins with @attr. If @is_first is FALSE,
|
||||
* the search begins after @attr. This is so that, after the first call to one
|
||||
* of the search attribute functions, we can call the function again, without
|
||||
* any modification of the search context, to automagically get the next
|
||||
* matching attribute.
|
||||
*/
|
||||
typedef struct {
|
||||
MFT_RECORD *mrec;
|
||||
ATTR_RECORD *attr;
|
||||
BOOL is_first;
|
||||
ntfs_inode *ntfs_ino;
|
||||
ATTR_LIST_ENTRY *al_entry;
|
||||
ntfs_inode *base_ntfs_ino;
|
||||
MFT_RECORD *base_mrec;
|
||||
ATTR_RECORD *base_attr;
|
||||
} attr_search_context;
|
||||
|
||||
extern run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
|
||||
const ATTR_RECORD *attr, run_list_element *old_rl);
|
||||
|
||||
extern int map_run_list(ntfs_inode *ni, VCN vcn);
|
||||
|
||||
extern LCN vcn_to_lcn(const run_list_element *rl, const VCN vcn);
|
||||
|
||||
extern BOOL find_attr(const ATTR_TYPES type, const uchar_t *name,
|
||||
const u32 name_len, const IGNORE_CASE_BOOL ic, const u8 *val,
|
||||
const u32 val_len, attr_search_context *ctx);
|
||||
|
||||
BOOL lookup_attr(const ATTR_TYPES type, const uchar_t *name, const u32 name_len,
|
||||
const IGNORE_CASE_BOOL ic, const VCN lowest_vcn, const u8 *val,
|
||||
const u32 val_len, attr_search_context *ctx);
|
||||
|
||||
extern int load_attribute_list(ntfs_volume *vol, run_list *rl, u8 *al_start,
|
||||
const s64 size, const s64 initialized_size);
|
||||
|
||||
static inline s64 attribute_value_length(const ATTR_RECORD *a)
|
||||
{
|
||||
if (!a->non_resident)
|
||||
return (s64)le32_to_cpu(a->data.resident.value_length);
|
||||
return sle64_to_cpu(a->data.non_resident.data_size);
|
||||
}
|
||||
|
||||
extern void reinit_attr_search_ctx(attr_search_context *ctx);
|
||||
extern attr_search_context *get_attr_search_ctx(ntfs_inode *ni,
|
||||
MFT_RECORD *mrec);
|
||||
extern void put_attr_search_ctx(attr_search_context *ctx);
|
||||
|
||||
#endif /* _LINUX_NTFS_ATTRIB_H */
|
||||
|
945
reactos/drivers/fs/ntfs/linux-ntfs/compress.c
Normal file
945
reactos/drivers/fs/ntfs/linux-ntfs/compress.c
Normal file
|
@ -0,0 +1,945 @@
|
|||
/**
|
||||
* compress.c - NTFS kernel compressed attributes handling.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2003 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
#include "ntfs.h"
|
||||
|
||||
/**
|
||||
* ntfs_compression_constants - enum of constants used in the compression code
|
||||
*/
|
||||
typedef enum {
|
||||
/* Token types and access mask. */
|
||||
NTFS_SYMBOL_TOKEN = 0,
|
||||
NTFS_PHRASE_TOKEN = 1,
|
||||
NTFS_TOKEN_MASK = 1,
|
||||
|
||||
/* Compression sub-block constants. */
|
||||
NTFS_SB_SIZE_MASK = 0x0fff,
|
||||
NTFS_SB_SIZE = 0x1000,
|
||||
NTFS_SB_IS_COMPRESSED = 0x8000,
|
||||
|
||||
/*
|
||||
* The maximum compression block size is by definition 16 * the cluster
|
||||
* size, with the maximum supported cluster size being 4kiB. Thus the
|
||||
* maximum compression buffer size is 64kiB, so we use this when
|
||||
* initializing the compression buffer.
|
||||
*/
|
||||
NTFS_MAX_CB_SIZE = 64 * 1024,
|
||||
} ntfs_compression_constants;
|
||||
|
||||
/**
|
||||
* ntfs_compression_buffer - one buffer for the decompression engine
|
||||
*/
|
||||
static u8 *ntfs_compression_buffer = NULL;
|
||||
|
||||
/**
|
||||
* ntfs_cb_lock - spinlock which protects ntfs_compression_buffer
|
||||
*/
|
||||
static spinlock_t ntfs_cb_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
/**
|
||||
* allocate_compression_buffers - allocate the decompression buffers
|
||||
*
|
||||
* Caller has to hold the ntfs_lock semaphore.
|
||||
*
|
||||
* Return 0 on success or -ENOMEM if the allocations failed.
|
||||
*/
|
||||
int allocate_compression_buffers(void)
|
||||
{
|
||||
BUG_ON(ntfs_compression_buffer);
|
||||
|
||||
ntfs_compression_buffer = vmalloc(NTFS_MAX_CB_SIZE);
|
||||
if (!ntfs_compression_buffer)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* free_compression_buffers - free the decompression buffers
|
||||
*
|
||||
* Caller has to hold the ntfs_lock semaphore.
|
||||
*/
|
||||
void free_compression_buffers(void)
|
||||
{
|
||||
BUG_ON(!ntfs_compression_buffer);
|
||||
vfree(ntfs_compression_buffer);
|
||||
ntfs_compression_buffer = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* zero_partial_compressed_page - zero out of bounds compressed page region
|
||||
*/
|
||||
static void zero_partial_compressed_page(ntfs_inode *ni, struct page *page)
|
||||
{
|
||||
u8 *kp = page_address(page);
|
||||
unsigned int kp_ofs;
|
||||
|
||||
ntfs_debug("Zeroing page region outside initialized size.");
|
||||
if (((s64)page->index << PAGE_CACHE_SHIFT) >= ni->initialized_size) {
|
||||
/*
|
||||
* FIXME: Using clear_page() will become wrong when we get
|
||||
* PAGE_CACHE_SIZE != PAGE_SIZE but for now there is no problem.
|
||||
*/
|
||||
clear_page(kp);
|
||||
return;
|
||||
}
|
||||
kp_ofs = ni->initialized_size & ~PAGE_CACHE_MASK;
|
||||
memset(kp + kp_ofs, 0, PAGE_CACHE_SIZE - kp_ofs);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_bounds_compressed_page - test for&handle out of bounds compressed page
|
||||
*/
|
||||
static inline void handle_bounds_compressed_page(ntfs_inode *ni,
|
||||
struct page *page)
|
||||
{
|
||||
if ((page->index >= (ni->initialized_size >> PAGE_CACHE_SHIFT)) &&
|
||||
(ni->initialized_size < VFS_I(ni)->i_size))
|
||||
zero_partial_compressed_page(ni, page);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_decompress - decompress a compression block into an array of pages
|
||||
* @dest_pages: destination array of pages
|
||||
* @dest_index: current index into @dest_pages (IN/OUT)
|
||||
* @dest_ofs: current offset within @dest_pages[@dest_index] (IN/OUT)
|
||||
* @dest_max_index: maximum index into @dest_pages (IN)
|
||||
* @dest_max_ofs: maximum offset within @dest_pages[@dest_max_index] (IN)
|
||||
* @xpage: the target page (-1 if none) (IN)
|
||||
* @xpage_done: set to 1 if xpage was completed successfully (IN/OUT)
|
||||
* @cb_start: compression block to decompress (IN)
|
||||
* @cb_size: size of compression block @cb_start in bytes (IN)
|
||||
*
|
||||
* The caller must have disabled preemption. ntfs_decompress() reenables it when
|
||||
* the critical section is finished.
|
||||
*
|
||||
* This decompresses the compression block @cb_start into the array of
|
||||
* destination pages @dest_pages starting at index @dest_index into @dest_pages
|
||||
* and at offset @dest_pos into the page @dest_pages[@dest_index].
|
||||
*
|
||||
* When the page @dest_pages[@xpage] is completed, @xpage_done is set to 1.
|
||||
* If xpage is -1 or @xpage has not been completed, @xpage_done is not modified.
|
||||
*
|
||||
* @cb_start is a pointer to the compression block which needs decompressing
|
||||
* and @cb_size is the size of @cb_start in bytes (8-64kiB).
|
||||
*
|
||||
* Return 0 if success or -EOVERFLOW on error in the compressed stream.
|
||||
* @xpage_done indicates whether the target page (@dest_pages[@xpage]) was
|
||||
* completed during the decompression of the compression block (@cb_start).
|
||||
*
|
||||
* Warning: This function *REQUIRES* PAGE_CACHE_SIZE >= 4096 or it will blow up
|
||||
* unpredicatbly! You have been warned!
|
||||
*
|
||||
* Note to hackers: This function may not sleep until it has finished accessing
|
||||
* the compression block @cb_start as it is a per-CPU buffer.
|
||||
*/
|
||||
static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
|
||||
int *dest_ofs, const int dest_max_index, const int dest_max_ofs,
|
||||
const int xpage, char *xpage_done, u8 *const cb_start,
|
||||
const u32 cb_size)
|
||||
{
|
||||
/*
|
||||
* Pointers into the compressed data, i.e. the compression block (cb),
|
||||
* and the therein contained sub-blocks (sb).
|
||||
*/
|
||||
u8 *cb_end = cb_start + cb_size; /* End of cb. */
|
||||
u8 *cb = cb_start; /* Current position in cb. */
|
||||
u8 *cb_sb_start = cb; /* Beginning of the current sb in the cb. */
|
||||
u8 *cb_sb_end; /* End of current sb / beginning of next sb. */
|
||||
|
||||
/* Variables for uncompressed data / destination. */
|
||||
struct page *dp; /* Current destination page being worked on. */
|
||||
u8 *dp_addr; /* Current pointer into dp. */
|
||||
u8 *dp_sb_start; /* Start of current sub-block in dp. */
|
||||
u8 *dp_sb_end; /* End of current sb in dp (dp_sb_start +
|
||||
NTFS_SB_SIZE). */
|
||||
u16 do_sb_start; /* @dest_ofs when starting this sub-block. */
|
||||
u16 do_sb_end; /* @dest_ofs of end of this sb (do_sb_start +
|
||||
NTFS_SB_SIZE). */
|
||||
|
||||
/* Variables for tag and token parsing. */
|
||||
u8 tag; /* Current tag. */
|
||||
int token; /* Loop counter for the eight tokens in tag. */
|
||||
|
||||
/* Need this because we can't sleep, so need two stages. */
|
||||
int completed_pages[dest_max_index - *dest_index + 1];
|
||||
int nr_completed_pages = 0;
|
||||
|
||||
/* Default error code. */
|
||||
int err = -EOVERFLOW;
|
||||
|
||||
ntfs_debug("Entering, cb_size = 0x%x.", cb_size);
|
||||
do_next_sb:
|
||||
ntfs_debug("Beginning sub-block at offset = 0x%x in the cb.",
|
||||
cb - cb_start);
|
||||
|
||||
/* Have we reached the end of the compression block? */
|
||||
if (cb == cb_end || !le16_to_cpup((u16*)cb)) {
|
||||
int i;
|
||||
|
||||
ntfs_debug("Completed. Returning success (0).");
|
||||
err = 0;
|
||||
return_error:
|
||||
/* We can sleep from now on, so we drop lock. */
|
||||
spin_unlock(&ntfs_cb_lock);
|
||||
/* Second stage: finalize completed pages. */
|
||||
if (nr_completed_pages > 0) {
|
||||
struct page *page = dest_pages[completed_pages[0]];
|
||||
ntfs_inode *ni = NTFS_I(page->mapping->host);
|
||||
|
||||
for (i = 0; i < nr_completed_pages; i++) {
|
||||
int di = completed_pages[i];
|
||||
|
||||
dp = dest_pages[di];
|
||||
/*
|
||||
* If we are outside the initialized size, zero
|
||||
* the out of bounds page range.
|
||||
*/
|
||||
handle_bounds_compressed_page(ni, dp);
|
||||
flush_dcache_page(dp);
|
||||
kunmap(dp);
|
||||
SetPageUptodate(dp);
|
||||
unlock_page(dp);
|
||||
if (di == xpage)
|
||||
*xpage_done = 1;
|
||||
else
|
||||
page_cache_release(dp);
|
||||
dest_pages[di] = NULL;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Setup offsets for the current sub-block destination. */
|
||||
do_sb_start = *dest_ofs;
|
||||
do_sb_end = do_sb_start + NTFS_SB_SIZE;
|
||||
|
||||
/* Check that we are still within allowed boundaries. */
|
||||
if (*dest_index == dest_max_index && do_sb_end > dest_max_ofs)
|
||||
goto return_overflow;
|
||||
|
||||
/* Does the minimum size of a compressed sb overflow valid range? */
|
||||
if (cb + 6 > cb_end)
|
||||
goto return_overflow;
|
||||
|
||||
/* Setup the current sub-block source pointers and validate range. */
|
||||
cb_sb_start = cb;
|
||||
cb_sb_end = cb_sb_start + (le16_to_cpup((u16*)cb) & NTFS_SB_SIZE_MASK)
|
||||
+ 3;
|
||||
if (cb_sb_end > cb_end)
|
||||
goto return_overflow;
|
||||
|
||||
/* Get the current destination page. */
|
||||
dp = dest_pages[*dest_index];
|
||||
if (!dp) {
|
||||
/* No page present. Skip decompression of this sub-block. */
|
||||
cb = cb_sb_end;
|
||||
|
||||
/* Advance destination position to next sub-block. */
|
||||
*dest_ofs = (*dest_ofs + NTFS_SB_SIZE) & ~PAGE_CACHE_MASK;
|
||||
if (!*dest_ofs && (++*dest_index > dest_max_index))
|
||||
goto return_overflow;
|
||||
goto do_next_sb;
|
||||
}
|
||||
|
||||
/* We have a valid destination page. Setup the destination pointers. */
|
||||
dp_addr = (u8*)page_address(dp) + do_sb_start;
|
||||
|
||||
/* Now, we are ready to process the current sub-block (sb). */
|
||||
if (!(le16_to_cpup((u16*)cb) & NTFS_SB_IS_COMPRESSED)) {
|
||||
ntfs_debug("Found uncompressed sub-block.");
|
||||
/* This sb is not compressed, just copy it into destination. */
|
||||
|
||||
/* Advance source position to first data byte. */
|
||||
cb += 2;
|
||||
|
||||
/* An uncompressed sb must be full size. */
|
||||
if (cb_sb_end - cb != NTFS_SB_SIZE)
|
||||
goto return_overflow;
|
||||
|
||||
/* Copy the block and advance the source position. */
|
||||
memcpy(dp_addr, cb, NTFS_SB_SIZE);
|
||||
cb += NTFS_SB_SIZE;
|
||||
|
||||
/* Advance destination position to next sub-block. */
|
||||
*dest_ofs += NTFS_SB_SIZE;
|
||||
if (!(*dest_ofs &= ~PAGE_CACHE_MASK)) {
|
||||
finalize_page:
|
||||
/*
|
||||
* First stage: add current page index to array of
|
||||
* completed pages.
|
||||
*/
|
||||
completed_pages[nr_completed_pages++] = *dest_index;
|
||||
if (++*dest_index > dest_max_index)
|
||||
goto return_overflow;
|
||||
}
|
||||
goto do_next_sb;
|
||||
}
|
||||
ntfs_debug("Found compressed sub-block.");
|
||||
/* This sb is compressed, decompress it into destination. */
|
||||
|
||||
/* Setup destination pointers. */
|
||||
dp_sb_start = dp_addr;
|
||||
dp_sb_end = dp_sb_start + NTFS_SB_SIZE;
|
||||
|
||||
/* Forward to the first tag in the sub-block. */
|
||||
cb += 2;
|
||||
do_next_tag:
|
||||
if (cb == cb_sb_end) {
|
||||
/* Check if the decompressed sub-block was not full-length. */
|
||||
if (dp_addr < dp_sb_end) {
|
||||
int nr_bytes = do_sb_end - *dest_ofs;
|
||||
|
||||
ntfs_debug("Filling incomplete sub-block with "
|
||||
"zeroes.");
|
||||
/* Zero remainder and update destination position. */
|
||||
memset(dp_addr, 0, nr_bytes);
|
||||
*dest_ofs += nr_bytes;
|
||||
}
|
||||
/* We have finished the current sub-block. */
|
||||
if (!(*dest_ofs &= ~PAGE_CACHE_MASK))
|
||||
goto finalize_page;
|
||||
goto do_next_sb;
|
||||
}
|
||||
|
||||
/* Check we are still in range. */
|
||||
if (cb > cb_sb_end || dp_addr > dp_sb_end)
|
||||
goto return_overflow;
|
||||
|
||||
/* Get the next tag and advance to first token. */
|
||||
tag = *cb++;
|
||||
|
||||
/* Parse the eight tokens described by the tag. */
|
||||
for (token = 0; token < 8; token++, tag >>= 1) {
|
||||
u16 lg, pt, length, max_non_overlap;
|
||||
register u16 i;
|
||||
u8 *dp_back_addr;
|
||||
|
||||
/* Check if we are done / still in range. */
|
||||
if (cb >= cb_sb_end || dp_addr > dp_sb_end)
|
||||
break;
|
||||
|
||||
/* Determine token type and parse appropriately.*/
|
||||
if ((tag & NTFS_TOKEN_MASK) == NTFS_SYMBOL_TOKEN) {
|
||||
/*
|
||||
* We have a symbol token, copy the symbol across, and
|
||||
* advance the source and destination positions.
|
||||
*/
|
||||
*dp_addr++ = *cb++;
|
||||
++*dest_ofs;
|
||||
|
||||
/* Continue with the next token. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a phrase token. Make sure it is not the first tag in
|
||||
* the sb as this is illegal and would confuse the code below.
|
||||
*/
|
||||
if (dp_addr == dp_sb_start)
|
||||
goto return_overflow;
|
||||
|
||||
/*
|
||||
* Determine the number of bytes to go back (p) and the number
|
||||
* of bytes to copy (l). We use an optimized algorithm in which
|
||||
* we first calculate log2(current destination position in sb),
|
||||
* which allows determination of l and p in O(1) rather than
|
||||
* O(n). We just need an arch-optimized log2() function now.
|
||||
*/
|
||||
lg = 0;
|
||||
for (i = *dest_ofs - do_sb_start - 1; i >= 0x10; i >>= 1)
|
||||
lg++;
|
||||
|
||||
/* Get the phrase token into i. */
|
||||
pt = le16_to_cpup((u16*)cb);
|
||||
|
||||
/*
|
||||
* Calculate starting position of the byte sequence in
|
||||
* the destination using the fact that p = (pt >> (12 - lg)) + 1
|
||||
* and make sure we don't go too far back.
|
||||
*/
|
||||
dp_back_addr = dp_addr - (pt >> (12 - lg)) - 1;
|
||||
if (dp_back_addr < dp_sb_start)
|
||||
goto return_overflow;
|
||||
|
||||
/* Now calculate the length of the byte sequence. */
|
||||
length = (pt & (0xfff >> lg)) + 3;
|
||||
|
||||
/* Advance destination position and verify it is in range. */
|
||||
*dest_ofs += length;
|
||||
if (*dest_ofs > do_sb_end)
|
||||
goto return_overflow;
|
||||
|
||||
/* The number of non-overlapping bytes. */
|
||||
max_non_overlap = dp_addr - dp_back_addr;
|
||||
|
||||
if (length <= max_non_overlap) {
|
||||
/* The byte sequence doesn't overlap, just copy it. */
|
||||
memcpy(dp_addr, dp_back_addr, length);
|
||||
|
||||
/* Advance destination pointer. */
|
||||
dp_addr += length;
|
||||
} else {
|
||||
/*
|
||||
* The byte sequence does overlap, copy non-overlapping
|
||||
* part and then do a slow byte by byte copy for the
|
||||
* overlapping part. Also, advance the destination
|
||||
* pointer.
|
||||
*/
|
||||
memcpy(dp_addr, dp_back_addr, max_non_overlap);
|
||||
dp_addr += max_non_overlap;
|
||||
dp_back_addr += max_non_overlap;
|
||||
length -= max_non_overlap;
|
||||
while (length--)
|
||||
*dp_addr++ = *dp_back_addr++;
|
||||
}
|
||||
|
||||
/* Advance source position and continue with the next token. */
|
||||
cb += 2;
|
||||
}
|
||||
|
||||
/* No tokens left in the current tag. Continue with the next tag. */
|
||||
goto do_next_tag;
|
||||
|
||||
return_overflow:
|
||||
ntfs_error(NULL, "Failed. Returning -EOVERFLOW.\n");
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_read_compressed_block - read a compressed block into the page cache
|
||||
* @page: locked page in the compression block(s) we need to read
|
||||
*
|
||||
* When we are called the page has already been verified to be locked and the
|
||||
* attribute is known to be non-resident, not encrypted, but compressed.
|
||||
*
|
||||
* 1. Determine which compression block(s) @page is in.
|
||||
* 2. Get hold of all pages corresponding to this/these compression block(s).
|
||||
* 3. Read the (first) compression block.
|
||||
* 4. Decompress it into the corresponding pages.
|
||||
* 5. Throw the compressed data away and proceed to 3. for the next compression
|
||||
* block or return success if no more compression blocks left.
|
||||
*
|
||||
* Warning: We have to be careful what we do about existing pages. They might
|
||||
* have been written to so that we would lose data if we were to just overwrite
|
||||
* them with the out-of-date uncompressed data.
|
||||
*
|
||||
* FIXME: For PAGE_CACHE_SIZE > cb_size we are not doing the Right Thing(TM) at
|
||||
* the end of the file I think. We need to detect this case and zero the out
|
||||
* of bounds remainder of the page in question and mark it as handled. At the
|
||||
* moment we would just return -EIO on such a page. This bug will only become
|
||||
* apparent if pages are above 8kiB and the NTFS volume only uses 512 byte
|
||||
* clusters so is probably not going to be seen by anyone. Still this should
|
||||
* be fixed. (AIA)
|
||||
*
|
||||
* FIXME: Again for PAGE_CACHE_SIZE > cb_size we are screwing up both in
|
||||
* handling sparse and compressed cbs. (AIA)
|
||||
*
|
||||
* FIXME: At the moment we don't do any zeroing out in the case that
|
||||
* initialized_size is less than data_size. This should be safe because of the
|
||||
* nature of the compression algorithm used. Just in case we check and output
|
||||
* an error message in read inode if the two sizes are not equal for a
|
||||
* compressed file. (AIA)
|
||||
*/
|
||||
int ntfs_read_compressed_block(struct page *page)
|
||||
{
|
||||
struct address_space *mapping = page->mapping;
|
||||
ntfs_inode *ni = NTFS_I(mapping->host);
|
||||
ntfs_volume *vol = ni->vol;
|
||||
struct super_block *sb = vol->sb;
|
||||
run_list_element *rl;
|
||||
unsigned long block_size = sb->s_blocksize;
|
||||
unsigned char block_size_bits = sb->s_blocksize_bits;
|
||||
u8 *cb, *cb_pos, *cb_end;
|
||||
struct buffer_head **bhs;
|
||||
unsigned long offset, index = page->index;
|
||||
u32 cb_size = ni->itype.compressed.block_size;
|
||||
u64 cb_size_mask = cb_size - 1UL;
|
||||
VCN vcn;
|
||||
LCN lcn;
|
||||
/* The first wanted vcn (minimum alignment is PAGE_CACHE_SIZE). */
|
||||
VCN start_vcn = (((s64)index << PAGE_CACHE_SHIFT) & ~cb_size_mask) >>
|
||||
vol->cluster_size_bits;
|
||||
/*
|
||||
* The first vcn after the last wanted vcn (minumum alignment is again
|
||||
* PAGE_CACHE_SIZE.
|
||||
*/
|
||||
VCN end_vcn = ((((s64)(index + 1UL) << PAGE_CACHE_SHIFT) + cb_size - 1)
|
||||
& ~cb_size_mask) >> vol->cluster_size_bits;
|
||||
/* Number of compression blocks (cbs) in the wanted vcn range. */
|
||||
unsigned int nr_cbs = (end_vcn - start_vcn) << vol->cluster_size_bits
|
||||
>> ni->itype.compressed.block_size_bits;
|
||||
/*
|
||||
* Number of pages required to store the uncompressed data from all
|
||||
* compression blocks (cbs) overlapping @page. Due to alignment
|
||||
* guarantees of start_vcn and end_vcn, no need to round up here.
|
||||
*/
|
||||
unsigned int nr_pages = (end_vcn - start_vcn) <<
|
||||
vol->cluster_size_bits >> PAGE_CACHE_SHIFT;
|
||||
unsigned int xpage, max_page, cur_page, cur_ofs, i;
|
||||
unsigned int cb_clusters, cb_max_ofs;
|
||||
int block, max_block, cb_max_page, bhs_size, nr_bhs, err = 0;
|
||||
struct page **pages;
|
||||
unsigned char xpage_done = 0;
|
||||
|
||||
ntfs_debug("Entering, page->index = 0x%lx, cb_size = 0x%x, nr_pages = "
|
||||
"%i.", index, cb_size, nr_pages);
|
||||
/*
|
||||
* Bad things happen if we get here for anything that is not an
|
||||
* unnamed $DATA attribute.
|
||||
*/
|
||||
BUG_ON(ni->type != AT_DATA);
|
||||
BUG_ON(ni->name_len);
|
||||
|
||||
pages = kmalloc(nr_pages * sizeof(struct page *), GFP_NOFS);
|
||||
|
||||
/* Allocate memory to store the buffer heads we need. */
|
||||
bhs_size = cb_size / block_size * sizeof(struct buffer_head *);
|
||||
bhs = kmalloc(bhs_size, GFP_NOFS);
|
||||
|
||||
if (unlikely(!pages || !bhs)) {
|
||||
kfree(bhs);
|
||||
kfree(pages);
|
||||
SetPageError(page);
|
||||
unlock_page(page);
|
||||
ntfs_error(vol->sb, "Failed to allocate internal buffers.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have already been given one page, this is the one we must do.
|
||||
* Once again, the alignment guarantees keep it simple.
|
||||
*/
|
||||
offset = start_vcn << vol->cluster_size_bits >> PAGE_CACHE_SHIFT;
|
||||
xpage = index - offset;
|
||||
pages[xpage] = page;
|
||||
/*
|
||||
* The remaining pages need to be allocated and inserted into the page
|
||||
* cache, alignment guarantees keep all the below much simpler. (-8
|
||||
*/
|
||||
max_page = ((VFS_I(ni)->i_size + PAGE_CACHE_SIZE - 1) >>
|
||||
PAGE_CACHE_SHIFT) - offset;
|
||||
if (nr_pages < max_page)
|
||||
max_page = nr_pages;
|
||||
for (i = 0; i < max_page; i++, offset++) {
|
||||
if (i != xpage)
|
||||
pages[i] = grab_cache_page_nowait(mapping, offset);
|
||||
page = pages[i];
|
||||
if (page) {
|
||||
/*
|
||||
* We only (re)read the page if it isn't already read
|
||||
* in and/or dirty or we would be losing data or at
|
||||
* least wasting our time.
|
||||
*/
|
||||
if (!PageDirty(page) && (!PageUptodate(page) ||
|
||||
PageError(page))) {
|
||||
ClearPageError(page);
|
||||
kmap(page);
|
||||
continue;
|
||||
}
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
pages[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We have the run list, and all the destination pages we need to fill.
|
||||
* Now read the first compression block.
|
||||
*/
|
||||
cur_page = 0;
|
||||
cur_ofs = 0;
|
||||
cb_clusters = ni->itype.compressed.block_clusters;
|
||||
do_next_cb:
|
||||
nr_cbs--;
|
||||
nr_bhs = 0;
|
||||
|
||||
/* Read all cb buffer heads one cluster at a time. */
|
||||
rl = NULL;
|
||||
for (vcn = start_vcn, start_vcn += cb_clusters; vcn < start_vcn;
|
||||
vcn++) {
|
||||
BOOL is_retry = FALSE;
|
||||
|
||||
if (!rl) {
|
||||
lock_retry_remap:
|
||||
down_read(&ni->run_list.lock);
|
||||
rl = ni->run_list.rl;
|
||||
}
|
||||
if (likely(rl != NULL)) {
|
||||
/* Seek to element containing target vcn. */
|
||||
while (rl->length && rl[1].vcn <= vcn)
|
||||
rl++;
|
||||
lcn = vcn_to_lcn(rl, vcn);
|
||||
} else
|
||||
lcn = (LCN)LCN_RL_NOT_MAPPED;
|
||||
ntfs_debug("Reading vcn = 0x%Lx, lcn = 0x%Lx.",
|
||||
(long long)vcn, (long long)lcn);
|
||||
if (lcn < 0) {
|
||||
/*
|
||||
* When we reach the first sparse cluster we have
|
||||
* finished with the cb.
|
||||
*/
|
||||
if (lcn == LCN_HOLE)
|
||||
break;
|
||||
if (is_retry || lcn != LCN_RL_NOT_MAPPED)
|
||||
goto rl_err;
|
||||
is_retry = TRUE;
|
||||
/*
|
||||
* Attempt to map run list, dropping lock for the
|
||||
* duration.
|
||||
*/
|
||||
up_read(&ni->run_list.lock);
|
||||
if (!map_run_list(ni, vcn))
|
||||
goto lock_retry_remap;
|
||||
goto map_rl_err;
|
||||
}
|
||||
block = lcn << vol->cluster_size_bits >> block_size_bits;
|
||||
/* Read the lcn from device in chunks of block_size bytes. */
|
||||
max_block = block + (vol->cluster_size >> block_size_bits);
|
||||
do {
|
||||
ntfs_debug("block = 0x%x.", block);
|
||||
if (unlikely(!(bhs[nr_bhs] = sb_getblk(sb, block))))
|
||||
goto getblk_err;
|
||||
nr_bhs++;
|
||||
} while (++block < max_block);
|
||||
}
|
||||
|
||||
/* Release the lock if we took it. */
|
||||
if (rl)
|
||||
up_read(&ni->run_list.lock);
|
||||
|
||||
/* Setup and initiate io on all buffer heads. */
|
||||
for (i = 0; i < nr_bhs; i++) {
|
||||
struct buffer_head *tbh = bhs[i];
|
||||
|
||||
if (unlikely(test_set_buffer_locked(tbh)))
|
||||
continue;
|
||||
if (unlikely(buffer_uptodate(tbh))) {
|
||||
unlock_buffer(tbh);
|
||||
continue;
|
||||
}
|
||||
atomic_inc(&tbh->b_count);
|
||||
tbh->b_end_io = end_buffer_read_sync;
|
||||
submit_bh(READ, tbh);
|
||||
}
|
||||
|
||||
/* Wait for io completion on all buffer heads. */
|
||||
for (i = 0; i < nr_bhs; i++) {
|
||||
struct buffer_head *tbh = bhs[i];
|
||||
|
||||
if (buffer_uptodate(tbh))
|
||||
continue;
|
||||
wait_on_buffer(tbh);
|
||||
/*
|
||||
* We need an optimization barrier here, otherwise we start
|
||||
* hitting the below fixup code when accessing a loopback
|
||||
* mounted ntfs partition. This indicates either there is a
|
||||
* race condition in the loop driver or, more likely, gcc
|
||||
* overoptimises the code without the barrier and it doesn't
|
||||
* do the Right Thing(TM).
|
||||
*/
|
||||
barrier();
|
||||
if (unlikely(!buffer_uptodate(tbh))) {
|
||||
ntfs_warning(vol->sb, "Buffer is unlocked but not "
|
||||
"uptodate! Unplugging the disk queue "
|
||||
"and rescheduling.");
|
||||
get_bh(tbh);
|
||||
blk_run_queues();
|
||||
schedule();
|
||||
put_bh(tbh);
|
||||
if (unlikely(!buffer_uptodate(tbh)))
|
||||
goto read_err;
|
||||
ntfs_warning(vol->sb, "Buffer is now uptodate. Good.");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the compression buffer. We must not sleep any more
|
||||
* until we are finished with it.
|
||||
*/
|
||||
spin_lock(&ntfs_cb_lock);
|
||||
cb = ntfs_compression_buffer;
|
||||
|
||||
BUG_ON(!cb);
|
||||
|
||||
cb_pos = cb;
|
||||
cb_end = cb + cb_size;
|
||||
|
||||
/* Copy the buffer heads into the contiguous buffer. */
|
||||
for (i = 0; i < nr_bhs; i++) {
|
||||
memcpy(cb_pos, bhs[i]->b_data, block_size);
|
||||
cb_pos += block_size;
|
||||
}
|
||||
|
||||
/* Just a precaution. */
|
||||
if (cb_pos + 2 <= cb + cb_size)
|
||||
*(u16*)cb_pos = 0;
|
||||
|
||||
/* Reset cb_pos back to the beginning. */
|
||||
cb_pos = cb;
|
||||
|
||||
/* We now have both source (if present) and destination. */
|
||||
ntfs_debug("Successfully read the compression block.");
|
||||
|
||||
/* The last page and maximum offset within it for the current cb. */
|
||||
cb_max_page = (cur_page << PAGE_CACHE_SHIFT) + cur_ofs + cb_size;
|
||||
cb_max_ofs = cb_max_page & ~PAGE_CACHE_MASK;
|
||||
cb_max_page >>= PAGE_CACHE_SHIFT;
|
||||
|
||||
/* Catch end of file inside a compression block. */
|
||||
if (cb_max_page > max_page)
|
||||
cb_max_page = max_page;
|
||||
|
||||
if (vcn == start_vcn - cb_clusters) {
|
||||
/* Sparse cb, zero out page range overlapping the cb. */
|
||||
ntfs_debug("Found sparse compression block.");
|
||||
/* We can sleep from now on, so we drop lock. */
|
||||
spin_unlock(&ntfs_cb_lock);
|
||||
if (cb_max_ofs)
|
||||
cb_max_page--;
|
||||
for (; cur_page < cb_max_page; cur_page++) {
|
||||
page = pages[cur_page];
|
||||
if (page) {
|
||||
/*
|
||||
* FIXME: Using clear_page() will become wrong
|
||||
* when we get PAGE_CACHE_SIZE != PAGE_SIZE but
|
||||
* for now there is no problem.
|
||||
*/
|
||||
if (likely(!cur_ofs))
|
||||
clear_page(page_address(page));
|
||||
else
|
||||
memset(page_address(page) + cur_ofs, 0,
|
||||
PAGE_CACHE_SIZE -
|
||||
cur_ofs);
|
||||
flush_dcache_page(page);
|
||||
kunmap(page);
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
if (cur_page == xpage)
|
||||
xpage_done = 1;
|
||||
else
|
||||
page_cache_release(page);
|
||||
pages[cur_page] = NULL;
|
||||
}
|
||||
cb_pos += PAGE_CACHE_SIZE - cur_ofs;
|
||||
cur_ofs = 0;
|
||||
if (cb_pos >= cb_end)
|
||||
break;
|
||||
}
|
||||
/* If we have a partial final page, deal with it now. */
|
||||
if (cb_max_ofs && cb_pos < cb_end) {
|
||||
page = pages[cur_page];
|
||||
if (page)
|
||||
memset(page_address(page) + cur_ofs, 0,
|
||||
cb_max_ofs - cur_ofs);
|
||||
/*
|
||||
* No need to update cb_pos at this stage:
|
||||
* cb_pos += cb_max_ofs - cur_ofs;
|
||||
*/
|
||||
cur_ofs = cb_max_ofs;
|
||||
}
|
||||
} else if (vcn == start_vcn) {
|
||||
/* We can't sleep so we need two stages. */
|
||||
unsigned int cur2_page = cur_page;
|
||||
unsigned int cur_ofs2 = cur_ofs;
|
||||
u8 *cb_pos2 = cb_pos;
|
||||
|
||||
ntfs_debug("Found uncompressed compression block.");
|
||||
/* Uncompressed cb, copy it to the destination pages. */
|
||||
/*
|
||||
* TODO: As a big optimization, we could detect this case
|
||||
* before we read all the pages and use block_read_full_page()
|
||||
* on all full pages instead (we still have to treat partial
|
||||
* pages especially but at least we are getting rid of the
|
||||
* synchronous io for the majority of pages.
|
||||
* Or if we choose not to do the read-ahead/-behind stuff, we
|
||||
* could just return block_read_full_page(pages[xpage]) as long
|
||||
* as PAGE_CACHE_SIZE <= cb_size.
|
||||
*/
|
||||
if (cb_max_ofs)
|
||||
cb_max_page--;
|
||||
/* First stage: copy data into destination pages. */
|
||||
for (; cur_page < cb_max_page; cur_page++) {
|
||||
page = pages[cur_page];
|
||||
if (page)
|
||||
memcpy(page_address(page) + cur_ofs, cb_pos,
|
||||
PAGE_CACHE_SIZE - cur_ofs);
|
||||
cb_pos += PAGE_CACHE_SIZE - cur_ofs;
|
||||
cur_ofs = 0;
|
||||
if (cb_pos >= cb_end)
|
||||
break;
|
||||
}
|
||||
/* If we have a partial final page, deal with it now. */
|
||||
if (cb_max_ofs && cb_pos < cb_end) {
|
||||
page = pages[cur_page];
|
||||
if (page)
|
||||
memcpy(page_address(page) + cur_ofs, cb_pos,
|
||||
cb_max_ofs - cur_ofs);
|
||||
cb_pos += cb_max_ofs - cur_ofs;
|
||||
cur_ofs = cb_max_ofs;
|
||||
}
|
||||
/* We can sleep from now on, so drop lock. */
|
||||
spin_unlock(&ntfs_cb_lock);
|
||||
/* Second stage: finalize pages. */
|
||||
for (; cur2_page < cb_max_page; cur2_page++) {
|
||||
page = pages[cur2_page];
|
||||
if (page) {
|
||||
/*
|
||||
* If we are outside the initialized size, zero
|
||||
* the out of bounds page range.
|
||||
*/
|
||||
handle_bounds_compressed_page(ni, page);
|
||||
flush_dcache_page(page);
|
||||
kunmap(page);
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
if (cur2_page == xpage)
|
||||
xpage_done = 1;
|
||||
else
|
||||
page_cache_release(page);
|
||||
pages[cur2_page] = NULL;
|
||||
}
|
||||
cb_pos2 += PAGE_CACHE_SIZE - cur_ofs2;
|
||||
cur_ofs2 = 0;
|
||||
if (cb_pos2 >= cb_end)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Compressed cb, decompress it into the destination page(s). */
|
||||
unsigned int prev_cur_page = cur_page;
|
||||
|
||||
ntfs_debug("Found compressed compression block.");
|
||||
err = ntfs_decompress(pages, &cur_page, &cur_ofs,
|
||||
cb_max_page, cb_max_ofs, xpage, &xpage_done,
|
||||
cb_pos, cb_size - (cb_pos - cb));
|
||||
/*
|
||||
* We can sleep from now on, lock already dropped by
|
||||
* ntfs_decompress().
|
||||
*/
|
||||
if (err) {
|
||||
ntfs_error(vol->sb, "ntfs_decompress() failed in inode "
|
||||
"0x%lx with error code %i. Skipping "
|
||||
"this compression block.\n",
|
||||
ni->mft_no, -err);
|
||||
/* Release the unfinished pages. */
|
||||
for (; prev_cur_page < cur_page; prev_cur_page++) {
|
||||
page = pages[prev_cur_page];
|
||||
if (page) {
|
||||
if (prev_cur_page == xpage &&
|
||||
!xpage_done)
|
||||
SetPageError(page);
|
||||
flush_dcache_page(page);
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
if (prev_cur_page != xpage)
|
||||
page_cache_release(page);
|
||||
pages[prev_cur_page] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the buffer heads. */
|
||||
for (i = 0; i < nr_bhs; i++)
|
||||
brelse(bhs[i]);
|
||||
|
||||
/* Do we have more work to do? */
|
||||
if (nr_cbs)
|
||||
goto do_next_cb;
|
||||
|
||||
/* We no longer need the list of buffer heads. */
|
||||
kfree(bhs);
|
||||
|
||||
/* Clean up if we have any pages left. Should never happen. */
|
||||
for (cur_page = 0; cur_page < max_page; cur_page++) {
|
||||
page = pages[cur_page];
|
||||
if (page) {
|
||||
ntfs_error(vol->sb, "Still have pages left! "
|
||||
"Terminating them with extreme "
|
||||
"prejudice.");
|
||||
if (cur_page == xpage && !xpage_done)
|
||||
SetPageError(page);
|
||||
flush_dcache_page(page);
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
if (cur_page != xpage)
|
||||
page_cache_release(page);
|
||||
pages[cur_page] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* We no longer need the list of pages. */
|
||||
kfree(pages);
|
||||
|
||||
/* If we have completed the requested page, we return success. */
|
||||
if (likely(xpage_done))
|
||||
return 0;
|
||||
|
||||
ntfs_debug("Failed. Returning error code %s.", err == -EOVERFLOW ?
|
||||
"EOVERFLOW" : (!err ? "EIO" : "unkown error"));
|
||||
return err < 0 ? err : -EIO;
|
||||
|
||||
read_err:
|
||||
ntfs_error(vol->sb, "IO error while reading compressed data.");
|
||||
/* Release the buffer heads. */
|
||||
for (i = 0; i < nr_bhs; i++)
|
||||
brelse(bhs[i]);
|
||||
goto err_out;
|
||||
|
||||
map_rl_err:
|
||||
ntfs_error(vol->sb, "map_run_list() failed. Cannot read compression "
|
||||
"block.");
|
||||
goto err_out;
|
||||
|
||||
rl_err:
|
||||
up_read(&ni->run_list.lock);
|
||||
ntfs_error(vol->sb, "vcn_to_lcn() failed. Cannot read compression "
|
||||
"block.");
|
||||
goto err_out;
|
||||
|
||||
getblk_err:
|
||||
up_read(&ni->run_list.lock);
|
||||
ntfs_error(vol->sb, "getblk() failed. Cannot read compression block.");
|
||||
|
||||
err_out:
|
||||
kfree(bhs);
|
||||
for (i = cur_page; i < max_page; i++) {
|
||||
page = pages[i];
|
||||
if (page) {
|
||||
if (i == xpage && !xpage_done)
|
||||
SetPageError(page);
|
||||
flush_dcache_page(page);
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
if (i != xpage)
|
||||
page_cache_release(page);
|
||||
}
|
||||
}
|
||||
kfree(pages);
|
||||
return -EIO;
|
||||
}
|
||||
|
175
reactos/drivers/fs/ntfs/linux-ntfs/debug.c
Normal file
175
reactos/drivers/fs/ntfs/linux-ntfs/debug.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* debug.c - NTFS kernel debug support. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001,2002 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/*
|
||||
* A static buffer to hold the error string being displayed and a spinlock
|
||||
* to protect concurrent accesses to it.
|
||||
*/
|
||||
static char err_buf[1024];
|
||||
static spinlock_t err_buf_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
/**
|
||||
* __ntfs_warning - output a warning to the syslog
|
||||
* @function: name of function outputting the warning
|
||||
* @sb: super block of mounted ntfs filesystem
|
||||
* @fmt: warning string containing format specifications
|
||||
* @...: a variable number of arguments specified in @fmt
|
||||
*
|
||||
* Outputs a warning to the syslog for the mounted ntfs filesystem described
|
||||
* by @sb.
|
||||
*
|
||||
* @fmt and the corresponding @... is printf style format string containing
|
||||
* the warning string and the corresponding format arguments, respectively.
|
||||
*
|
||||
* @function is the name of the function from which __ntfs_warning is being
|
||||
* called.
|
||||
*
|
||||
* Note, you should be using debug.h::ntfs_warning(@sb, @fmt, @...) instead
|
||||
* as this provides the @function parameter automatically.
|
||||
*/
|
||||
void __ntfs_warning(const char *function, const struct super_block *sb,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int flen = 0;
|
||||
|
||||
if (function)
|
||||
flen = strlen(function);
|
||||
spin_lock(&err_buf_lock);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(err_buf, sizeof(err_buf), fmt, args);
|
||||
va_end(args);
|
||||
if (sb)
|
||||
printk(KERN_ERR "NTFS-fs warning (device %s): %s(): %s\n",
|
||||
sb->s_id, flen ? function : "", err_buf);
|
||||
else
|
||||
printk(KERN_ERR "NTFS-fs warning: %s(): %s\n",
|
||||
flen ? function : "", err_buf);
|
||||
spin_unlock(&err_buf_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* __ntfs_error - output an error to the syslog
|
||||
* @function: name of function outputting the error
|
||||
* @sb: super block of mounted ntfs filesystem
|
||||
* @fmt: error string containing format specifications
|
||||
* @...: a variable number of arguments specified in @fmt
|
||||
*
|
||||
* Outputs an error to the syslog for the mounted ntfs filesystem described
|
||||
* by @sb.
|
||||
*
|
||||
* @fmt and the corresponding @... is printf style format string containing
|
||||
* the error string and the corresponding format arguments, respectively.
|
||||
*
|
||||
* @function is the name of the function from which __ntfs_error is being
|
||||
* called.
|
||||
*
|
||||
* Note, you should be using debug.h::ntfs_error(@sb, @fmt, @...) instead
|
||||
* as this provides the @function parameter automatically.
|
||||
*/
|
||||
void __ntfs_error(const char *function, const struct super_block *sb,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int flen = 0;
|
||||
|
||||
if (function)
|
||||
flen = strlen(function);
|
||||
spin_lock(&err_buf_lock);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(err_buf, sizeof(err_buf), fmt, args);
|
||||
va_end(args);
|
||||
if (sb)
|
||||
printk(KERN_ERR "NTFS-fs error (device %s): %s(): %s\n",
|
||||
sb->s_id, flen ? function : "", err_buf);
|
||||
else
|
||||
printk(KERN_ERR "NTFS-fs error: %s(): %s\n",
|
||||
flen ? function : "", err_buf);
|
||||
spin_unlock(&err_buf_lock);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* If 1, output debug messages, and if 0, don't. */
|
||||
int debug_msgs = 0;
|
||||
|
||||
void __ntfs_debug (const char *file, int line, const char *function,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int flen = 0;
|
||||
|
||||
if (!debug_msgs)
|
||||
return;
|
||||
if (function)
|
||||
flen = strlen(function);
|
||||
spin_lock(&err_buf_lock);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(err_buf, sizeof(err_buf), fmt, args);
|
||||
va_end(args);
|
||||
printk(KERN_DEBUG "NTFS-fs DEBUG (%s, %d): %s: %s\n",
|
||||
file, line, flen ? function : "", err_buf);
|
||||
spin_unlock(&err_buf_lock);
|
||||
}
|
||||
|
||||
/* Dump a run list. Caller has to provide synchronisation for @rl. */
|
||||
void ntfs_debug_dump_runlist(const run_list_element *rl)
|
||||
{
|
||||
int i;
|
||||
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
||||
"LCN_ENOENT ", "LCN_EINVAL ",
|
||||
"LCN_unknown " };
|
||||
|
||||
if (!debug_msgs)
|
||||
return;
|
||||
printk(KERN_DEBUG "NTFS-fs DEBUG: Dumping run list (values "
|
||||
"in hex):\n");
|
||||
if (!rl) {
|
||||
printk(KERN_DEBUG "Run list not present.\n");
|
||||
return;
|
||||
}
|
||||
printk(KERN_DEBUG "VCN LCN Run length\n");
|
||||
for (i = 0; ; i++) {
|
||||
LCN lcn = (rl + i)->lcn;
|
||||
|
||||
if (lcn < (LCN)0) {
|
||||
int index = -lcn - 1;
|
||||
|
||||
if (index > -LCN_EINVAL - 1)
|
||||
index = 4;
|
||||
printk(KERN_DEBUG "%-16Lx %s %-16Lx%s\n",
|
||||
(rl + i)->vcn, lcn_str[index],
|
||||
(rl + i)->length, (rl + i)->length ?
|
||||
"" : " (run list end)");
|
||||
} else
|
||||
printk(KERN_DEBUG "%-16Lx %-16Lx %-16Lx%s\n",
|
||||
(rl + i)->vcn, (rl + i)->lcn,
|
||||
(rl + i)->length, (rl + i)->length ?
|
||||
"" : " (run list end)");
|
||||
if (!(rl + i)->length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
72
reactos/drivers/fs/ntfs/linux-ntfs/debug.h
Normal file
72
reactos/drivers/fs/ntfs/linux-ntfs/debug.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* debug.h - NTFS kernel debug support. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001,2002 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_DEBUG_H
|
||||
#define _LINUX_NTFS_DEBUG_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "inode.h"
|
||||
#include "attrib.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
extern int debug_msgs;
|
||||
|
||||
#if 0 /* Fool kernel-doc since it doesn't do macros yet */
|
||||
/**
|
||||
* ntfs_debug - write a debug level message to syslog
|
||||
* @f: a printf format string containing the message
|
||||
* @...: the variables to substitute into @f
|
||||
*
|
||||
* ntfs_debug() writes a DEBUG level message to the syslog but only if the
|
||||
* driver was compiled with -DDEBUG. Otherwise, the call turns into a NOP.
|
||||
*/
|
||||
static void ntfs_debug(const char *f, ...);
|
||||
#endif
|
||||
|
||||
extern void __ntfs_debug (const char *file, int line, const char *function,
|
||||
const char *format, ...) __attribute__ ((format (printf, 4, 5)));
|
||||
#define ntfs_debug(f, a...) \
|
||||
__ntfs_debug(__FILE__, __LINE__, __FUNCTION__, f, ##a)
|
||||
|
||||
extern void ntfs_debug_dump_runlist(const run_list_element *rl);
|
||||
|
||||
#else /* !DEBUG */
|
||||
|
||||
#define ntfs_debug(f, a...) do {} while (0)
|
||||
#define ntfs_debug_dump_runlist(rl) do {} while (0)
|
||||
|
||||
#endif /* !DEBUG */
|
||||
|
||||
extern void __ntfs_warning(const char *function, const struct super_block *sb,
|
||||
const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
#define ntfs_warning(sb, f, a...) __ntfs_warning(__FUNCTION__, sb, f, ##a)
|
||||
|
||||
extern void __ntfs_error(const char *function, const struct super_block *sb,
|
||||
const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
#define ntfs_error(sb, f, a...) __ntfs_error(__FUNCTION__, sb, f, ##a)
|
||||
|
||||
#endif /* _LINUX_NTFS_DEBUG_H */
|
||||
|
1420
reactos/drivers/fs/ntfs/linux-ntfs/dir.c
Normal file
1420
reactos/drivers/fs/ntfs/linux-ntfs/dir.c
Normal file
File diff suppressed because it is too large
Load diff
47
reactos/drivers/fs/ntfs/linux-ntfs/dir.h
Normal file
47
reactos/drivers/fs/ntfs/linux-ntfs/dir.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* dir.h - Defines for directory handling in NTFS Linux kernel driver. Part of
|
||||
* the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_DIR_H
|
||||
#define _LINUX_NTFS_DIR_H
|
||||
|
||||
#include "layout.h"
|
||||
|
||||
/*
|
||||
* ntfs_name is used to return the file name to the caller of
|
||||
* ntfs_lookup_inode_by_name() in order for the caller (namei.c::ntfs_lookup())
|
||||
* to be able to deal with dcache aliasing issues.
|
||||
*/
|
||||
typedef struct {
|
||||
MFT_REF mref;
|
||||
FILE_NAME_TYPE_FLAGS type;
|
||||
u8 len;
|
||||
uchar_t name[0];
|
||||
} __attribute__ ((__packed__)) ntfs_name;
|
||||
|
||||
/* The little endian Unicode string $I30 as a global constant. */
|
||||
extern uchar_t I30[5];
|
||||
|
||||
extern MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni,
|
||||
const uchar_t *uname, const int uname_len, ntfs_name **res);
|
||||
|
||||
#endif /* _LINUX_NTFS_FS_DIR_H */
|
||||
|
48
reactos/drivers/fs/ntfs/linux-ntfs/endian.h
Normal file
48
reactos/drivers/fs/ntfs/linux-ntfs/endian.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* endian.h - Defines for endianness handling in NTFS Linux kernel driver.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_ENDIAN_H
|
||||
#define _LINUX_NTFS_ENDIAN_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/*
|
||||
* Signed endianness conversion defines.
|
||||
*/
|
||||
#define sle16_to_cpu(x) ((s16)__le16_to_cpu((s16)(x)))
|
||||
#define sle32_to_cpu(x) ((s32)__le32_to_cpu((s32)(x)))
|
||||
#define sle64_to_cpu(x) ((s64)__le64_to_cpu((s64)(x)))
|
||||
|
||||
#define sle16_to_cpup(x) ((s16)__le16_to_cpu(*(s16*)(x)))
|
||||
#define sle32_to_cpup(x) ((s32)__le32_to_cpu(*(s32*)(x)))
|
||||
#define sle64_to_cpup(x) ((s64)__le64_to_cpu(*(s64*)(x)))
|
||||
|
||||
#define cpu_to_sle16(x) ((s16)__cpu_to_le16((s16)(x)))
|
||||
#define cpu_to_sle32(x) ((s32)__cpu_to_le32((s32)(x)))
|
||||
#define cpu_to_sle64(x) ((s64)__cpu_to_le64((s64)(x)))
|
||||
|
||||
#define cpu_to_sle16p(x) ((s16)__cpu_to_le16(*(s16*)(x)))
|
||||
#define cpu_to_sle32p(x) ((s32)__cpu_to_le32(*(s32*)(x)))
|
||||
#define cpu_to_sle64p(x) ((s64)__cpu_to_le64(*(s64*)(x)))
|
||||
|
||||
#endif /* _LINUX_NTFS_ENDIAN_H */
|
||||
|
76
reactos/drivers/fs/ntfs/linux-ntfs/file.c
Normal file
76
reactos/drivers/fs/ntfs/linux-ntfs/file.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* file.c - NTFS kernel file operations. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ntfs.h"
|
||||
|
||||
/**
|
||||
* ntfs_file_open - called when an inode is about to be opened
|
||||
* @vi: inode to be opened
|
||||
* @filp: file structure describing the inode
|
||||
*
|
||||
* Limit file size to the page cache limit on architectures where unsigned long
|
||||
* is 32-bits. This is the most we can do for now without overflowing the page
|
||||
* cache page index. Doing it this way means we don't run into problems because
|
||||
* of existing too large files. It would be better to allow the user to read
|
||||
* the beginning of the file but I doubt very much anyone is going to hit this
|
||||
* check on a 32-bit architecture, so there is no point in adding the extra
|
||||
* complexity required to support this.
|
||||
*
|
||||
* On 64-bit architectures, the check is hopefully optimized away by the
|
||||
* compiler.
|
||||
*
|
||||
* After the check passes, just call generic_file_open() to do its work.
|
||||
*/
|
||||
static int ntfs_file_open(struct inode *vi, struct file *filp)
|
||||
{
|
||||
if (sizeof(unsigned long) < 8) {
|
||||
if (vi->i_size > MAX_LFS_FILESIZE)
|
||||
return -EFBIG;
|
||||
}
|
||||
return generic_file_open(vi, filp);
|
||||
}
|
||||
|
||||
struct file_operations ntfs_file_ops = {
|
||||
.llseek = generic_file_llseek, /* Seek inside file. */
|
||||
.read = generic_file_read, /* Read from file. */
|
||||
#ifdef NTFS_RW
|
||||
.write = generic_file_write, /* Write to a file. */
|
||||
#endif
|
||||
.mmap = generic_file_mmap, /* Mmap file. */
|
||||
.sendfile = generic_file_sendfile,/* Zero-copy data send with the
|
||||
data source being on the
|
||||
ntfs partition. We don't
|
||||
need to care about the data
|
||||
destination. */
|
||||
.open = ntfs_file_open, /* Open file. */
|
||||
};
|
||||
|
||||
struct inode_operations ntfs_file_inode_ops = {
|
||||
#ifdef NTFS_RW
|
||||
.truncate = ntfs_truncate,
|
||||
.setattr = ntfs_setattr,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct file_operations ntfs_empty_file_ops = {};
|
||||
|
||||
struct inode_operations ntfs_empty_inode_ops = {};
|
||||
|
2025
reactos/drivers/fs/ntfs/linux-ntfs/inode.c
Normal file
2025
reactos/drivers/fs/ntfs/linux-ntfs/inode.c
Normal file
File diff suppressed because it is too large
Load diff
251
reactos/drivers/fs/ntfs/linux-ntfs/inode.h
Normal file
251
reactos/drivers/fs/ntfs/linux-ntfs/inode.h
Normal file
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* inode.h - Defines for inode structures NTFS Linux kernel driver. Part of
|
||||
* the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2003 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_INODE_H
|
||||
#define _LINUX_NTFS_INODE_H
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include "layout.h"
|
||||
#include "volume.h"
|
||||
|
||||
typedef struct _ntfs_inode ntfs_inode;
|
||||
|
||||
/*
|
||||
* The NTFS in-memory inode structure. It is just used as an extension to the
|
||||
* fields already provided in the VFS inode.
|
||||
*/
|
||||
struct _ntfs_inode {
|
||||
s64 initialized_size; /* Copy from the attribute record. */
|
||||
s64 allocated_size; /* Copy from the attribute record. */
|
||||
unsigned long state; /* NTFS specific flags describing this inode.
|
||||
See ntfs_inode_state_bits below. */
|
||||
unsigned long mft_no; /* Number of the mft record / inode. */
|
||||
u16 seq_no; /* Sequence number of the mft record. */
|
||||
atomic_t count; /* Inode reference count for book keeping. */
|
||||
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
|
||||
/*
|
||||
* If NInoAttr() is true, the below fields describe the attribute which
|
||||
* this fake inode belongs to. The actual inode of this attribute is
|
||||
* pointed to by base_ntfs_ino and nr_extents is always set to -1 (see
|
||||
* below). For real inodes, we also set the type (AT_DATA for files and
|
||||
* AT_INDEX_ALLOCATION for directories), with the name = NULL and
|
||||
* name_len = 0 for files and name = I30 (global constant) and
|
||||
* name_len = 4 for directories.
|
||||
*/
|
||||
ATTR_TYPES type; /* Attribute type of this fake inode. */
|
||||
uchar_t *name; /* Attribute name of this fake inode. */
|
||||
u32 name_len; /* Attribute name length of this fake inode. */
|
||||
run_list run_list; /* If state has the NI_NonResident bit set,
|
||||
the run list of the unnamed data attribute
|
||||
(if a file) or of the index allocation
|
||||
attribute (directory) or of the attribute
|
||||
described by the fake inode (if NInoAttr()).
|
||||
If run_list.rl is NULL, the run list has not
|
||||
been read in yet or has been unmapped. If
|
||||
NI_NonResident is clear, the attribute is
|
||||
resident (file and fake inode) or there is
|
||||
no $I30 index allocation attribute
|
||||
(small directory). In the latter case
|
||||
run_list.rl is always NULL.*/
|
||||
/*
|
||||
* The following fields are only valid for real inodes and extent
|
||||
* inodes.
|
||||
*/
|
||||
struct semaphore mrec_lock; /* Lock for serializing access to the
|
||||
mft record belonging to this inode. */
|
||||
struct page *page; /* The page containing the mft record of the
|
||||
inode. This should only be touched by the
|
||||
(un)map_mft_record*() functions. */
|
||||
int page_ofs; /* Offset into the page at which the mft record
|
||||
begins. This should only be touched by the
|
||||
(un)map_mft_record*() functions. */
|
||||
/*
|
||||
* Attribute list support (only for use by the attribute lookup
|
||||
* functions). Setup during read_inode for all inodes with attribute
|
||||
* lists. Only valid if NI_AttrList is set in state, and attr_list_rl is
|
||||
* further only valid if NI_AttrListNonResident is set.
|
||||
*/
|
||||
u32 attr_list_size; /* Length of attribute list value in bytes. */
|
||||
u8 *attr_list; /* Attribute list value itself. */
|
||||
run_list attr_list_rl; /* Run list for the attribute list value. */
|
||||
union {
|
||||
struct { /* It is a directory or $MFT. */
|
||||
struct inode *bmp_ino; /* Attribute inode for the
|
||||
directory index $BITMAP. */
|
||||
u32 block_size; /* Size of an index block. */
|
||||
u32 vcn_size; /* Size of a vcn in this
|
||||
directory index. */
|
||||
u8 block_size_bits; /* Log2 of the above. */
|
||||
u8 vcn_size_bits; /* Log2 of the above. */
|
||||
} index;
|
||||
struct { /* It is a compressed file or fake inode. */
|
||||
s64 size; /* Copy of compressed_size from
|
||||
$DATA. */
|
||||
u32 block_size; /* Size of a compression block
|
||||
(cb). */
|
||||
u8 block_size_bits; /* Log2 of the size of a cb. */
|
||||
u8 block_clusters; /* Number of clusters per cb. */
|
||||
} compressed;
|
||||
} itype;
|
||||
struct semaphore extent_lock; /* Lock for accessing/modifying the
|
||||
below . */
|
||||
s32 nr_extents; /* For a base mft record, the number of attached extent
|
||||
inodes (0 if none), for extent records and for fake
|
||||
inodes describing an attribute this is -1. */
|
||||
union { /* This union is only used if nr_extents != 0. */
|
||||
ntfs_inode **extent_ntfs_inos; /* For nr_extents > 0, array of
|
||||
the ntfs inodes of the extent
|
||||
mft records belonging to
|
||||
this base inode which have
|
||||
been loaded. */
|
||||
ntfs_inode *base_ntfs_ino; /* For nr_extents == -1, the
|
||||
ntfs inode of the base mft
|
||||
record. For fake inodes, the
|
||||
real (base) inode to which
|
||||
the attribute belongs. */
|
||||
} ext;
|
||||
};
|
||||
|
||||
/*
|
||||
* Defined bits for the state field in the ntfs_inode structure.
|
||||
* (f) = files only, (d) = directories only, (a) = attributes/fake inodes only
|
||||
*/
|
||||
typedef enum {
|
||||
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
||||
NI_AttrList, /* 1: Mft record contains an attribute list. */
|
||||
NI_AttrListNonResident, /* 1: Attribute list is non-resident. Implies
|
||||
NI_AttrList is set. */
|
||||
|
||||
NI_Attr, /* 1: Fake inode for attribute i/o.
|
||||
0: Real inode or extent inode. */
|
||||
|
||||
NI_MstProtected, /* 1: Attribute is protected by MST fixups.
|
||||
0: Attribute is not protected by fixups. */
|
||||
NI_NonResident, /* 1: Unnamed data attr is non-resident (f).
|
||||
1: Attribute is non-resident (a). */
|
||||
NI_IndexAllocPresent = NI_NonResident, /* 1: $I30 index alloc attr is
|
||||
present (d). */
|
||||
NI_Compressed, /* 1: Unnamed data attr is compressed (f).
|
||||
1: Create compressed files by default (d).
|
||||
1: Attribute is compressed (a). */
|
||||
NI_Encrypted, /* 1: Unnamed data attr is encrypted (f).
|
||||
1: Create encrypted files by default (d).
|
||||
1: Attribute is encrypted (a). */
|
||||
NI_Sparse, /* 1: Unnamed data attr is sparse (f).
|
||||
1: Create sparse files by default (d).
|
||||
1: Attribute is sparse (a). */
|
||||
} ntfs_inode_state_bits;
|
||||
|
||||
/*
|
||||
* NOTE: We should be adding dirty mft records to a list somewhere and they
|
||||
* should be independent of the (ntfs/vfs) inode structure so that an inode can
|
||||
* be removed but the record can be left dirty for syncing later.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Macro tricks to expand the NInoFoo(), NInoSetFoo(), and NInoClearFoo()
|
||||
* functions.
|
||||
*/
|
||||
#define NINO_FNS(flag) \
|
||||
static inline int NIno##flag(ntfs_inode *ni) \
|
||||
{ \
|
||||
return test_bit(NI_##flag, &(ni)->state); \
|
||||
} \
|
||||
static inline void NInoSet##flag(ntfs_inode *ni) \
|
||||
{ \
|
||||
set_bit(NI_##flag, &(ni)->state); \
|
||||
} \
|
||||
static inline void NInoClear##flag(ntfs_inode *ni) \
|
||||
{ \
|
||||
clear_bit(NI_##flag, &(ni)->state); \
|
||||
}
|
||||
|
||||
/* Emit the ntfs inode bitops functions. */
|
||||
NINO_FNS(Dirty)
|
||||
NINO_FNS(AttrList)
|
||||
NINO_FNS(AttrListNonResident)
|
||||
NINO_FNS(Attr)
|
||||
NINO_FNS(MstProtected)
|
||||
NINO_FNS(NonResident)
|
||||
NINO_FNS(IndexAllocPresent)
|
||||
NINO_FNS(Compressed)
|
||||
NINO_FNS(Encrypted)
|
||||
NINO_FNS(Sparse)
|
||||
|
||||
/*
|
||||
* The full structure containing a ntfs_inode and a vfs struct inode. Used for
|
||||
* all real and fake inodes but not for extent inodes which lack the vfs struct
|
||||
* inode.
|
||||
*/
|
||||
typedef struct {
|
||||
ntfs_inode ntfs_inode;
|
||||
struct inode vfs_inode; /* The vfs inode structure. */
|
||||
} big_ntfs_inode;
|
||||
|
||||
/**
|
||||
* NTFS_I - return the ntfs inode given a vfs inode
|
||||
* @inode: VFS inode
|
||||
*
|
||||
* NTFS_I() returns the ntfs inode associated with the VFS @inode.
|
||||
*/
|
||||
static inline ntfs_inode *NTFS_I(struct inode *inode)
|
||||
{
|
||||
return (ntfs_inode *)list_entry(inode, big_ntfs_inode, vfs_inode);
|
||||
}
|
||||
|
||||
static inline struct inode *VFS_I(ntfs_inode *ni)
|
||||
{
|
||||
return &((big_ntfs_inode *)ni)->vfs_inode;
|
||||
}
|
||||
|
||||
extern struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no);
|
||||
extern struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPES type,
|
||||
uchar_t *name, u32 name_len);
|
||||
|
||||
extern struct inode *ntfs_alloc_big_inode(struct super_block *sb);
|
||||
extern void ntfs_destroy_big_inode(struct inode *inode);
|
||||
extern void ntfs_clear_big_inode(struct inode *vi);
|
||||
|
||||
extern ntfs_inode *ntfs_new_extent_inode(struct super_block *sb,
|
||||
unsigned long mft_no);
|
||||
extern void ntfs_clear_extent_inode(ntfs_inode *ni);
|
||||
|
||||
extern void ntfs_read_inode_mount(struct inode *vi);
|
||||
|
||||
extern void ntfs_dirty_inode(struct inode *vi);
|
||||
|
||||
extern void ntfs_put_inode(struct inode *vi);
|
||||
|
||||
extern int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt);
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
extern void ntfs_truncate(struct inode *vi);
|
||||
|
||||
extern int ntfs_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_NTFS_FS_INODE_H */
|
||||
|
2258
reactos/drivers/fs/ntfs/linux-ntfs/layout.h
Normal file
2258
reactos/drivers/fs/ntfs/linux-ntfs/layout.h
Normal file
File diff suppressed because it is too large
Load diff
64
reactos/drivers/fs/ntfs/linux-ntfs/malloc.h
Normal file
64
reactos/drivers/fs/ntfs/linux-ntfs/malloc.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* malloc.h - NTFS kernel memory handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001,2002 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_MALLOC_H
|
||||
#define _LINUX_NTFS_MALLOC_H
|
||||
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/**
|
||||
* ntfs_malloc_nofs - allocate memory in multiples of pages
|
||||
* @size number of bytes to allocate
|
||||
*
|
||||
* Allocates @size bytes of memory, rounded up to multiples of PAGE_SIZE and
|
||||
* returns a pointer to the allocated memory.
|
||||
*
|
||||
* If there was insufficient memory to complete the request, return NULL.
|
||||
*/
|
||||
static inline void *ntfs_malloc_nofs(unsigned long size)
|
||||
{
|
||||
if (likely(size <= PAGE_SIZE)) {
|
||||
if (likely(size)) {
|
||||
/* kmalloc() has per-CPU caches so if faster for now. */
|
||||
return kmalloc(PAGE_SIZE, GFP_NOFS);
|
||||
/* return (void *)__get_free_page(GFP_NOFS |
|
||||
__GFP_HIGHMEM); */
|
||||
}
|
||||
BUG();
|
||||
}
|
||||
if (likely(size >> PAGE_SHIFT < num_physpages))
|
||||
return __vmalloc(size, GFP_NOFS | __GFP_HIGHMEM, PAGE_KERNEL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void ntfs_free(void *addr)
|
||||
{
|
||||
if (likely(((unsigned long)addr < VMALLOC_START) ||
|
||||
((unsigned long)addr >= VMALLOC_END ))) {
|
||||
return kfree(addr);
|
||||
/* return free_page((unsigned long)addr); */
|
||||
}
|
||||
vfree(addr);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_NTFS_MALLOC_H */
|
||||
|
432
reactos/drivers/fs/ntfs/linux-ntfs/mft.c
Normal file
432
reactos/drivers/fs/ntfs/linux-ntfs/mft.c
Normal file
|
@ -0,0 +1,432 @@
|
|||
/**
|
||||
* mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2003 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/swap.h>
|
||||
|
||||
#include "ntfs.h"
|
||||
|
||||
/**
|
||||
* __format_mft_record - initialize an empty mft record
|
||||
* @m: mapped, pinned and locked for writing mft record
|
||||
* @size: size of the mft record
|
||||
* @rec_no: mft record number / inode number
|
||||
*
|
||||
* Private function to initialize an empty mft record. Use one of the two
|
||||
* provided format_mft_record() functions instead.
|
||||
*/
|
||||
static void __format_mft_record(MFT_RECORD *m, const int size,
|
||||
const unsigned long rec_no)
|
||||
{
|
||||
ATTR_RECORD *a;
|
||||
|
||||
memset(m, 0, size);
|
||||
m->magic = magic_FILE;
|
||||
/* Aligned to 2-byte boundary. */
|
||||
m->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD) + 1) & ~1);
|
||||
m->usa_count = cpu_to_le16(size / NTFS_BLOCK_SIZE + 1);
|
||||
/* Set the update sequence number to 1. */
|
||||
*(u16*)((char*)m + ((sizeof(MFT_RECORD) + 1) & ~1)) = cpu_to_le16(1);
|
||||
m->lsn = cpu_to_le64(0LL);
|
||||
m->sequence_number = cpu_to_le16(1);
|
||||
m->link_count = cpu_to_le16(0);
|
||||
/* Aligned to 8-byte boundary. */
|
||||
m->attrs_offset = cpu_to_le16((le16_to_cpu(m->usa_ofs) +
|
||||
(le16_to_cpu(m->usa_count) << 1) + 7) & ~7);
|
||||
m->flags = cpu_to_le16(0);
|
||||
/*
|
||||
* Using attrs_offset plus eight bytes (for the termination attribute),
|
||||
* aligned to 8-byte boundary.
|
||||
*/
|
||||
m->bytes_in_use = cpu_to_le32((le16_to_cpu(m->attrs_offset) + 8 + 7) &
|
||||
~7);
|
||||
m->bytes_allocated = cpu_to_le32(size);
|
||||
m->base_mft_record = cpu_to_le64((MFT_REF)0);
|
||||
m->next_attr_instance = cpu_to_le16(0);
|
||||
a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
|
||||
a->type = AT_END;
|
||||
a->length = cpu_to_le32(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* format_mft_record - initialize an empty mft record
|
||||
* @ni: ntfs inode of mft record
|
||||
* @mft_rec: mapped, pinned and locked mft record (optional)
|
||||
*
|
||||
* Initialize an empty mft record. This is used when extending the MFT.
|
||||
*
|
||||
* If @mft_rec is NULL, we call map_mft_record() to obtain the
|
||||
* record and we unmap it again when finished.
|
||||
*
|
||||
* We return 0 on success or -errno on error.
|
||||
*/
|
||||
int format_mft_record(ntfs_inode *ni, MFT_RECORD *mft_rec)
|
||||
{
|
||||
MFT_RECORD *m;
|
||||
|
||||
if (mft_rec)
|
||||
m = mft_rec;
|
||||
else {
|
||||
m = map_mft_record(ni);
|
||||
if (IS_ERR(m))
|
||||
return PTR_ERR(m);
|
||||
}
|
||||
__format_mft_record(m, ni->vol->mft_record_size, ni->mft_no);
|
||||
if (!mft_rec) {
|
||||
// FIXME: Need to set the mft record dirty!
|
||||
unmap_mft_record(ni);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_readpage - external declaration, function is in fs/ntfs/aops.c
|
||||
*/
|
||||
extern int ntfs_readpage(struct file *, struct page *);
|
||||
|
||||
/**
|
||||
* ntfs_mft_aops - address space operations for access to $MFT
|
||||
*
|
||||
* Address space operations for access to $MFT. This allows us to simply use
|
||||
* ntfs_map_page() in map_mft_record_page().
|
||||
*/
|
||||
struct address_space_operations ntfs_mft_aops = {
|
||||
.readpage = ntfs_readpage, /* Fill page with data. */
|
||||
.sync_page = block_sync_page, /* Currently, just unplugs the
|
||||
disk request queue. */
|
||||
};
|
||||
|
||||
/**
|
||||
* map_mft_record_page - map the page in which a specific mft record resides
|
||||
* @ni: ntfs inode whose mft record page to map
|
||||
*
|
||||
* This maps the page in which the mft record of the ntfs inode @ni is situated
|
||||
* and returns a pointer to the mft record within the mapped page.
|
||||
*
|
||||
* Return value needs to be checked with IS_ERR() and if that is true PTR_ERR()
|
||||
* contains the negative error code returned.
|
||||
*/
|
||||
static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
|
||||
{
|
||||
ntfs_volume *vol = ni->vol;
|
||||
struct inode *mft_vi = vol->mft_ino;
|
||||
struct page *page;
|
||||
unsigned long index, ofs, end_index;
|
||||
|
||||
BUG_ON(ni->page);
|
||||
/*
|
||||
* The index into the page cache and the offset within the page cache
|
||||
* page of the wanted mft record. FIXME: We need to check for
|
||||
* overflowing the unsigned long, but I don't think we would ever get
|
||||
* here if the volume was that big...
|
||||
*/
|
||||
index = ni->mft_no << vol->mft_record_size_bits >> PAGE_CACHE_SHIFT;
|
||||
ofs = (ni->mft_no << vol->mft_record_size_bits) & ~PAGE_CACHE_MASK;
|
||||
|
||||
/* The maximum valid index into the page cache for $MFT's data. */
|
||||
end_index = mft_vi->i_size >> PAGE_CACHE_SHIFT;
|
||||
|
||||
/* If the wanted index is out of bounds the mft record doesn't exist. */
|
||||
if (unlikely(index >= end_index)) {
|
||||
if (index > end_index || (mft_vi->i_size & ~PAGE_CACHE_MASK) <
|
||||
ofs + vol->mft_record_size) {
|
||||
page = ERR_PTR(-ENOENT);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
/* Read, map, and pin the page. */
|
||||
page = ntfs_map_page(mft_vi->i_mapping, index);
|
||||
if (likely(!IS_ERR(page))) {
|
||||
ni->page = page;
|
||||
ni->page_ofs = ofs;
|
||||
return page_address(page) + ofs;
|
||||
}
|
||||
err_out:
|
||||
ni->page = NULL;
|
||||
ni->page_ofs = 0;
|
||||
ntfs_error(vol->sb, "Failed with error code %lu.", -PTR_ERR(page));
|
||||
return (void*)page;
|
||||
}
|
||||
|
||||
/**
|
||||
* map_mft_record - map, pin and lock an mft record
|
||||
* @ni: ntfs inode whose MFT record to map
|
||||
*
|
||||
* First, take the mrec_lock semaphore. We might now be sleeping, while waiting
|
||||
* for the semaphore if it was already locked by someone else.
|
||||
*
|
||||
* The page of the record is mapped using map_mft_record_page() before being
|
||||
* returned to the caller.
|
||||
*
|
||||
* This in turn uses ntfs_map_page() to get the page containing the wanted mft
|
||||
* record (it in turn calls read_cache_page() which reads it in from disk if
|
||||
* necessary, increments the use count on the page so that it cannot disappear
|
||||
* under us and returns a reference to the page cache page).
|
||||
*
|
||||
* If read_cache_page() invokes ntfs_readpage() to load the page from disk, it
|
||||
* sets PG_locked and clears PG_uptodate on the page. Once I/O has completed
|
||||
* and the post-read mst fixups on each mft record in the page have been
|
||||
* performed, the page gets PG_uptodate set and PG_locked cleared (this is done
|
||||
* in our asynchronous I/O completion handler end_buffer_read_mft_async()).
|
||||
* ntfs_map_page() waits for PG_locked to become clear and checks if
|
||||
* PG_uptodate is set and returns an error code if not. This provides
|
||||
* sufficient protection against races when reading/using the page.
|
||||
*
|
||||
* However there is the write mapping to think about. Doing the above described
|
||||
* checking here will be fine, because when initiating the write we will set
|
||||
* PG_locked and clear PG_uptodate making sure nobody is touching the page
|
||||
* contents. Doing the locking this way means that the commit to disk code in
|
||||
* the page cache code paths is automatically sufficiently locked with us as
|
||||
* we will not touch a page that has been locked or is not uptodate. The only
|
||||
* locking problem then is them locking the page while we are accessing it.
|
||||
*
|
||||
* So that code will end up having to own the mrec_lock of all mft
|
||||
* records/inodes present in the page before I/O can proceed. In that case we
|
||||
* wouldn't need to bother with PG_locked and PG_uptodate as nobody will be
|
||||
* accessing anything without owning the mrec_lock semaphore. But we do need
|
||||
* to use them because of the read_cache_page() invocation and the code becomes
|
||||
* so much simpler this way that it is well worth it.
|
||||
*
|
||||
* The mft record is now ours and we return a pointer to it. You need to check
|
||||
* the returned pointer with IS_ERR() and if that is true, PTR_ERR() will return
|
||||
* the error code.
|
||||
*
|
||||
* NOTE: Caller is responsible for setting the mft record dirty before calling
|
||||
* unmap_mft_record(). This is obviously only necessary if the caller really
|
||||
* modified the mft record...
|
||||
* Q: Do we want to recycle one of the VFS inode state bits instead?
|
||||
* A: No, the inode ones mean we want to change the mft record, not we want to
|
||||
* write it out.
|
||||
*/
|
||||
MFT_RECORD *map_mft_record(ntfs_inode *ni)
|
||||
{
|
||||
MFT_RECORD *m;
|
||||
|
||||
ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
|
||||
|
||||
/* Make sure the ntfs inode doesn't go away. */
|
||||
atomic_inc(&ni->count);
|
||||
|
||||
/* Serialize access to this mft record. */
|
||||
down(&ni->mrec_lock);
|
||||
|
||||
m = map_mft_record_page(ni);
|
||||
if (likely(!IS_ERR(m)))
|
||||
return m;
|
||||
|
||||
up(&ni->mrec_lock);
|
||||
atomic_dec(&ni->count);
|
||||
ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* unmap_mft_record_page - unmap the page in which a specific mft record resides
|
||||
* @ni: ntfs inode whose mft record page to unmap
|
||||
*
|
||||
* This unmaps the page in which the mft record of the ntfs inode @ni is
|
||||
* situated and returns. This is a NOOP if highmem is not configured.
|
||||
*
|
||||
* The unmap happens via ntfs_unmap_page() which in turn decrements the use
|
||||
* count on the page thus releasing it from the pinned state.
|
||||
*
|
||||
* We do not actually unmap the page from memory of course, as that will be
|
||||
* done by the page cache code itself when memory pressure increases or
|
||||
* whatever.
|
||||
*/
|
||||
static inline void unmap_mft_record_page(ntfs_inode *ni)
|
||||
{
|
||||
BUG_ON(!ni->page);
|
||||
|
||||
// TODO: If dirty, blah...
|
||||
ntfs_unmap_page(ni->page);
|
||||
ni->page = NULL;
|
||||
ni->page_ofs = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* unmap_mft_record - release a mapped mft record
|
||||
* @ni: ntfs inode whose MFT record to unmap
|
||||
*
|
||||
* We release the page mapping and the mrec_lock mutex which unmaps the mft
|
||||
* record and releases it for others to get hold of. We also release the ntfs
|
||||
* inode by decrementing the ntfs inode reference count.
|
||||
*
|
||||
* NOTE: If caller has modified the mft record, it is imperative to set the mft
|
||||
* record dirty BEFORE calling unmap_mft_record().
|
||||
*/
|
||||
void unmap_mft_record(ntfs_inode *ni)
|
||||
{
|
||||
struct page *page = ni->page;
|
||||
|
||||
BUG_ON(!page);
|
||||
|
||||
ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
|
||||
|
||||
unmap_mft_record_page(ni);
|
||||
up(&ni->mrec_lock);
|
||||
atomic_dec(&ni->count);
|
||||
/*
|
||||
* If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
|
||||
* ntfs_clear_extent_inode() in the extent inode case, and to the
|
||||
* caller in the non-extent, yet pure ntfs inode case, to do the actual
|
||||
* tear down of all structures and freeing of all allocated memory.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* map_extent_mft_record - load an extent inode and attach it to its base
|
||||
* @base_ni: base ntfs inode
|
||||
* @mref: mft reference of the extent inode to load (in little endian)
|
||||
* @ntfs_ino: on successful return, pointer to the ntfs_inode structure
|
||||
*
|
||||
* Load the extent mft record @mref and attach it to its base inode @base_ni.
|
||||
* Return the mapped extent mft record if IS_ERR(result) is false. Otherwise
|
||||
* PTR_ERR(result) gives the negative error code.
|
||||
*
|
||||
* On successful return, @ntfs_ino contains a pointer to the ntfs_inode
|
||||
* structure of the mapped extent inode.
|
||||
*/
|
||||
MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
|
||||
ntfs_inode **ntfs_ino)
|
||||
{
|
||||
MFT_RECORD *m;
|
||||
ntfs_inode *ni = NULL;
|
||||
ntfs_inode **extent_nis = NULL;
|
||||
int i;
|
||||
unsigned long mft_no = MREF_LE(mref);
|
||||
u16 seq_no = MSEQNO_LE(mref);
|
||||
BOOL destroy_ni = FALSE;
|
||||
|
||||
ntfs_debug("Mapping extent mft record 0x%lx (base mft record 0x%lx).",
|
||||
mft_no, base_ni->mft_no);
|
||||
/* Make sure the base ntfs inode doesn't go away. */
|
||||
atomic_inc(&base_ni->count);
|
||||
/*
|
||||
* Check if this extent inode has already been added to the base inode,
|
||||
* in which case just return it. If not found, add it to the base
|
||||
* inode before returning it.
|
||||
*/
|
||||
down(&base_ni->extent_lock);
|
||||
if (base_ni->nr_extents > 0) {
|
||||
extent_nis = base_ni->ext.extent_ntfs_inos;
|
||||
for (i = 0; i < base_ni->nr_extents; i++) {
|
||||
if (mft_no != extent_nis[i]->mft_no)
|
||||
continue;
|
||||
ni = extent_nis[i];
|
||||
/* Make sure the ntfs inode doesn't go away. */
|
||||
atomic_inc(&ni->count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (likely(ni != NULL)) {
|
||||
up(&base_ni->extent_lock);
|
||||
atomic_dec(&base_ni->count);
|
||||
/* We found the record; just have to map and return it. */
|
||||
m = map_mft_record(ni);
|
||||
/* map_mft_record() has incremented this on success. */
|
||||
atomic_dec(&ni->count);
|
||||
if (likely(!IS_ERR(m))) {
|
||||
/* Verify the sequence number. */
|
||||
if (likely(le16_to_cpu(m->sequence_number) == seq_no)) {
|
||||
ntfs_debug("Done 1.");
|
||||
*ntfs_ino = ni;
|
||||
return m;
|
||||
}
|
||||
unmap_mft_record(ni);
|
||||
ntfs_error(base_ni->vol->sb, "Found stale extent mft "
|
||||
"reference! Corrupt file system. "
|
||||
"Run chkdsk.");
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
map_err_out:
|
||||
ntfs_error(base_ni->vol->sb, "Failed to map extent "
|
||||
"mft record, error code %ld.", -PTR_ERR(m));
|
||||
return m;
|
||||
}
|
||||
/* Record wasn't there. Get a new ntfs inode and initialize it. */
|
||||
ni = ntfs_new_extent_inode(base_ni->vol->sb, mft_no);
|
||||
if (unlikely(!ni)) {
|
||||
up(&base_ni->extent_lock);
|
||||
atomic_dec(&base_ni->count);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
ni->vol = base_ni->vol;
|
||||
ni->seq_no = seq_no;
|
||||
ni->nr_extents = -1;
|
||||
ni->ext.base_ntfs_ino = base_ni;
|
||||
/* Now map the record. */
|
||||
m = map_mft_record(ni);
|
||||
if (unlikely(IS_ERR(m))) {
|
||||
up(&base_ni->extent_lock);
|
||||
atomic_dec(&base_ni->count);
|
||||
ntfs_clear_extent_inode(ni);
|
||||
goto map_err_out;
|
||||
}
|
||||
/* Verify the sequence number. */
|
||||
if (unlikely(le16_to_cpu(m->sequence_number) != seq_no)) {
|
||||
ntfs_error(base_ni->vol->sb, "Found stale extent mft "
|
||||
"reference! Corrupt file system. Run chkdsk.");
|
||||
destroy_ni = TRUE;
|
||||
m = ERR_PTR(-EIO);
|
||||
goto unm_err_out;
|
||||
}
|
||||
/* Attach extent inode to base inode, reallocating memory if needed. */
|
||||
if (!(base_ni->nr_extents & 3)) {
|
||||
ntfs_inode **tmp;
|
||||
int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);
|
||||
|
||||
tmp = (ntfs_inode **)kmalloc(new_size, GFP_NOFS);
|
||||
if (unlikely(!tmp)) {
|
||||
ntfs_error(base_ni->vol->sb, "Failed to allocate "
|
||||
"internal buffer.");
|
||||
destroy_ni = TRUE;
|
||||
m = ERR_PTR(-ENOMEM);
|
||||
goto unm_err_out;
|
||||
}
|
||||
if (base_ni->ext.extent_ntfs_inos) {
|
||||
memcpy(tmp, base_ni->ext.extent_ntfs_inos, new_size -
|
||||
4 * sizeof(ntfs_inode *));
|
||||
kfree(base_ni->ext.extent_ntfs_inos);
|
||||
}
|
||||
base_ni->ext.extent_ntfs_inos = tmp;
|
||||
}
|
||||
base_ni->ext.extent_ntfs_inos[base_ni->nr_extents++] = ni;
|
||||
up(&base_ni->extent_lock);
|
||||
atomic_dec(&base_ni->count);
|
||||
ntfs_debug("Done 2.");
|
||||
*ntfs_ino = ni;
|
||||
return m;
|
||||
unm_err_out:
|
||||
unmap_mft_record(ni);
|
||||
up(&base_ni->extent_lock);
|
||||
atomic_dec(&base_ni->count);
|
||||
/*
|
||||
* If the extent inode was not attached to the base inode we need to
|
||||
* release it or we will leak memory.
|
||||
*/
|
||||
if (destroy_ni)
|
||||
ntfs_clear_extent_inode(ni);
|
||||
return m;
|
||||
}
|
||||
|
61
reactos/drivers/fs/ntfs/linux-ntfs/mft.h
Normal file
61
reactos/drivers/fs/ntfs/linux-ntfs/mft.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* mft.h - Defines for mft record handling in NTFS Linux kernel driver.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001,2002 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_MFT_H
|
||||
#define _LINUX_NTFS_MFT_H
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "inode.h"
|
||||
|
||||
extern int format_mft_record(ntfs_inode *ni, MFT_RECORD *m);
|
||||
//extern int format_mft_record2(struct super_block *vfs_sb,
|
||||
// const unsigned long inum, MFT_RECORD *m);
|
||||
|
||||
extern MFT_RECORD *map_mft_record(ntfs_inode *ni);
|
||||
extern void unmap_mft_record(ntfs_inode *ni);
|
||||
|
||||
extern MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
|
||||
ntfs_inode **ntfs_ino);
|
||||
|
||||
static inline void unmap_extent_mft_record(ntfs_inode *ni)
|
||||
{
|
||||
unmap_mft_record(ni);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* flush_dcache_mft_record_page - flush_dcache_page() for mft records
|
||||
* @ni: ntfs inode structure of mft record
|
||||
*
|
||||
* Call flush_dcache_page() for the page in which an mft record resides.
|
||||
*
|
||||
* This must be called every time an mft record is modified, just after the
|
||||
* modification.
|
||||
*/
|
||||
static inline void flush_dcache_mft_record_page(ntfs_inode *ni)
|
||||
{
|
||||
flush_dcache_page(ni->page);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_NTFS_MFT_H */
|
||||
|
202
reactos/drivers/fs/ntfs/linux-ntfs/mst.c
Normal file
202
reactos/drivers/fs/ntfs/linux-ntfs/mst.c
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* mst.c - NTFS multi sector transfer protection handling code. Part of the
|
||||
* Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ntfs.h"
|
||||
|
||||
/**
|
||||
* post_read_mst_fixup - deprotect multi sector transfer protected data
|
||||
* @b: pointer to the data to deprotect
|
||||
* @size: size in bytes of @b
|
||||
*
|
||||
* Perform the necessary post read multi sector transfer fixup and detect the
|
||||
* presence of incomplete multi sector transfers. - In that case, overwrite the
|
||||
* magic of the ntfs record header being processed with "BAAD" (in memory only!)
|
||||
* and abort processing.
|
||||
*
|
||||
* Return 0 on success and -EINVAL on error ("BAAD" magic will be present).
|
||||
*
|
||||
* NOTE: We consider the absence / invalidity of an update sequence array to
|
||||
* mean that the structure is not protected at all and hence doesn't need to
|
||||
* be fixed up. Thus, we return success and not failure in this case. This is
|
||||
* in contrast to pre_write_mst_fixup(), see below.
|
||||
*/
|
||||
int post_read_mst_fixup(NTFS_RECORD *b, const u32 size)
|
||||
{
|
||||
u16 usa_ofs, usa_count, usn;
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
/* Setup the variables. */
|
||||
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
/* Decrement usa_count to get number of fixups. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
/* Size and alignment checks. */
|
||||
if ( size & (NTFS_BLOCK_SIZE - 1) ||
|
||||
usa_ofs & 1 ||
|
||||
usa_ofs + (usa_count * 2) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count)
|
||||
return 0;
|
||||
/* Position of usn in update sequence array. */
|
||||
usa_pos = (u16*)b + usa_ofs/sizeof(u16);
|
||||
/*
|
||||
* The update sequence number which has to be equal to each of the
|
||||
* u16 values before they are fixed up. Note no need to care for
|
||||
* endianness since we are comparing and moving data for on disk
|
||||
* structures which means the data is consistent. - If it is
|
||||
* consistenty the wrong endianness it doesn't make any difference.
|
||||
*/
|
||||
usn = *usa_pos;
|
||||
/*
|
||||
* Position in protected data of first u16 that needs fixing up.
|
||||
*/
|
||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
/*
|
||||
* Check for incomplete multi sector transfer(s).
|
||||
*/
|
||||
while (usa_count--) {
|
||||
if (*data_pos != usn) {
|
||||
/*
|
||||
* Incomplete multi sector transfer detected! )-:
|
||||
* Set the magic to "BAAD" and return failure.
|
||||
* Note that magic_BAAD is already converted to le32.
|
||||
*/
|
||||
b->magic = magic_BAAD;
|
||||
return -EINVAL;
|
||||
}
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
/* Re-setup the variables. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
*/
|
||||
*data_pos = *(++usa_pos);
|
||||
/* Increment position in data as well. */
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pre_write_mst_fixup - apply multi sector transfer protection
|
||||
* @b: pointer to the data to protect
|
||||
* @size: size in bytes of @b
|
||||
*
|
||||
* Perform the necessary pre write multi sector transfer fixup on the data
|
||||
* pointer to by @b of @size.
|
||||
*
|
||||
* Return 0 if fixup applied (success) or -EINVAL if no fixup was performed
|
||||
* (assumed not needed). This is in contrast to post_read_mst_fixup() above.
|
||||
*
|
||||
* NOTE: We consider the absence / invalidity of an update sequence array to
|
||||
* mean that the structure is not subject to protection and hence doesn't need
|
||||
* to be fixed up. This means that you have to create a valid update sequence
|
||||
* array header in the ntfs record before calling this function, otherwise it
|
||||
* will fail (the header needs to contain the position of the update sequence
|
||||
* array together with the number of elements in the array). You also need to
|
||||
* initialise the update sequence number before calling this function
|
||||
* otherwise a random word will be used (whatever was in the record at that
|
||||
* position at that time).
|
||||
*/
|
||||
int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size)
|
||||
{
|
||||
u16 usa_ofs, usa_count, usn;
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
/* Sanity check + only fixup if it makes sense. */
|
||||
if (!b || is_baad_record(b->magic) || is_hole_record(b->magic))
|
||||
return -EINVAL;
|
||||
/* Setup the variables. */
|
||||
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
/* Decrement usa_count to get number of fixups. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
/* Size and alignment checks. */
|
||||
if ( size & (NTFS_BLOCK_SIZE - 1) ||
|
||||
usa_ofs & 1 ||
|
||||
usa_ofs + (usa_count * 2) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count)
|
||||
return -EINVAL;
|
||||
/* Position of usn in update sequence array. */
|
||||
usa_pos = (u16*)((u8*)b + usa_ofs);
|
||||
/*
|
||||
* Cyclically increment the update sequence number
|
||||
* (skipping 0 and -1, i.e. 0xffff).
|
||||
*/
|
||||
usn = le16_to_cpup(usa_pos) + 1;
|
||||
if (usn == 0xffff || !usn)
|
||||
usn = 1;
|
||||
usn = cpu_to_le16(usn);
|
||||
*usa_pos = usn;
|
||||
/* Position in data of first u16 that needs fixing up. */
|
||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
/*
|
||||
* Increment the position in the usa and save the
|
||||
* original data from the data buffer into the usa.
|
||||
*/
|
||||
*(++usa_pos) = *data_pos;
|
||||
/* Apply fixup to data. */
|
||||
*data_pos = usn;
|
||||
/* Increment position in data as well. */
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* post_write_mst_fixup - fast deprotect multi sector transfer protected data
|
||||
* @b: pointer to the data to deprotect
|
||||
*
|
||||
* Perform the necessary post write multi sector transfer fixup, not checking
|
||||
* for any errors, because we assume we have just used pre_write_mst_fixup(),
|
||||
* thus the data will be fine or we would never have gotten here.
|
||||
*/
|
||||
void post_write_mst_fixup(NTFS_RECORD *b)
|
||||
{
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
u16 usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
u16 usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
|
||||
/* Position of usn in update sequence array. */
|
||||
usa_pos = (u16*)b + usa_ofs/sizeof(u16);
|
||||
|
||||
/* Position in protected data of first u16 that needs fixing up. */
|
||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
*/
|
||||
*data_pos = *(++usa_pos);
|
||||
|
||||
/* Increment position in data as well. */
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
}
|
||||
|
297
reactos/drivers/fs/ntfs/linux-ntfs/namei.c
Normal file
297
reactos/drivers/fs/ntfs/linux-ntfs/namei.c
Normal file
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
* namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2001-2003 Anton Altaparmakov
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/dcache.h>
|
||||
|
||||
#include "ntfs.h"
|
||||
#include "dir.h"
|
||||
|
||||
/**
|
||||
* ntfs_lookup - find the inode represented by a dentry in a directory inode
|
||||
* @dir_ino: directory inode in which to look for the inode
|
||||
* @dent: dentry representing the inode to look for
|
||||
* @nd: lookup nameidata
|
||||
*
|
||||
* In short, ntfs_lookup() looks for the inode represented by the dentry @dent
|
||||
* in the directory inode @dir_ino and if found attaches the inode to the
|
||||
* dentry @dent.
|
||||
*
|
||||
* In more detail, the dentry @dent specifies which inode to look for by
|
||||
* supplying the name of the inode in @dent->d_name.name. ntfs_lookup()
|
||||
* converts the name to Unicode and walks the contents of the directory inode
|
||||
* @dir_ino looking for the converted Unicode name. If the name is found in the
|
||||
* directory, the corresponding inode is loaded by calling ntfs_iget() on its
|
||||
* inode number and the inode is associated with the dentry @dent via a call to
|
||||
* d_add().
|
||||
*
|
||||
* If the name is not found in the directory, a NULL inode is inserted into the
|
||||
* dentry @dent. The dentry is then termed a negative dentry.
|
||||
*
|
||||
* Only if an actual error occurs, do we return an error via ERR_PTR().
|
||||
*
|
||||
* In order to handle the case insensitivity issues of NTFS with regards to the
|
||||
* dcache and the dcache requiring only one dentry per directory, we deal with
|
||||
* dentry aliases that only differ in case in ->ntfs_lookup() while maintining
|
||||
* a case sensitive dcache. This means that we get the full benefit of dcache
|
||||
* speed when the file/directory is looked up with the same case as returned by
|
||||
* ->ntfs_readdir() but that a lookup for any other case (or for the short file
|
||||
* name) will not find anything in dcache and will enter ->ntfs_lookup()
|
||||
* instead, where we search the directory for a fully matching file name
|
||||
* (including case) and if that is not found, we search for a file name that
|
||||
* matches with different case and if that has non-POSIX semantics we return
|
||||
* that. We actually do only one search (case sensitive) and keep tabs on
|
||||
* whether we have found a case insensitive match in the process.
|
||||
*
|
||||
* To simplify matters for us, we do not treat the short vs long filenames as
|
||||
* two hard links but instead if the lookup matches a short filename, we
|
||||
* return the dentry for the corresponding long filename instead.
|
||||
*
|
||||
* There are three cases we need to distinguish here:
|
||||
*
|
||||
* 1) @dent perfectly matches (i.e. including case) a directory entry with a
|
||||
* file name in the WIN32 or POSIX namespaces. In this case
|
||||
* ntfs_lookup_inode_by_name() will return with name set to NULL and we
|
||||
* just d_add() @dent.
|
||||
* 2) @dent matches (not including case) a directory entry with a file name in
|
||||
* the WIN32 namespace. In this case ntfs_lookup_inode_by_name() will return
|
||||
* with name set to point to a kmalloc()ed ntfs_name structure containing
|
||||
* the properly cased little endian Unicode name. We convert the name to the
|
||||
* current NLS code page, search if a dentry with this name already exists
|
||||
* and if so return that instead of @dent. The VFS will then destroy the old
|
||||
* @dent and use the one we returned. If a dentry is not found, we allocate
|
||||
* a new one, d_add() it, and return it as above.
|
||||
* 3) @dent matches either perfectly or not (i.e. we don't care about case) a
|
||||
* directory entry with a file name in the DOS namespace. In this case
|
||||
* ntfs_lookup_inode_by_name() will return with name set to point to a
|
||||
* kmalloc()ed ntfs_name structure containing the mft reference (cpu endian)
|
||||
* of the inode. We use the mft reference to read the inode and to find the
|
||||
* file name in the WIN32 namespace corresponding to the matched short file
|
||||
* name. We then convert the name to the current NLS code page, and proceed
|
||||
* searching for a dentry with this name, etc, as in case 2), above.
|
||||
*/
|
||||
static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, struct nameidata *nd)
|
||||
{
|
||||
ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
|
||||
struct inode *dent_inode;
|
||||
uchar_t *uname;
|
||||
ntfs_name *name = NULL;
|
||||
MFT_REF mref;
|
||||
unsigned long dent_ino;
|
||||
int uname_len;
|
||||
|
||||
ntfs_debug("Looking up %s in directory inode 0x%lx.",
|
||||
dent->d_name.name, dir_ino->i_ino);
|
||||
/* Convert the name of the dentry to Unicode. */
|
||||
uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len,
|
||||
&uname);
|
||||
if (uname_len < 0) {
|
||||
ntfs_error(vol->sb, "Failed to convert name to Unicode.");
|
||||
return ERR_PTR(uname_len);
|
||||
}
|
||||
mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len,
|
||||
&name);
|
||||
kmem_cache_free(ntfs_name_cache, uname);
|
||||
if (!IS_ERR_MREF(mref)) {
|
||||
dent_ino = MREF(mref);
|
||||
ntfs_debug("Found inode 0x%lx. Calling ntfs_iget.", dent_ino);
|
||||
dent_inode = ntfs_iget(vol->sb, dent_ino);
|
||||
if (likely(!IS_ERR(dent_inode))) {
|
||||
/* Consistency check. */
|
||||
if (MSEQNO(mref) == NTFS_I(dent_inode)->seq_no ||
|
||||
dent_ino == FILE_MFT) {
|
||||
/* Perfect WIN32/POSIX match. -- Case 1. */
|
||||
if (!name) {
|
||||
d_add(dent, dent_inode);
|
||||
ntfs_debug("Done.");
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* We are too indented. Handle imperfect
|
||||
* matches and short file names further below.
|
||||
*/
|
||||
goto handle_name;
|
||||
}
|
||||
ntfs_error(vol->sb, "Found stale reference to inode "
|
||||
"0x%lx (reference sequence number = "
|
||||
"0x%x, inode sequence number = 0x%x, "
|
||||
"returning -EIO. Run chkdsk.",
|
||||
dent_ino, MSEQNO(mref),
|
||||
NTFS_I(dent_inode)->seq_no);
|
||||
iput(dent_inode);
|
||||
dent_inode = ERR_PTR(-EIO);
|
||||
} else
|
||||
ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with "
|
||||
"error code %li.", dent_ino,
|
||||
PTR_ERR(dent_inode));
|
||||
if (name)
|
||||
kfree(name);
|
||||
/* Return the error code. */
|
||||
return (struct dentry *)dent_inode;
|
||||
}
|
||||
/* It is guaranteed that name is no longer allocated at this point. */
|
||||
if (MREF_ERR(mref) == -ENOENT) {
|
||||
ntfs_debug("Entry was not found, adding negative dentry.");
|
||||
/* The dcache will handle negative entries. */
|
||||
d_add(dent, NULL);
|
||||
ntfs_debug("Done.");
|
||||
return NULL;
|
||||
}
|
||||
ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error "
|
||||
"code %i.", -MREF_ERR(mref));
|
||||
return ERR_PTR(MREF_ERR(mref));
|
||||
|
||||
// TODO: Consider moving this lot to a separate function! (AIA)
|
||||
handle_name:
|
||||
{
|
||||
struct dentry *real_dent;
|
||||
MFT_RECORD *m;
|
||||
attr_search_context *ctx;
|
||||
ntfs_inode *ni = NTFS_I(dent_inode);
|
||||
int err;
|
||||
struct qstr nls_name;
|
||||
|
||||
nls_name.name = NULL;
|
||||
if (name->type != FILE_NAME_DOS) { /* Case 2. */
|
||||
nls_name.len = (unsigned)ntfs_ucstonls(vol,
|
||||
(uchar_t*)&name->name, name->len,
|
||||
(unsigned char**)&nls_name.name,
|
||||
name->len * 3 + 1);
|
||||
kfree(name);
|
||||
} else /* if (name->type == FILE_NAME_DOS) */ { /* Case 3. */
|
||||
FILE_NAME_ATTR *fn;
|
||||
|
||||
kfree(name);
|
||||
|
||||
/* Find the WIN32 name corresponding to the matched DOS name. */
|
||||
ni = NTFS_I(dent_inode);
|
||||
m = map_mft_record(ni);
|
||||
if (IS_ERR(m)) {
|
||||
err = PTR_ERR(m);
|
||||
m = NULL;
|
||||
ctx = NULL;
|
||||
goto err_out;
|
||||
}
|
||||
ctx = get_attr_search_ctx(ni, m);
|
||||
if (!ctx) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
do {
|
||||
ATTR_RECORD *a;
|
||||
u32 val_len;
|
||||
|
||||
if (!lookup_attr(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0,
|
||||
ctx)) {
|
||||
ntfs_error(vol->sb, "Inode corrupt: No WIN32 "
|
||||
"namespace counterpart to DOS "
|
||||
"file name. Run chkdsk.");
|
||||
err = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
/* Consistency checks. */
|
||||
a = ctx->attr;
|
||||
if (a->non_resident || a->flags)
|
||||
goto eio_err_out;
|
||||
val_len = le32_to_cpu(a->data.resident.value_length);
|
||||
if (le16_to_cpu(a->data.resident.value_offset) +
|
||||
val_len > le32_to_cpu(a->length))
|
||||
goto eio_err_out;
|
||||
fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
|
||||
ctx->attr->data.resident.value_offset));
|
||||
if ((u32)(fn->file_name_length * sizeof(uchar_t) +
|
||||
sizeof(FILE_NAME_ATTR)) > val_len)
|
||||
goto eio_err_out;
|
||||
} while (fn->file_name_type != FILE_NAME_WIN32);
|
||||
|
||||
/* Convert the found WIN32 name to current NLS code page. */
|
||||
nls_name.len = (unsigned)ntfs_ucstonls(vol,
|
||||
(uchar_t*)&fn->file_name, fn->file_name_length,
|
||||
(unsigned char**)&nls_name.name,
|
||||
fn->file_name_length * 3 + 1);
|
||||
|
||||
put_attr_search_ctx(ctx);
|
||||
unmap_mft_record(ni);
|
||||
}
|
||||
m = NULL;
|
||||
ctx = NULL;
|
||||
|
||||
/* Check if a conversion error occurred. */
|
||||
if ((signed)nls_name.len < 0) {
|
||||
err = (signed)nls_name.len;
|
||||
goto err_out;
|
||||
}
|
||||
nls_name.hash = full_name_hash(nls_name.name, nls_name.len);
|
||||
|
||||
/*
|
||||
* Note: No need for dent->d_lock lock as i_sem is held on the
|
||||
* parent inode.
|
||||
*/
|
||||
|
||||
/* Does a dentry matching the nls_name exist already? */
|
||||
real_dent = d_lookup(dent->d_parent, &nls_name);
|
||||
/* If not, create it now. */
|
||||
if (!real_dent) {
|
||||
real_dent = d_alloc(dent->d_parent, &nls_name);
|
||||
kfree(nls_name.name);
|
||||
if (!real_dent) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
d_add(real_dent, dent_inode);
|
||||
return real_dent;
|
||||
}
|
||||
kfree(nls_name.name);
|
||||
/* Matching dentry exists, check if it is negative. */
|
||||
if (real_dent->d_inode) {
|
||||
BUG_ON(real_dent->d_inode != dent_inode);
|
||||
/*
|
||||
* Already have the inode and the dentry attached, decrement
|
||||
* the reference count to balance the ntfs_iget() we did
|
||||
* earlier on.
|
||||
*/
|
||||
iput(dent_inode);
|
||||
return real_dent;
|
||||
}
|
||||
/* Negative dentry: instantiate it. */
|
||||
d_instantiate(real_dent, dent_inode);
|
||||
return real_dent;
|
||||
|
||||
eio_err_out:
|
||||
ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
|
||||
err = -EIO;
|
||||
err_out:
|
||||
if (ctx)
|
||||
put_attr_search_ctx(ctx);
|
||||
if (m)
|
||||
unmap_mft_record(ni);
|
||||
iput(dent_inode);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Inode operations for directories.
|
||||
*/
|
||||
struct inode_operations ntfs_dir_inode_ops = {
|
||||
.lookup = ntfs_lookup, /* VFS: Lookup directory. */
|
||||
};
|
||||
|
217
reactos/drivers/fs/ntfs/linux-ntfs/ntfs.h
Normal file
217
reactos/drivers/fs/ntfs/linux-ntfs/ntfs.h
Normal file
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* ntfs.h - Defines for NTFS Linux kernel driver. Part of the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2001,2002 Anton Altaparmakov.
|
||||
* Copyright (C) 2002 Richard Russon.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_H
|
||||
#define _LINUX_NTFS_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/smp.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "malloc.h"
|
||||
#include "endian.h"
|
||||
#include "volume.h"
|
||||
#include "inode.h"
|
||||
#include "layout.h"
|
||||
#include "attrib.h"
|
||||
#include "mft.h"
|
||||
|
||||
typedef enum {
|
||||
NTFS_BLOCK_SIZE = 512,
|
||||
NTFS_BLOCK_SIZE_BITS = 9,
|
||||
NTFS_SB_MAGIC = 0x5346544e, /* 'NTFS' */
|
||||
NTFS_MAX_NAME_LEN = 255,
|
||||
} NTFS_CONSTANTS;
|
||||
|
||||
/* Global variables. */
|
||||
|
||||
/* Slab caches (from super.c). */
|
||||
extern kmem_cache_t *ntfs_name_cache;
|
||||
extern kmem_cache_t *ntfs_inode_cache;
|
||||
extern kmem_cache_t *ntfs_big_inode_cache;
|
||||
extern kmem_cache_t *ntfs_attr_ctx_cache;
|
||||
|
||||
/* The various operations structs defined throughout the driver files. */
|
||||
extern struct super_operations ntfs_sops;
|
||||
extern struct super_operations ntfs_mount_sops;
|
||||
|
||||
extern struct address_space_operations ntfs_aops;
|
||||
extern struct address_space_operations ntfs_mft_aops;
|
||||
|
||||
extern struct file_operations ntfs_file_ops;
|
||||
extern struct inode_operations ntfs_file_inode_ops;
|
||||
|
||||
extern struct file_operations ntfs_dir_ops;
|
||||
extern struct inode_operations ntfs_dir_inode_ops;
|
||||
|
||||
extern struct file_operations ntfs_empty_file_ops;
|
||||
extern struct inode_operations ntfs_empty_inode_ops;
|
||||
|
||||
/* Generic macro to convert pointers to values for comparison purposes. */
|
||||
#ifndef p2n
|
||||
#define p2n(p) ((ptrdiff_t)((ptrdiff_t*)(p)))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* NTFS_SB - return the ntfs volume given a vfs super block
|
||||
* @sb: VFS super block
|
||||
*
|
||||
* NTFS_SB() returns the ntfs volume associated with the VFS super block @sb.
|
||||
*/
|
||||
static inline ntfs_volume *NTFS_SB(struct super_block *sb)
|
||||
{
|
||||
return sb->s_fs_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_unmap_page - release a page that was mapped using ntfs_map_page()
|
||||
* @page: the page to release
|
||||
*
|
||||
* Unpin, unmap and release a page that was obtained from ntfs_map_page().
|
||||
*/
|
||||
static inline void ntfs_unmap_page(struct page *page)
|
||||
{
|
||||
kunmap(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_map_page - map a page into accessible memory, reading it if necessary
|
||||
* @mapping: address space for which to obtain the page
|
||||
* @index: index into the page cache for @mapping of the page to map
|
||||
*
|
||||
* Read a page from the page cache of the address space @mapping at position
|
||||
* @index, where @index is in units of PAGE_CACHE_SIZE, and not in bytes.
|
||||
*
|
||||
* If the page is not in memory it is loaded from disk first using the readpage
|
||||
* method defined in the address space operations of @mapping and the page is
|
||||
* added to the page cache of @mapping in the process.
|
||||
*
|
||||
* If the page is in high memory it is mapped into memory directly addressible
|
||||
* by the kernel.
|
||||
*
|
||||
* Finally the page count is incremented, thus pinning the page into place.
|
||||
*
|
||||
* The above means that page_address(page) can be used on all pages obtained
|
||||
* with ntfs_map_page() to get the kernel virtual address of the page.
|
||||
*
|
||||
* When finished with the page, the caller has to call ntfs_unmap_page() to
|
||||
* unpin, unmap and release the page.
|
||||
*
|
||||
* Note this does not grant exclusive access. If such is desired, the caller
|
||||
* must provide it independently of the ntfs_{un}map_page() calls by using
|
||||
* a {rw_}semaphore or other means of serialization. A spin lock cannot be
|
||||
* used as ntfs_map_page() can block.
|
||||
*
|
||||
* The unlocked and uptodate page is returned on success or an encoded error
|
||||
* on failure. Caller has to test for error using the IS_ERR() macro on the
|
||||
* return value. If that evaluates to TRUE, the negative error code can be
|
||||
* obtained using PTR_ERR() on the return value of ntfs_map_page().
|
||||
*/
|
||||
static inline struct page *ntfs_map_page(struct address_space *mapping,
|
||||
unsigned long index)
|
||||
{
|
||||
struct page *page = read_cache_page(mapping, index,
|
||||
(filler_t*)mapping->a_ops->readpage, NULL);
|
||||
|
||||
if (!IS_ERR(page)) {
|
||||
wait_on_page_locked(page);
|
||||
kmap(page);
|
||||
if (PageUptodate(page) && !PageError(page))
|
||||
return page;
|
||||
ntfs_unmap_page(page);
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
/* Declarations of functions and global variables. */
|
||||
|
||||
/* From fs/ntfs/compress.c */
|
||||
extern int ntfs_read_compressed_block(struct page *page);
|
||||
|
||||
/* From fs/ntfs/super.c */
|
||||
#define default_upcase_len 0x10000
|
||||
extern wchar_t *default_upcase;
|
||||
extern unsigned long ntfs_nr_upcase_users;
|
||||
extern unsigned long ntfs_nr_mounts;
|
||||
extern struct semaphore ntfs_lock;
|
||||
|
||||
typedef struct {
|
||||
int val;
|
||||
char *str;
|
||||
} option_t;
|
||||
extern const option_t on_errors_arr[];
|
||||
|
||||
/* From fs/ntfs/compress.c */
|
||||
extern int allocate_compression_buffers(void);
|
||||
extern void free_compression_buffers(void);
|
||||
|
||||
/* From fs/ntfs/mst.c */
|
||||
extern int post_read_mst_fixup(NTFS_RECORD *b, const u32 size);
|
||||
extern int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size);
|
||||
extern void post_write_mst_fixup(NTFS_RECORD *b);
|
||||
|
||||
/* From fs/ntfs/time.c */
|
||||
extern inline s64 utc2ntfs(const time_t time);
|
||||
extern inline s64 get_current_ntfs_time(void);
|
||||
extern inline time_t ntfs2utc(const s64 time);
|
||||
|
||||
/* From fs/ntfs/unistr.c */
|
||||
extern BOOL ntfs_are_names_equal(const uchar_t *s1, size_t s1_len,
|
||||
const uchar_t *s2, size_t s2_len,
|
||||
const IGNORE_CASE_BOOL ic,
|
||||
const uchar_t *upcase, const u32 upcase_size);
|
||||
extern int ntfs_collate_names(const uchar_t *name1, const u32 name1_len,
|
||||
const uchar_t *name2, const u32 name2_len,
|
||||
const int err_val, const IGNORE_CASE_BOOL ic,
|
||||
const uchar_t *upcase, const u32 upcase_len);
|
||||
extern int ntfs_ucsncmp(const uchar_t *s1, const uchar_t *s2, size_t n);
|
||||
extern int ntfs_ucsncasecmp(const uchar_t *s1, const uchar_t *s2, size_t n,
|
||||
const uchar_t *upcase, const u32 upcase_size);
|
||||
extern void ntfs_upcase_name(uchar_t *name, u32 name_len,
|
||||
const uchar_t *upcase, const u32 upcase_len);
|
||||
extern void ntfs_file_upcase_value(FILE_NAME_ATTR *file_name_attr,
|
||||
const uchar_t *upcase, const u32 upcase_len);
|
||||
extern int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1,
|
||||
FILE_NAME_ATTR *file_name_attr2,
|
||||
const int err_val, const IGNORE_CASE_BOOL ic,
|
||||
const uchar_t *upcase, const u32 upcase_len);
|
||||
extern int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
|
||||
const int ins_len, uchar_t **outs);
|
||||
extern int ntfs_ucstonls(const ntfs_volume *vol, const uchar_t *ins,
|
||||
const int ins_len, unsigned char **outs, int outs_len);
|
||||
|
||||
/* From fs/ntfs/upcase.c */
|
||||
extern uchar_t *generate_default_upcase(void);
|
||||
|
||||
#endif /* _LINUX_NTFS_H */
|
||||
|
1806
reactos/drivers/fs/ntfs/linux-ntfs/super.c
Normal file
1806
reactos/drivers/fs/ntfs/linux-ntfs/super.c
Normal file
File diff suppressed because it is too large
Load diff
86
reactos/drivers/fs/ntfs/linux-ntfs/sysctl.c
Normal file
86
reactos/drivers/fs/ntfs/linux-ntfs/sysctl.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* sysctl.c - Code for sysctl handling in NTFS Linux kernel driver. Part of
|
||||
* the Linux-NTFS project. Adapted from the old NTFS driver,
|
||||
* Copyright (C) 1997 Martin von Löwis, Régis Duchesne.
|
||||
*
|
||||
* Copyright (c) 2002 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/sysctl.h>
|
||||
|
||||
#include "sysctl.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define FS_NTFS 1
|
||||
|
||||
/* Definition of the ntfs sysctl. */
|
||||
static ctl_table ntfs_sysctls[] = {
|
||||
{ FS_NTFS, "ntfs-debug", /* Binary and text IDs. */
|
||||
&debug_msgs,sizeof(debug_msgs), /* Data pointer and size. */
|
||||
0644, NULL, &proc_dointvec }, /* Mode, child, proc handler. */
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/* Define the parent directory /proc/sys/fs. */
|
||||
static ctl_table sysctls_root[] = {
|
||||
{ CTL_FS, "fs", NULL, 0, 0555, ntfs_sysctls },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/* Storage for the sysctls header. */
|
||||
static struct ctl_table_header *sysctls_root_table = NULL;
|
||||
|
||||
/**
|
||||
* ntfs_sysctl - add or remove the debug sysctl
|
||||
* @add: add (1) or remove (0) the sysctl
|
||||
*
|
||||
* Add or remove the debug sysctl. Return 0 on success or -errno on error.
|
||||
*/
|
||||
int ntfs_sysctl(int add)
|
||||
{
|
||||
if (add) {
|
||||
BUG_ON(sysctls_root_table);
|
||||
sysctls_root_table = register_sysctl_table(sysctls_root, 0);
|
||||
if (!sysctls_root_table)
|
||||
return -ENOMEM;
|
||||
#ifdef CONFIG_PROC_FS
|
||||
/*
|
||||
* If the proc file system is in use and we are a module, need
|
||||
* to set the owner of our proc entry to our module. In the
|
||||
* non-modular case, THIS_MODULE is NULL, so this is ok.
|
||||
*/
|
||||
ntfs_sysctls[0].de->owner = THIS_MODULE;
|
||||
#endif
|
||||
} else {
|
||||
BUG_ON(!sysctls_root_table);
|
||||
unregister_sysctl_table(sysctls_root_table);
|
||||
sysctls_root_table = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SYSCTL */
|
||||
#endif /* DEBUG */
|
||||
|
43
reactos/drivers/fs/ntfs/linux-ntfs/sysctl.h
Normal file
43
reactos/drivers/fs/ntfs/linux-ntfs/sysctl.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* sysctl.h - Defines for sysctl handling in NTFS Linux kernel driver. Part of
|
||||
* the Linux-NTFS project. Adapted from the old NTFS driver,
|
||||
* Copyright (C) 1997 Martin von Löwis, Régis Duchesne.
|
||||
*
|
||||
* Copyright (c) 2002 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_SYSCTL_H
|
||||
#define _LINUX_NTFS_SYSCTL_H
|
||||
|
||||
#include <linux/config.h>
|
||||
|
||||
#if (DEBUG && CONFIG_SYSCTL)
|
||||
|
||||
extern int ntfs_sysctl(int add);
|
||||
|
||||
#else
|
||||
|
||||
/* Just return success. */
|
||||
static inline int ntfs_sysctl(int add)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* DEBUG && CONFIG_SYSCTL */
|
||||
#endif /* _LINUX_NTFS_SYSCTL_H */
|
||||
|
82
reactos/drivers/fs/ntfs/linux-ntfs/time.c
Normal file
82
reactos/drivers/fs/ntfs/linux-ntfs/time.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* time.c - NTFS time conversion functions. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/sched.h> /* For CURRENT_TIME. */
|
||||
#include <asm/div64.h> /* For do_div(). */
|
||||
|
||||
#include "ntfs.h"
|
||||
|
||||
#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
|
||||
|
||||
/**
|
||||
* utc2ntfs - convert Linux time to NTFS time
|
||||
* @time: Linux time to convert to NTFS
|
||||
*
|
||||
* Convert the Linux time @time to its corresponding NTFS time and return that
|
||||
* in little endian format.
|
||||
*
|
||||
* Linux stores time in a long at present and measures it as the number of
|
||||
* 1-second intervals since 1st January 1970, 00:00:00 UTC.
|
||||
*
|
||||
* NTFS uses Microsoft's standard time format which is stored in a s64 and is
|
||||
* measured as the number of 100 nano-second intervals since 1st January 1601,
|
||||
* 00:00:00 UTC.
|
||||
*/
|
||||
inline s64 utc2ntfs(const time_t time)
|
||||
{
|
||||
/* Convert to 100ns intervals and then add the NTFS time offset. */
|
||||
return cpu_to_sle64((s64)time * 10000000 + NTFS_TIME_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_current_ntfs_time - get the current time in little endian NTFS format
|
||||
*
|
||||
* Get the current time from the Linux kernel, convert it to its corresponding
|
||||
* NTFS time and return that in little endian format.
|
||||
*/
|
||||
inline s64 get_current_ntfs_time(void)
|
||||
{
|
||||
/* ignores leap second */
|
||||
return utc2ntfs(get_seconds()) + xtime.tv_nsec/1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs2utc - convert NTFS time to Linux time
|
||||
* @time: NTFS time (little endian) to convert to Linux
|
||||
*
|
||||
* Convert the little endian NTFS time @time to its corresponding Linux time
|
||||
* and return that in cpu format.
|
||||
*
|
||||
* Linux stores time in a long at present and measures it as the number of
|
||||
* 1-second intervals since 1st January 1970, 00:00:00 UTC.
|
||||
*
|
||||
* NTFS uses Microsoft's standard time format which is stored in a s64 and is
|
||||
* measured as the number of 100 nano-second intervals since 1st January 1601,
|
||||
* 00:00:00 UTC.
|
||||
*/
|
||||
inline time_t ntfs2utc(const s64 time)
|
||||
{
|
||||
/* Subtract the NTFS time offset, then convert to 1s intervals. */
|
||||
s64 t = sle64_to_cpu(time) - NTFS_TIME_OFFSET;
|
||||
do_div(t, 10000000);
|
||||
return (time_t)t;
|
||||
}
|
||||
|
84
reactos/drivers/fs/ntfs/linux-ntfs/types.h
Normal file
84
reactos/drivers/fs/ntfs/linux-ntfs/types.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* types.h - Defines for NTFS Linux kernel driver specific types.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001,2002 Anton Altaparmakov.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_TYPES_H
|
||||
#define _LINUX_NTFS_TYPES_H
|
||||
|
||||
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
|
||||
#define SN(X) X /* Struct Name */
|
||||
#define SC(P,N) P.N /* ShortCut: Prefix, Name */
|
||||
#else
|
||||
#define SN(X)
|
||||
#define SC(P,N) N
|
||||
#endif
|
||||
|
||||
/* 2-byte Unicode character type. */
|
||||
typedef u16 uchar_t;
|
||||
#define UCHAR_T_SIZE_BITS 1
|
||||
|
||||
/*
|
||||
* Clusters are signed 64-bit values on NTFS volumes. We define two types, LCN
|
||||
* and VCN, to allow for type checking and better code readability.
|
||||
*/
|
||||
typedef s64 VCN;
|
||||
typedef s64 LCN;
|
||||
|
||||
/**
|
||||
* run_list_element - in memory vcn to lcn mapping array element
|
||||
* @vcn: starting vcn of the current array element
|
||||
* @lcn: starting lcn of the current array element
|
||||
* @length: length in clusters of the current array element
|
||||
*
|
||||
* The last vcn (in fact the last vcn + 1) is reached when length == 0.
|
||||
*
|
||||
* When lcn == -1 this means that the count vcns starting at vcn are not
|
||||
* physically allocated (i.e. this is a hole / data is sparse).
|
||||
*/
|
||||
typedef struct { /* In memory vcn to lcn mapping structure element. */
|
||||
VCN vcn; /* vcn = Starting virtual cluster number. */
|
||||
LCN lcn; /* lcn = Starting logical cluster number. */
|
||||
s64 length; /* Run length in clusters. */
|
||||
} run_list_element;
|
||||
|
||||
/**
|
||||
* run_list - in memory vcn to lcn mapping array including a read/write lock
|
||||
* @rl: pointer to an array of run list elements
|
||||
* @lock: read/write spinlock for serializing access to @rl
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
run_list_element *rl;
|
||||
struct rw_semaphore lock;
|
||||
} run_list;
|
||||
|
||||
typedef enum {
|
||||
FALSE = 0,
|
||||
TRUE = 1
|
||||
} BOOL;
|
||||
|
||||
typedef enum {
|
||||
CASE_SENSITIVE = 0,
|
||||
IGNORE_CASE = 1,
|
||||
} IGNORE_CASE_BOOL;
|
||||
|
||||
#endif /* _LINUX_NTFS_TYPES_H */
|
||||
|
383
reactos/drivers/fs/ntfs/linux-ntfs/unistr.c
Normal file
383
reactos/drivers/fs/ntfs/linux-ntfs/unistr.c
Normal file
|
@ -0,0 +1,383 @@
|
|||
/*
|
||||
* unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2003 Anton Altaparmakov
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ntfs.h"
|
||||
|
||||
/*
|
||||
* IMPORTANT
|
||||
* =========
|
||||
*
|
||||
* All these routines assume that the Unicode characters are in little endian
|
||||
* encoding inside the strings!!!
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is used by the name collation functions to quickly determine what
|
||||
* characters are (in)valid.
|
||||
*/
|
||||
static const u8 legal_ansi_char_array[0x40] = {
|
||||
0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
|
||||
0x17, 0x07, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17,
|
||||
0x17, 0x17, 0x18, 0x16, 0x16, 0x17, 0x07, 0x00,
|
||||
|
||||
0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
|
||||
0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18,
|
||||
};
|
||||
|
||||
/**
|
||||
* ntfs_are_names_equal - compare two Unicode names for equality
|
||||
* @s1: name to compare to @s2
|
||||
* @s1_len: length in Unicode characters of @s1
|
||||
* @s2: name to compare to @s1
|
||||
* @s2_len: length in Unicode characters of @s2
|
||||
* @ic: ignore case bool
|
||||
* @upcase: upcase table (only if @ic == IGNORE_CASE)
|
||||
* @upcase_size: length in Unicode characters of @upcase (if present)
|
||||
*
|
||||
* Compare the names @s1 and @s2 and return TRUE (1) if the names are
|
||||
* identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE,
|
||||
* the @upcase table is used to performa a case insensitive comparison.
|
||||
*/
|
||||
BOOL ntfs_are_names_equal(const uchar_t *s1, size_t s1_len,
|
||||
const uchar_t *s2, size_t s2_len,
|
||||
const IGNORE_CASE_BOOL ic,
|
||||
const uchar_t *upcase, const u32 upcase_size)
|
||||
{
|
||||
if (s1_len != s2_len)
|
||||
return FALSE;
|
||||
if (ic == CASE_SENSITIVE)
|
||||
return !ntfs_ucsncmp(s1, s2, s1_len);
|
||||
return !ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_collate_names - collate two Unicode names
|
||||
* @name1: first Unicode name to compare
|
||||
* @name2: second Unicode name to compare
|
||||
* @err_val: if @name1 contains an invalid character return this value
|
||||
* @ic: either CASE_SENSITIVE or IGNORE_CASE
|
||||
* @upcase: upcase table (ignored if @ic is CASE_SENSITIVE)
|
||||
* @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE)
|
||||
*
|
||||
* ntfs_collate_names collates two Unicode names and returns:
|
||||
*
|
||||
* -1 if the first name collates before the second one,
|
||||
* 0 if the names match,
|
||||
* 1 if the second name collates before the first one, or
|
||||
* @err_val if an invalid character is found in @name1 during the comparison.
|
||||
*
|
||||
* The following characters are considered invalid: '"', '*', '<', '>' and '?'.
|
||||
*/
|
||||
int ntfs_collate_names(const uchar_t *name1, const u32 name1_len,
|
||||
const uchar_t *name2, const u32 name2_len,
|
||||
const int err_val, const IGNORE_CASE_BOOL ic,
|
||||
const uchar_t *upcase, const u32 upcase_len)
|
||||
{
|
||||
u32 cnt, min_len;
|
||||
uchar_t c1, c2;
|
||||
|
||||
min_len = name1_len;
|
||||
if (name1_len > name2_len)
|
||||
min_len = name2_len;
|
||||
for (cnt = 0; cnt < min_len; ++cnt) {
|
||||
c1 = le16_to_cpu(*name1++);
|
||||
c2 = le16_to_cpu(*name2++);
|
||||
if (ic) {
|
||||
if (c1 < upcase_len)
|
||||
c1 = le16_to_cpu(upcase[c1]);
|
||||
if (c2 < upcase_len)
|
||||
c2 = le16_to_cpu(upcase[c2]);
|
||||
}
|
||||
if (c1 < 64 && legal_ansi_char_array[c1] & 8)
|
||||
return err_val;
|
||||
if (c1 < c2)
|
||||
return -1;
|
||||
if (c1 > c2)
|
||||
return 1;
|
||||
}
|
||||
if (name1_len < name2_len)
|
||||
return -1;
|
||||
if (name1_len == name2_len)
|
||||
return 0;
|
||||
/* name1_len > name2_len */
|
||||
c1 = le16_to_cpu(*name1);
|
||||
if (c1 < 64 && legal_ansi_char_array[c1] & 8)
|
||||
return err_val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ucsncmp - compare two little endian Unicode strings
|
||||
* @s1: first string
|
||||
* @s2: second string
|
||||
* @n: maximum unicode characters to compare
|
||||
*
|
||||
* Compare the first @n characters of the Unicode strings @s1 and @s2,
|
||||
* The strings in little endian format and appropriate le16_to_cpu()
|
||||
* conversion is performed on non-little endian machines.
|
||||
*
|
||||
* The function returns an integer less than, equal to, or greater than zero
|
||||
* if @s1 (or the first @n Unicode characters thereof) is found, respectively,
|
||||
* to be less than, to match, or be greater than @s2.
|
||||
*/
|
||||
int ntfs_ucsncmp(const uchar_t *s1, const uchar_t *s2, size_t n)
|
||||
{
|
||||
uchar_t c1, c2;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
c1 = le16_to_cpu(s1[i]);
|
||||
c2 = le16_to_cpu(s2[i]);
|
||||
if (c1 < c2)
|
||||
return -1;
|
||||
if (c1 > c2)
|
||||
return 1;
|
||||
if (!c1)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ucsncasecmp - compare two little endian Unicode strings, ignoring case
|
||||
* @s1: first string
|
||||
* @s2: second string
|
||||
* @n: maximum unicode characters to compare
|
||||
* @upcase: upcase table
|
||||
* @upcase_size: upcase table size in Unicode characters
|
||||
*
|
||||
* Compare the first @n characters of the Unicode strings @s1 and @s2,
|
||||
* ignoring case. The strings in little endian format and appropriate
|
||||
* le16_to_cpu() conversion is performed on non-little endian machines.
|
||||
*
|
||||
* Each character is uppercased using the @upcase table before the comparison.
|
||||
*
|
||||
* The function returns an integer less than, equal to, or greater than zero
|
||||
* if @s1 (or the first @n Unicode characters thereof) is found, respectively,
|
||||
* to be less than, to match, or be greater than @s2.
|
||||
*/
|
||||
int ntfs_ucsncasecmp(const uchar_t *s1, const uchar_t *s2, size_t n,
|
||||
const uchar_t *upcase, const u32 upcase_size)
|
||||
{
|
||||
uchar_t c1, c2;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if ((c1 = le16_to_cpu(s1[i])) < upcase_size)
|
||||
c1 = le16_to_cpu(upcase[c1]);
|
||||
if ((c2 = le16_to_cpu(s2[i])) < upcase_size)
|
||||
c2 = le16_to_cpu(upcase[c2]);
|
||||
if (c1 < c2)
|
||||
return -1;
|
||||
if (c1 > c2)
|
||||
return 1;
|
||||
if (!c1)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ntfs_upcase_name(uchar_t *name, u32 name_len, const uchar_t *upcase,
|
||||
const u32 upcase_len)
|
||||
{
|
||||
u32 i;
|
||||
uchar_t u;
|
||||
|
||||
for (i = 0; i < name_len; i++)
|
||||
if ((u = le16_to_cpu(name[i])) < upcase_len)
|
||||
name[i] = upcase[u];
|
||||
}
|
||||
|
||||
void ntfs_file_upcase_value(FILE_NAME_ATTR *file_name_attr,
|
||||
const uchar_t *upcase, const u32 upcase_len)
|
||||
{
|
||||
ntfs_upcase_name((uchar_t*)&file_name_attr->file_name,
|
||||
file_name_attr->file_name_length, upcase, upcase_len);
|
||||
}
|
||||
|
||||
int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1,
|
||||
FILE_NAME_ATTR *file_name_attr2,
|
||||
const int err_val, const IGNORE_CASE_BOOL ic,
|
||||
const uchar_t *upcase, const u32 upcase_len)
|
||||
{
|
||||
return ntfs_collate_names((uchar_t*)&file_name_attr1->file_name,
|
||||
file_name_attr1->file_name_length,
|
||||
(uchar_t*)&file_name_attr2->file_name,
|
||||
file_name_attr2->file_name_length,
|
||||
err_val, ic, upcase, upcase_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_nlstoucs - convert NLS string to little endian Unicode string
|
||||
* @vol: ntfs volume which we are working with
|
||||
* @ins: input NLS string buffer
|
||||
* @ins_len: length of input string in bytes
|
||||
* @outs: on return contains the allocated output Unicode string buffer
|
||||
*
|
||||
* Convert the input string @ins, which is in whatever format the loaded NLS
|
||||
* map dictates, into a little endian, 2-byte Unicode string.
|
||||
*
|
||||
* This function allocates the string and the caller is responsible for
|
||||
* calling kmem_cache_free(ntfs_name_cache, @outs); when finished with it.
|
||||
*
|
||||
* On success the function returns the number of Unicode characters written to
|
||||
* the output string *@outs (>= 0), not counting the terminating Unicode NULL
|
||||
* character. *@outs is set to the allocated output string buffer.
|
||||
*
|
||||
* On error, a negative number corresponding to the error code is returned. In
|
||||
* that case the output string is not allocated. Both *@outs and *@outs_len
|
||||
* are then undefined.
|
||||
*
|
||||
* This might look a bit odd due to fast path optimization...
|
||||
*/
|
||||
int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
|
||||
const int ins_len, uchar_t **outs)
|
||||
{
|
||||
struct nls_table *nls = vol->nls_map;
|
||||
uchar_t *ucs;
|
||||
wchar_t wc;
|
||||
int i, o, wc_len;
|
||||
|
||||
/* We don't trust outside sources. */
|
||||
if (ins) {
|
||||
ucs = (uchar_t*)kmem_cache_alloc(ntfs_name_cache, SLAB_NOFS);
|
||||
if (ucs) {
|
||||
for (i = o = 0; i < ins_len; i += wc_len) {
|
||||
wc_len = nls->char2uni(ins + i, ins_len - i,
|
||||
&wc);
|
||||
if (wc_len >= 0) {
|
||||
if (wc) {
|
||||
ucs[o++] = cpu_to_le16(wc);
|
||||
continue;
|
||||
} /* else (!wc) */
|
||||
break;
|
||||
} /* else (wc_len < 0) */
|
||||
goto conversion_err;
|
||||
}
|
||||
ucs[o] = cpu_to_le16('\0');
|
||||
*outs = ucs;
|
||||
return o;
|
||||
} /* else (!ucs) */
|
||||
ntfs_error(vol->sb, "Failed to allocate name from "
|
||||
"ntfs_name_cache!");
|
||||
return -ENOMEM;
|
||||
} /* else (!ins) */
|
||||
ntfs_error(NULL, "Received NULL pointer.");
|
||||
return -EINVAL;
|
||||
conversion_err:
|
||||
ntfs_error(vol->sb, "Name using character set %s contains characters "
|
||||
"that cannot be converted to Unicode.", nls->charset);
|
||||
kmem_cache_free(ntfs_name_cache, ucs);
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ucstonls - convert little endian Unicode string to NLS string
|
||||
* @vol: ntfs volume which we are working with
|
||||
* @ins: input Unicode string buffer
|
||||
* @ins_len: length of input string in Unicode characters
|
||||
* @outs: on return contains the (allocated) output NLS string buffer
|
||||
* @outs_len: length of output string buffer in bytes
|
||||
*
|
||||
* Convert the input little endian, 2-byte Unicode string @ins, of length
|
||||
* @ins_len into the string format dictated by the loaded NLS.
|
||||
*
|
||||
* If @outs is NULL, this function allocates the string and the caller is
|
||||
* responsible for calling kfree(@outs); when finished with it.
|
||||
*
|
||||
* On success the function returns the number of bytes written to the output
|
||||
* string *@outs (>= 0), not counting the terminating NULL byte. If the output
|
||||
* string buffer was allocated, *@outs is set to it.
|
||||
*
|
||||
* On error, a negative number corresponding to the error code is returned. In
|
||||
* that case the output string is not allocated. The contents of *@outs are
|
||||
* then undefined.
|
||||
*
|
||||
* This might look a bit odd due to fast path optimization...
|
||||
*/
|
||||
int ntfs_ucstonls(const ntfs_volume *vol, const uchar_t *ins,
|
||||
const int ins_len, unsigned char **outs, int outs_len)
|
||||
{
|
||||
struct nls_table *nls = vol->nls_map;
|
||||
unsigned char *ns;
|
||||
int i, o, ns_len, wc;
|
||||
|
||||
/* We don't trust outside sources. */
|
||||
if (ins) {
|
||||
ns = *outs;
|
||||
ns_len = outs_len;
|
||||
if (ns && !ns_len) {
|
||||
wc = -ENAMETOOLONG;
|
||||
goto conversion_err;
|
||||
}
|
||||
if (!ns) {
|
||||
ns_len = ins_len * NLS_MAX_CHARSET_SIZE;
|
||||
ns = (unsigned char*)kmalloc(ns_len + 1, GFP_NOFS);
|
||||
if (!ns)
|
||||
goto mem_err_out;
|
||||
}
|
||||
for (i = o = 0; i < ins_len; i++) {
|
||||
retry: wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o,
|
||||
ns_len - o);
|
||||
if (wc > 0) {
|
||||
o += wc;
|
||||
continue;
|
||||
} else if (!wc)
|
||||
break;
|
||||
else if (wc == -ENAMETOOLONG && ns != *outs) {
|
||||
unsigned char *tc;
|
||||
/* Grow in multiples of 64 bytes. */
|
||||
tc = (unsigned char*)kmalloc((ns_len + 64) &
|
||||
~63, GFP_NOFS);
|
||||
if (tc) {
|
||||
memcpy(tc, ns, ns_len);
|
||||
ns_len = ((ns_len + 64) & ~63) - 1;
|
||||
kfree(ns);
|
||||
ns = tc;
|
||||
goto retry;
|
||||
} /* No memory so goto conversion_error; */
|
||||
} /* wc < 0, real error. */
|
||||
goto conversion_err;
|
||||
}
|
||||
ns[o] = '\0';
|
||||
*outs = ns;
|
||||
return o;
|
||||
} /* else (!ins) */
|
||||
ntfs_error(vol->sb, "Received NULL pointer.");
|
||||
return -EINVAL;
|
||||
conversion_err:
|
||||
ntfs_error(vol->sb, "Unicode name contains characters that cannot be "
|
||||
"converted to character set %s.", nls->charset);
|
||||
if (ns != *outs)
|
||||
kfree(ns);
|
||||
if (wc != -ENAMETOOLONG)
|
||||
wc = -EILSEQ;
|
||||
return wc;
|
||||
mem_err_out:
|
||||
ntfs_error(vol->sb, "Failed to allocate name!");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
90
reactos/drivers/fs/ntfs/linux-ntfs/upcase.c
Normal file
90
reactos/drivers/fs/ntfs/linux-ntfs/upcase.c
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* upcase.c - Generate the full NTFS Unicode upcase table in little endian.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001 Richard Russon <ntfs@flatcap.org>
|
||||
* Copyright (c) 2001-2003 Anton Altaparmakov
|
||||
*
|
||||
* Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov.
|
||||
* Modified for kernel inclusion 10 September 2001 by Anton Altparmakov.
|
||||
*
|
||||
* 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 (in the main directory of the Linux-NTFS source
|
||||
* in the file COPYING); if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ntfs.h"
|
||||
|
||||
uchar_t *generate_default_upcase(void)
|
||||
{
|
||||
static const int uc_run_table[][3] = { /* Start, End, Add */
|
||||
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
|
||||
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
|
||||
{0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100},
|
||||
{0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128},
|
||||
{0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112},
|
||||
{0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126},
|
||||
{0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8},
|
||||
{0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8},
|
||||
{0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8},
|
||||
{0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7},
|
||||
{0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16},
|
||||
{0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26},
|
||||
{0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32},
|
||||
{0}
|
||||
};
|
||||
|
||||
static const int uc_dup_table[][2] = { /* Start, End */
|
||||
{0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC},
|
||||
{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
|
||||
{0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5},
|
||||
{0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9},
|
||||
{0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95},
|
||||
{0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9},
|
||||
{0}
|
||||
};
|
||||
|
||||
static const int uc_word_table[][2] = { /* Offset, Value */
|
||||
{0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196},
|
||||
{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
|
||||
{0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D},
|
||||
{0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F},
|
||||
{0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9},
|
||||
{0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE},
|
||||
{0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7},
|
||||
{0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197},
|
||||
{0}
|
||||
};
|
||||
|
||||
int i, r;
|
||||
uchar_t *uc;
|
||||
|
||||
uc = ntfs_malloc_nofs(default_upcase_len * sizeof(uchar_t));
|
||||
if (!uc)
|
||||
return uc;
|
||||
memset(uc, 0, default_upcase_len * sizeof(uchar_t));
|
||||
for (i = 0; i < default_upcase_len; i++)
|
||||
uc[i] = cpu_to_le16(i);
|
||||
for (r = 0; uc_run_table[r][0]; r++)
|
||||
for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++)
|
||||
uc[i] = cpu_to_le16((le16_to_cpu(uc[i]) +
|
||||
uc_run_table[r][2]));
|
||||
for (r = 0; uc_dup_table[r][0]; r++)
|
||||
for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2)
|
||||
uc[i + 1] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1);
|
||||
for (r = 0; uc_word_table[r][0]; r++)
|
||||
uc[uc_word_table[r][0]] = cpu_to_le16(uc_word_table[r][1]);
|
||||
return uc;
|
||||
}
|
||||
|
136
reactos/drivers/fs/ntfs/linux-ntfs/volume.h
Normal file
136
reactos/drivers/fs/ntfs/linux-ntfs/volume.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* volume.h - Defines for volume structures in NTFS Linux kernel driver. Part
|
||||
* of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001,2002 Anton Altaparmakov.
|
||||
* Copyright (c) 2002 Richard Russon.
|
||||
*
|
||||
* This program/include file 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/include file 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 (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_VOLUME_H
|
||||
#define _LINUX_NTFS_VOLUME_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
* The NTFS in memory super block structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/*
|
||||
* FIXME: Reorder to have commonly used together element within the
|
||||
* same cache line, aiming at a cache line size of 32 bytes. Aim for
|
||||
* 64 bytes for less commonly used together elements. Put most commonly
|
||||
* used elements to front of structure. Obviously do this only when the
|
||||
* structure has stabilized... (AIA)
|
||||
*/
|
||||
/* Device specifics. */
|
||||
struct super_block *sb; /* Pointer back to the super_block,
|
||||
so we don't have to get the offset
|
||||
every time. */
|
||||
LCN nr_blocks; /* Number of NTFS_BLOCK_SIZE bytes
|
||||
sized blocks on the device. */
|
||||
/* Configuration provided by user at mount time. */
|
||||
unsigned long flags; /* Miscellaneous flags, see above. */
|
||||
uid_t uid; /* uid that files will be mounted as. */
|
||||
gid_t gid; /* gid that files will be mounted as. */
|
||||
mode_t fmask; /* The mask for file permissions. */
|
||||
mode_t dmask; /* The mask for directory
|
||||
permissions. */
|
||||
u8 mft_zone_multiplier; /* Initial mft zone multiplier. */
|
||||
u8 on_errors; /* What to do on file system errors. */
|
||||
/* NTFS bootsector provided information. */
|
||||
u16 sector_size; /* in bytes */
|
||||
u8 sector_size_bits; /* log2(sector_size) */
|
||||
u32 cluster_size; /* in bytes */
|
||||
u32 cluster_size_mask; /* cluster_size - 1 */
|
||||
u8 cluster_size_bits; /* log2(cluster_size) */
|
||||
u32 mft_record_size; /* in bytes */
|
||||
u32 mft_record_size_mask; /* mft_record_size - 1 */
|
||||
u8 mft_record_size_bits; /* log2(mft_record_size) */
|
||||
u32 index_record_size; /* in bytes */
|
||||
u32 index_record_size_mask; /* index_record_size - 1 */
|
||||
u8 index_record_size_bits; /* log2(index_record_size) */
|
||||
LCN nr_clusters; /* Volume size in clusters == number of
|
||||
bits in lcn bitmap. */
|
||||
LCN mft_lcn; /* Cluster location of mft data. */
|
||||
LCN mftmirr_lcn; /* Cluster location of copy of mft. */
|
||||
u64 serial_no; /* The volume serial number. */
|
||||
/* Mount specific NTFS information. */
|
||||
u32 upcase_len; /* Number of entries in upcase[]. */
|
||||
uchar_t *upcase; /* The upcase table. */
|
||||
LCN mft_zone_start; /* First cluster of the mft zone. */
|
||||
LCN mft_zone_end; /* First cluster beyond the mft zone. */
|
||||
struct inode *mft_ino; /* The VFS inode of $MFT. */
|
||||
|
||||
struct inode *mftbmp_ino; /* Attribute inode for $MFT/$BITMAP. */
|
||||
struct rw_semaphore mftbmp_lock; /* Lock for serializing accesses to the
|
||||
mft record bitmap ($MFT/$BITMAP). */
|
||||
unsigned long nr_mft_records; /* Number of mft records == number of
|
||||
bits in mft bitmap. */
|
||||
|
||||
struct inode *mftmirr_ino; /* The VFS inode of $MFTMirr. */
|
||||
struct inode *lcnbmp_ino; /* The VFS inode of $Bitmap. */
|
||||
struct rw_semaphore lcnbmp_lock; /* Lock for serializing accesses to the
|
||||
cluster bitmap ($Bitmap/$DATA). */
|
||||
struct inode *vol_ino; /* The VFS inode of $Volume. */
|
||||
unsigned long vol_flags; /* Volume flags (VOLUME_*). */
|
||||
u8 major_ver; /* Ntfs major version of volume. */
|
||||
u8 minor_ver; /* Ntfs minor version of volume. */
|
||||
struct inode *root_ino; /* The VFS inode of the root
|
||||
directory. */
|
||||
struct inode *secure_ino; /* The VFS inode of $Secure (NTFS3.0+
|
||||
only, otherwise NULL). */
|
||||
struct nls_table *nls_map;
|
||||
} ntfs_volume;
|
||||
|
||||
/*
|
||||
* Defined bits for the flags field in the ntfs_volume structure.
|
||||
*/
|
||||
typedef enum {
|
||||
NV_Errors, /* 1: Volume has errors, prevent remount rw. */
|
||||
NV_ShowSystemFiles, /* 1: Return system files in ntfs_readdir(). */
|
||||
NV_CaseSensitive, /* 1: Treat file names as case sensitive and
|
||||
create filenames in the POSIX namespace.
|
||||
Otherwise be case insensitive and create
|
||||
file names in WIN32 namespace. */
|
||||
} ntfs_volume_flags;
|
||||
|
||||
/*
|
||||
* Macro tricks to expand the NVolFoo(), NVolSetFoo(), and NVolClearFoo()
|
||||
* functions.
|
||||
*/
|
||||
#define NVOL_FNS(flag) \
|
||||
static inline int NVol##flag(ntfs_volume *vol) \
|
||||
{ \
|
||||
return test_bit(NV_##flag, &(vol)->flags); \
|
||||
} \
|
||||
static inline void NVolSet##flag(ntfs_volume *vol) \
|
||||
{ \
|
||||
set_bit(NV_##flag, &(vol)->flags); \
|
||||
} \
|
||||
static inline void NVolClear##flag(ntfs_volume *vol) \
|
||||
{ \
|
||||
clear_bit(NV_##flag, &(vol)->flags); \
|
||||
}
|
||||
|
||||
/* Emit the ntfs volume bitops functions. */
|
||||
NVOL_FNS(Errors)
|
||||
NVOL_FNS(ShowSystemFiles)
|
||||
NVOL_FNS(CaseSensitive)
|
||||
|
||||
#endif /* _LINUX_NTFS_VOLUME_H */
|
||||
|
Loading…
Reference in a new issue