alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (WindowsUserDefinedFileAttributeView.java)

This example Java source code file (WindowsUserDefinedFileAttributeView.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

backupread, bytebuffer, closehandle, filechannel, hashset, ioexception, list, nio, open_existing, override, set, sizeof_stream_header, string, util, windowschannelfactory, windowsexception

The WindowsUserDefinedFileAttributeView.java Java example source code

/*
 * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.nio.fs;

import java.nio.file.*;
import static java.nio.file.StandardOpenOption.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.io.IOException;
import java.util.*;
import sun.misc.Unsafe;

import static sun.nio.fs.WindowsNativeDispatcher.*;
import static sun.nio.fs.WindowsConstants.*;

/**
 * Windows emulation of NamedAttributeView using Alternative Data Streams
 */

class WindowsUserDefinedFileAttributeView
    extends AbstractUserDefinedFileAttributeView
{
    private static final Unsafe unsafe = Unsafe.getUnsafe();

    // syntax to address named streams
    private String join(String file, String name) {
        if (name == null)
            throw new NullPointerException("'name' is null");
        return file + ":" + name;
    }
    private String join(WindowsPath file, String name) throws WindowsException {
        return join(file.getPathForWin32Calls(), name);
    }

    private final WindowsPath file;
    private final boolean followLinks;

    WindowsUserDefinedFileAttributeView(WindowsPath file, boolean followLinks) {
        this.file = file;
        this.followLinks = followLinks;
    }

    // enumerates the file streams using FindFirstStream/FindNextStream APIs.
    private List<String> listUsingStreamEnumeration() throws IOException {
        List<String> list = new ArrayList<>();
        try {
            FirstStream first = FindFirstStream(file.getPathForWin32Calls());
            if (first != null) {
                long handle = first.handle();
                try {
                    // first stream is always ::$DATA for files
                    String name = first.name();
                    if (!name.equals("::$DATA")) {
                        String[] segs = name.split(":");
                        list.add(segs[1]);
                    }
                    while ((name = FindNextStream(handle)) != null) {
                        String[] segs = name.split(":");
                        list.add(segs[1]);
                    }
                } finally {
                    FindClose(handle);
                }
            }
        } catch (WindowsException x) {
            x.rethrowAsIOException(file);
        }
        return Collections.unmodifiableList(list);
    }

    // enumerates the file streams by reading the stream headers using
    // BackupRead
    private List<String> listUsingBackupRead() throws IOException {
        long handle = -1L;
        try {
            int flags = FILE_FLAG_BACKUP_SEMANTICS;
            if (!followLinks && file.getFileSystem().supportsLinks())
                flags |= FILE_FLAG_OPEN_REPARSE_POINT;

            handle = CreateFile(file.getPathForWin32Calls(),
                                GENERIC_READ,
                                FILE_SHARE_READ, // no write as we depend on file size
                                OPEN_EXISTING,
                                flags);
        } catch (WindowsException x) {
            x.rethrowAsIOException(file);
        }

        // buffer to read stream header and stream name.
        final int BUFFER_SIZE = 4096;
        NativeBuffer buffer = null;

        // result with names of alternative data streams
        final List<String> list = new ArrayList<>();

        try {
            buffer = NativeBuffers.getNativeBuffer(BUFFER_SIZE);
            long address = buffer.address();

            /**
             * typedef struct _WIN32_STREAM_ID {
             *     DWORD dwStreamId;
             *     DWORD dwStreamAttributes;
             *     LARGE_INTEGER Size;
             *     DWORD dwStreamNameSize;
             *     WCHAR cStreamName[ANYSIZE_ARRAY];
             * } WIN32_STREAM_ID;
             */
            final int SIZEOF_STREAM_HEADER      = 20;
            final int OFFSETOF_STREAM_ID        = 0;
            final int OFFSETOF_STREAM_SIZE      = 8;
            final int OFFSETOF_STREAM_NAME_SIZE = 16;

            long context = 0L;
            try {
                for (;;) {
                    // read stream header
                    BackupResult result = BackupRead(handle, address,
                       SIZEOF_STREAM_HEADER, false, context);
                    context = result.context();
                    if (result.bytesTransferred() == 0)
                        break;

                    int streamId = unsafe.getInt(address + OFFSETOF_STREAM_ID);
                    long streamSize = unsafe.getLong(address + OFFSETOF_STREAM_SIZE);
                    int nameSize = unsafe.getInt(address + OFFSETOF_STREAM_NAME_SIZE);

                    // read stream name
                    if (nameSize > 0) {
                        result = BackupRead(handle, address, nameSize, false, context);
                        if (result.bytesTransferred() != nameSize)
                            break;
                    }

                    // check for alternative data stream
                    if (streamId == BACKUP_ALTERNATE_DATA) {
                        char[] nameAsArray = new char[nameSize/2];
                        unsafe.copyMemory(null, address, nameAsArray,
                            Unsafe.ARRAY_CHAR_BASE_OFFSET, nameSize);

                        String[] segs = new String(nameAsArray).split(":");
                        if (segs.length == 3)
                            list.add(segs[1]);
                    }

                    // sparse blocks not currently handled as documentation
                    // is not sufficient on how the spase block can be skipped.
                    if (streamId == BACKUP_SPARSE_BLOCK) {
                        throw new IOException("Spare blocks not handled");
                    }

                    // seek to end of stream
                    if (streamSize > 0L) {
                        BackupSeek(handle, streamSize, context);
                    }
                }
            } catch (WindowsException x) {
                // failed to read or seek
                throw new IOException(x.errorString());
            } finally {
                // release context
                if (context != 0L) {
                   try {
                       BackupRead(handle, 0L, 0, true, context);
                   } catch (WindowsException ignore) { }
                }
            }
        } finally {
            if (buffer != null)
                buffer.release();
            CloseHandle(handle);
        }
        return Collections.unmodifiableList(list);
    }

    @Override
    public List<String> list() throws IOException  {
        if (System.getSecurityManager() != null)
            checkAccess(file.getPathForPermissionCheck(), true, false);
        // use stream APIs on Windwos Server 2003 and newer
        if (file.getFileSystem().supportsStreamEnumeration()) {
            return listUsingStreamEnumeration();
        } else {
            return listUsingBackupRead();
        }
    }

    @Override
    public int size(String name) throws IOException  {
        if (System.getSecurityManager() != null)
            checkAccess(file.getPathForPermissionCheck(), true, false);

        // wrap with channel
        FileChannel fc = null;
        try {
            Set<OpenOption> opts = new HashSet<>();
            opts.add(READ);
            if (!followLinks)
                opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
            fc = WindowsChannelFactory
                .newFileChannel(join(file, name), null, opts, 0L);
        } catch (WindowsException x) {
            x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
        }
        try {
            long size = fc.size();
            if (size > Integer.MAX_VALUE)
                throw new ArithmeticException("Stream too large");
            return (int)size;
        } finally {
            fc.close();
        }
    }

    @Override
    public int read(String name, ByteBuffer dst) throws IOException {
        if (System.getSecurityManager() != null)
            checkAccess(file.getPathForPermissionCheck(), true, false);

        // wrap with channel
        FileChannel fc = null;
        try {
            Set<OpenOption> opts = new HashSet<>();
            opts.add(READ);
            if (!followLinks)
                opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
            fc = WindowsChannelFactory
                .newFileChannel(join(file, name), null, opts, 0L);
        } catch (WindowsException x) {
            x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
        }

        // read to EOF (nothing we can do if I/O error occurs)
        try {
            if (fc.size() > dst.remaining())
                throw new IOException("Stream too large");
            int total = 0;
            while (dst.hasRemaining()) {
                int n = fc.read(dst);
                if (n < 0)
                    break;
                total += n;
            }
            return total;
        } finally {
            fc.close();
        }
    }

    @Override
    public int write(String name, ByteBuffer src) throws IOException {
        if (System.getSecurityManager() != null)
            checkAccess(file.getPathForPermissionCheck(), false, true);

        /**
         * Creating a named stream will cause the unnamed stream to be created
         * if it doesn't already exist. To avoid this we open the unnamed stream
         * for reading and hope it isn't deleted/moved while we create or
         * replace the named stream. Opening the file without sharing options
         * may cause sharing violations with other programs that are accessing
         * the unnamed stream.
         */
        long handle = -1L;
        try {
            int flags = FILE_FLAG_BACKUP_SEMANTICS;
            if (!followLinks)
                flags |= FILE_FLAG_OPEN_REPARSE_POINT;

            handle = CreateFile(file.getPathForWin32Calls(),
                                GENERIC_READ,
                                (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
                                OPEN_EXISTING,
                                flags);
        } catch (WindowsException x) {
            x.rethrowAsIOException(file);
        }
        try {
            Set<OpenOption> opts = new HashSet<>();
            if (!followLinks)
                opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
            opts.add(CREATE);
            opts.add(WRITE);
            opts.add(StandardOpenOption.TRUNCATE_EXISTING);
            FileChannel named = null;
            try {
                named = WindowsChannelFactory
                    .newFileChannel(join(file, name), null, opts, 0L);
            } catch (WindowsException x) {
                x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
            }
            // write value (nothing we can do if I/O error occurs)
            try {
                int rem = src.remaining();
                while (src.hasRemaining()) {
                    named.write(src);
                }
                return rem;
            } finally {
                named.close();
            }
        } finally {
            CloseHandle(handle);
        }
    }

    @Override
    public void delete(String name) throws IOException {
        if (System.getSecurityManager() != null)
            checkAccess(file.getPathForPermissionCheck(), false, true);

        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
        String toDelete = join(path, name);
        try {
            DeleteFile(toDelete);
        } catch (WindowsException x) {
            x.rethrowAsIOException(toDelete);
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java WindowsUserDefinedFileAttributeView.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.