/* OCaml-Win32
 * win32_volume.c
 * Copyright (c) 2002-2004 by Harry Chomsky
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "win32.h"

/********************************************************************/
/* System Services: Files and I/O: SDK Documentation: Storage: Storage Reference: Volume Management Reference */

CAMLprim value get_drive_type(value root)
{
    CAMLparam1(root);
    char* r;
    UINT result;

    r = new_stringoption(root);
    enter_blocking_section();
    result = GetDriveType(r);
    leave_blocking_section();
    free_stringoption(r);
    CAMLreturn(Val_constant(result, drive_types));
}

CAMLprim value get_logical_drives(value unit)
{
    CAMLparam1(unit);
    DWORD mask, bit;
    CAMLlocal1(val);
    int i;

    enter_blocking_section();
    mask = GetLogicalDrives();
    leave_blocking_section();
    if (mask == 0)
        raise_last_error();
    val = alloc_tuple(32);
    for (i = 0, bit = 1; i < 32; ++i, bit <<= 1)
        Store_field(val, i, Val_bool((mask & bit) != 0));
    CAMLreturn(val);
}

CAMLprim value get_logical_drive_strings(value unit)
{
    CAMLparam1(unit);
    int len;
    char* buf;
    int n;
    char* p;
    CAMLlocal2(val, v);

    enter_blocking_section();
    len = GetLogicalDriveStrings(0, NULL);
    leave_blocking_section();
    if (len == 0)
        raise_last_error();
    buf = malloc(len);
    enter_blocking_section();
    len = GetLogicalDriveStrings(len, buf);
    leave_blocking_section();
    if (len == 0) {
        free(buf);
        raise_last_error();
    }
    n = 0;
    for (p = buf; *p; p += strlen(p) + 1)
        ++n;
    val = n > 0 ? alloc_tuple(n) : Atom(0);
    n = 0;
    for (p = buf; *p; p += strlen(p) + 1) {
        v = copy_string(p);
        Store_field(val, n, v);
        ++n;
    }
    free(buf);
    CAMLreturn(val);
}

static DWORD file_system_flags[] = {
    FILE_SUPPORTS_ENCRYPTION,
    FILE_SUPPORTS_OBJECT_IDS,
    FILE_SUPPORTS_REPARSE_POINTS,
    FILE_SUPPORTS_SPARSE_FILES,
    FILE_VOLUME_QUOTAS,
    FS_CASE_IS_PRESERVED,
    FS_CASE_SENSITIVE,
    FS_FILE_COMPRESSION,
    FS_PERSISTENT_ACLS,
    FS_UNICODE_STORED_ON_DISK,
    FS_VOL_IS_COMPRESSED
};
Define_static_constants(file_system_flags);

CAMLprim value get_volume_information(value path)
{
	CAMLparam1(path);
    char* p;
    DWORD serial, max_comp, fs_flags;
    char vol[_MAX_PATH+1], fs_name[_MAX_PATH+1];
    BOOL result;
    CAMLlocal2(val, v);

    p = new_stringoption(path);
    enter_blocking_section();
    result = GetVolumeInformation(p, vol, sizeof(vol), &serial, &max_comp, &fs_flags, fs_name, sizeof(fs_name));
    leave_blocking_section();
    free_stringoption(p);
    if (!result)
        raise_last_error();
    val = alloc_tuple(5);
    v = copy_string(vol);
    Store_field(val, 0, v);
    v = copy_int32(serial);
    Store_field(val, 1, v);
    Store_field(val, 2, Val_int(max_comp));
    v = Alloc_flags(fs_flags, file_system_flags);
    Store_field(val, 3, v);
    v = copy_string(fs_name);
    Store_field(val, 4, v);
    CAMLreturn(val);
}

CAMLprim value set_volume_label(value root, value label)
{
    CAMLparam2(root, label);
    char* r;
    char* l;
    BOOL result;

    r = new_stringoption(root);
    l = new_stringoption(label);
    enter_blocking_section();
    result = SetVolumeLabel(r, l);
    leave_blocking_section();
    free_stringoption(r);
    free_stringoption(l);
    if (!result)
        raise_last_error();
    CAMLreturn(Val_unit);
}
