EDIT: I don't have a good answer yet as to why I'm getting a failure here... So let me rephrase this a little. Do I even need the verify_area() check? What is the point of that? I have tested out the fact that my structure gets passed successfully to this ioctl, I'm thinking of just removing the failing check, but I'm not 100% what it's in there to do. Thoughts?
END EDIT
I'm working to update some older linux kernel drivers and while testing one out I'm getting a failure which seems odd to me. Here we go:
I have a simple ioctl call in user space:
Config_par_t cfg;
int ret;
cfg.target = CONF_TIMING;
cfg.val1 = nBaud;
ret = ioctl(fd, CAN_CONFIG, &cfg);
The Config_par_t is defined in can4linux.h file (this is the CAN driver that comes with uCLinux):
typedef struct Command_par {
int cmd; /**< special driver command */
int target; /**< special configuration target */
unsigned long val1; /**< 1. parameter for the target */
unsigned long val2; /**< 2. parameter for the target */
int error; /**< return value */
unsigned long retval; /**< return value */
} Command_par_t ;
In the kernel side of things, the ioctl function calls verify_area, which is the failing procedure:
long can_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void *argp;
long retval = -EIO;
Message_par_t Message;
Command_par_t Command;
struct inode *inode = file->f_path.dentry->d_inode;
argp = &Message;
Can_errno = 0;
switch(cmd) {
case CONFIG:
if( verify_area(VERIFY_READ, (void *) arg, sizeof(Command_par_t))) {
return(retval);
}
Now I know that verify_area() isn't used anymore so I updated it in a header file with this macro to access_ok:
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
#define verify_area(type, addr, size) access_ok(type, addr, size)
#endif
I'm on a x86 platform so I'm pretty sure the actual access_ok() macro being called is the one in /usr/src/linux/arch/x86/include/asm/uaccess.h as defined here:
#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))
#define __range_not_ok(addr, size) \
({ \
unsigned long flag, roksum; \
__chk_user_ptr(addr); \
asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \
: "=&r" (flag), "=r" (roksum) \
: "1" (addr), "g" ((long)(size)), \
"rm" (current_thread_info()->addr_limit.seg)); \
flag; \
})
I guess to me this looks like it should be working. Any ideas why I'm getting a 1 return from this verify_area if check? Or any ideas on how I can go about narrowing down the problem?
if( verify_area(VERIFY_READ, (void *) arg, sizeof(Command_par_t))) {
The macro access_ok returns 0 if the block is invalid and nonzero if it may be valid. So in your test, if the block is valid you immediately return -EIO. The way things look, you might want to negate the result of access_ok, something like:
if (!access_ok(...))
Related
I am working with the Renesas RA2A1 using their Flexible software package, trying to send data over a uart.
I am sending ints and floats over the uart, so I created a union of a float and a 4 byte uint8_t array, same for ints.
I put a few of these in a struct, and then put that in a union with an array that is the size of all the data contained in the struct.
I can't get it to work by passing the array in the struct to the function.. If I create an array of uint8_t, that passes in and works OK... I'm not sure what's wrong with trying to pass the array as I am.
It is failing an assert in R_SCI_UART_WRITE that checks the size, which is failing because it is 0.
typedef union{
float num_float;
uint32_t num_uint32;
int32_t num_int32;
uint8_t num_array[4];
} comms_data_t;
typedef struct{
comms_data_t a;
comms_data_t b;
comms_data_t c;
comms_data_t d;
comms_data_t e;
uint8_t lr[2];
} packet_data_t;
typedef union{
packet_data_t msg_packet_data;
uint8_t packet_array[22];
}msg_data_t;
/* Works */
uint8_t myData[10] = "Hi Dave!\r\n";
uart_print_main_processor_msg(myData);
/* Doesn't work */
msg_data_t msg_data;
/* code removed that puts data into msg_data,ex below */
msg_data.msg_packet_data.a.num_float = 1.2f;
uart_print_main_processor_msg(msg_data.packet_array);
// Functions below
/****************************************************************************************************************/
fsp_err_t uart_print_main_processor_msg(uint8_t *p_msg)
{
fsp_err_t err = FSP_SUCCESS;
uint8_t msg_len = RESET_VALUE;
uint32_t local_timeout = (DATA_LENGTH * UINT16_MAX);
char *p_temp_ptr = (char *)p_msg;
/* Calculate length of message received */
msg_len = ((uint8_t)(strlen(p_temp_ptr)));
/* Reset callback capture variable */
g_uart_event = RESET_VALUE;
/* Writing to terminal */
err = R_SCI_UART_Write (&g_uartMainProcessor_ctrl, p_msg, msg_len);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT ("\r\n** R_SCI_UART_Write API Failed **\r\n");
return err;
}
/* Check for event transfer complete */
while ((UART_EVENT_TX_COMPLETE != g_uart_event) && (--local_timeout))
{
/* Check if any error event occurred */
if (UART_ERROR_EVENTS == g_uart_event)
{
APP_ERR_PRINT ("\r\n** UART Error Event Received **\r\n");
return FSP_ERR_TRANSFER_ABORTED;
}
}
if(RESET_VALUE == local_timeout)
{
err = FSP_ERR_TIMEOUT;
}
return err;
}
fsp_err_t R_SCI_UART_Write (uart_ctrl_t * const p_api_ctrl, uint8_t const * const p_src, uint32_t const bytes)
{
#if (SCI_UART_CFG_TX_ENABLE)
sci_uart_instance_ctrl_t * p_ctrl = (sci_uart_instance_ctrl_t *) p_api_ctrl;
#if SCI_UART_CFG_PARAM_CHECKING_ENABLE || SCI_UART_CFG_DTC_SUPPORTED
fsp_err_t err = FSP_SUCCESS;
#endif
#if (SCI_UART_CFG_PARAM_CHECKING_ENABLE)
err = r_sci_read_write_param_check(p_ctrl, p_src, bytes);
FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
FSP_ERROR_RETURN(0U == p_ctrl->tx_src_bytes, FSP_ERR_IN_USE);
#endif
/* Transmit interrupts must be disabled to start with. */
p_ctrl->p_reg->SCR &= (uint8_t) ~(SCI_SCR_TIE_MASK | SCI_SCR_TEIE_MASK);
/* If the fifo is not used the first write will be done from this function. Subsequent writes will be done
* from txi_isr. */
#if SCI_UART_CFG_FIFO_SUPPORT
if (p_ctrl->fifo_depth > 0U)
{
p_ctrl->tx_src_bytes = bytes;
p_ctrl->p_tx_src = p_src;
}
else
#endif
{
p_ctrl->tx_src_bytes = bytes - p_ctrl->data_bytes;
p_ctrl->p_tx_src = p_src + p_ctrl->data_bytes;
}
#if SCI_UART_CFG_DTC_SUPPORTED
/* If a transfer instance is used for transmission, reset the transfer instance to transmit the requested
* data. */
if ((NULL != p_ctrl->p_cfg->p_transfer_tx) && p_ctrl->tx_src_bytes)
{
uint32_t data_bytes = p_ctrl->data_bytes;
uint32_t num_transfers = p_ctrl->tx_src_bytes >> (data_bytes - 1);
p_ctrl->tx_src_bytes = 0U;
#if (SCI_UART_CFG_PARAM_CHECKING_ENABLE)
/* Check that the number of transfers is within the 16-bit limit. */
FSP_ASSERT(num_transfers <= SCI_UART_DTC_MAX_TRANSFER);
#endif
err = p_ctrl->p_cfg->p_transfer_tx->p_api->reset(p_ctrl->p_cfg->p_transfer_tx->p_ctrl,
(void const *) p_ctrl->p_tx_src,
NULL,
(uint16_t) num_transfers);
FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
}
#endif
#if SCI_UART_CFG_FLOW_CONTROL_SUPPORT
if ((((sci_uart_extended_cfg_t *) p_ctrl->p_cfg->p_extend)->uart_mode == UART_MODE_RS485_HD) &&
(p_ctrl->flow_pin != SCI_UART_INVALID_16BIT_PARAM))
{
R_BSP_PinAccessEnable();
R_BSP_PinWrite(p_ctrl->flow_pin, BSP_IO_LEVEL_HIGH);
R_BSP_PinAccessDisable();
}
#endif
/* Trigger a TXI interrupt. This triggers the transfer instance or a TXI interrupt if the transfer instance is
* not used. */
p_ctrl->p_reg->SCR |= SCI_SCR_TIE_MASK;
#if SCI_UART_CFG_FIFO_SUPPORT
if (p_ctrl->fifo_depth == 0U)
#endif
{
/* On channels with no FIFO, the first byte is sent from this function to trigger the first TXI event. This
* method is used instead of setting TE and TIE at the same time as recommended in the hardware manual to avoid
* the one frame delay that occurs when the TE bit is set. */
if (2U == p_ctrl->data_bytes)
{
p_ctrl->p_reg->FTDRHL = *((uint16_t *) (p_src)) | (uint16_t) ~(SCI_UART_FIFO_DAT_MASK);
}
else
{
p_ctrl->p_reg->TDR = *(p_src);
}
}
return FSP_SUCCESS;
#else
FSP_PARAMETER_NOT_USED(p_api_ctrl);
FSP_PARAMETER_NOT_USED(p_src);
FSP_PARAMETER_NOT_USED(bytes);
return FSP_ERR_UNSUPPORTED;
#endif
}
There are several issues with this program. A large part of this code relies on undefined behavior. Unions are also UB if used for aliasing, even if pretty much all C compilers tend to allow it, but if you are using a union I would still prefer using a char[] for the array used for aliasing. As mentioned in the comments, "Hi Dave!\r\n"; actually takes up 11 bytes with the null-character. It's safer to use uint8_t myData[] = "Hi Dave!\r\n"; or const * uint8_t = "Hi Dave!\r\n"; and spare yourself the trouble.
Second problem is that strlen cannot work correctly for binary data. strlen works by searching for the first occurrence of the null-character in the string, so it's not applicable for binary data. If you pass a floating point value which has a single zero byte in its IEEE 754 representation, it will mark the end of this "string".
Plain and simple, your function should be declared as fsp_err_t uart_write(const char * msg, size_t msg_len); and be called using uart_write(data_array, sizeof data_array);. If you want to transmit messages of variable size over the UART, you will also have to define a certain communication protocol, i.e. create a message that can be unambiguously parsed. This will likely mean: 1) some cookie at the beginning, 2) length of the transmitted data, 3) actual data, 4) crc -- but this is outside the scope of this question.
So, strlen won't tell you the length of the data, you will pass it to the function yourself, and you don't need unions at all. If you choose not to properly serialize the data (e.g. using protobuf or some other protocol), you can simply pass the pointer to the struct to the function, i.e. call the above mentioned uart_write((char*)&some_struct, sizeof some_struct); and it will work as if you passed an array.
Note that char in this case doesn't mean "ascii character", or "character in a string". The point with using the char* is that it's the only pointer which is legally allowed to alias other pointers. So, you acquire a pointer to your struct (&str), cast it to a char*, and pass it to a function which can then read its representation in memory. I am aware that R_SCI_UART_Write is likely generated by your IDE, and unfortunately these blocks often use uint8_t* instead of char*, so you will probably have to cast to uint8_t* at some point.
I want to intercept the open() syscall, for testing each time a file is opened by the user, the message “OPEN IS!” should be displayed in dmesg.
The syscall table and open-call addresses in dmesg are displayed, but the message “OPEN IS!” is not visible. Kernel v. 4.18
I would like to know what the problem is. The code:
unsigned long cr0;
static unsigned long *__sys_call_table;
typedef asmlinkage int (*orig_open_t)(const char *, int, int);
orig_open_t orig_open;
unsigned long *
get_syscall_table_bf(void)
{
unsigned long *syscall_table;
unsigned long int i;
for (i = (unsigned long int)ksys_close; i < ULONG_MAX;
i += sizeof(void *)) {
syscall_table = (unsigned long *)i;
if (syscall_table[__NR_close] == (unsigned long)ksys_close) {
printk(KERN_INFO "syscall: %08lx\n", syscall_table);
return syscall_table;
}
}
return NULL;
}
asmlinkage int
hacked_open(const char *filename, int flags, int mode)
{
printk(KERN_INFO "OPEN IS!\n");
return 0;
}
static inline void
protect_memory(void)
{
write_cr0(cr0);
}
static inline void
unprotect_memory(void)
{
write_cr0(cr0 & ~0x00010000);
}
static int __init
diamorphine_init(void)
{
__sys_call_table = get_syscall_table_bf();
if (!__sys_call_table)
return -1;
cr0 = read_cr0();
orig_open = (orig_open_t)__sys_call_table[__NR_open];
unprotect_memory();
__sys_call_table[__NR_open] = (unsigned long)hacked_open;
printk(KERN_INFO "WE DO IT!\n");
printk(KERN_INFO "hacked is: %08lx\n", hacked_open);
protect_memory();
return 0;
}
static void __exit
diamorphine_cleanup(void)
{
unprotect_memory();
__sys_call_table[__NR_open] = (unsigned long)orig_open;
protect_memory();
}
module_init(diamorphine_init);
module_exit(diamorphine_cleanup);
MODULE_LICENSE("GPL");
I'm guessing something in your hooking is wrong. Either you're hooking a wrong offset of the syscall table or you're completely off. I couldn't understand why explicitly you start searching with ksys_close(), especially when it's an inlined function. You should try looking for the syscall table symbol as such:
typedef void (*_syscall_ptr_t)(void);
_syscall_ptr_t *_syscall_table = NULL;
_syscall_table=(_syscall_ptr_t *)kallsyms_lookup_name("sys_call_table");
A different (huge) issue I see with this is resetting CR0, which allows anything within your system to write to a read only memory at the time of your writing, instead of page-walking and setting the W bit on the specific page you're about to edit.
Additional one small word of advice: You should complete your hook to redirect to the original open syscall. Otherwise, you'll result in the entire system reading from STDIN for every newly opened file descriptor (which will kill your system, eventually)
I have implemented a queue in C language with usage of an array of structures.
typedef struct{
req_t buffer[BUFFER_SIZE]; // buffer
uint16_t size; // length of the queue
uint16_t count; // number of elements present in the queue
req_t *p_head; // pointer to head of the queue (read end)
req_t *p_tail; // pointer to tail of the queue (write end)
}circular_buffer_t;
void init_cb(circular_buffer_t *p_cb){
p_cb->p_head = p_cb->buffer;
p_cb->p_tail = p_cb->buffer;
p_cb->count = 0;
p_cb->size = BUFFER_SIZE;
}
The problem is that above given implementation is usable only for storing the
instances of req_t structures. Now I need to store instances of another
structure and I don't know how to define the queue in more general way so that
I will be able to use same queue for instances of different structures. Problem
is that I need to know the structure type before buffer definition. Does anybody
have any idea how to solve that?
#ifndef CIRCULAR_BUFFER_H_
#define CIRCULAR_BUFFER_H_
#define BUFFER_SIZE 32
// macro creates variant of the queue for each struct type
#define define_queue(TYPE) \
\
// queue element definition \
typedef struct{ \
TYPE buffer[BUFFER_SIZE]; \
uint16_t size; \
uint16_t count; \
TYPE *p_head; \
TYPE *p_tail; \
}circular_buffer_##TYPE##_t \
\
\
// queue init function definition \
void init_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb){ \
p_cb->p_head = p_cb->buffer; \
p_cb->p_tail = p_cb->buffer; \
p_cb->count = 0; \
p_cb->size = BUFFER_SIZE; \
} \
\
// queue enqueue function definition \
BOOL enqueue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE *p_enq_elem){ \
\
if(p_cb->count < p_cb->size){ \
\
taskENTER_CRITICAL(); \
\
*(p_cb->p_tail) = *p_enq_elem; \
p_cb->p_tail = ((++(p_cb->p_tail) == (p_cb->buffer + p_cb->size)) ? \
(p_cb->buffer) : (p_cb->p_tail)); \
p_cb->count++; \
\
taskEXIT_CRITICAL(); \
\
return TRUE; \
\
}else{ \
\
return FALSE; \
\
} \
\
} \
\
// queue dequeue function definition \
BOOL dequeue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE *p_deq_elem){ \
\
if((p_cb->count) != 0){ \
\
taskENTER_CRITICAL(); \
\
*p_deq_elem = *(p_cb->p_head); \
p_cb->p_head = ((++(p_cb->p_head) == (p_cb->buffer + p_cb->size)) ? \
(p_cb->buffer) : (p_cb->p_head)); \
p_cb->count--; \
\
taskEXIT_CRITICAL(); \
\
return TRUE; \
\
}else{ \
\
return FALSE; \
\
} \
\
} \
// macros for functions declarations
#define declare_init_cb(TYPE) void init_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb)
#define declare_enqueue_cb(TYPE) BOOL enqueue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE p_enq_elem);
#define declare_dequeue_cb(TYPE) BOOL dequeue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE p_deq_elem);
#endif
Structures I am going to use with the queue
typedef struct{
uint32_t addr; // address of the alarm signal
BOOL critical; // alarm is critical (=TRUE), alarm is non critical (=FALSE)
BOOL set; // alarm was set (=TRUE)
BOOL cleared; // alarm was cleared (=TRUE)
BOOL communicated; // alarm is communicated to Main Controller (=TRUE)
uint8_t code; // alarm code (0 - 255) - permanently 180
uint8_t no; // alarm number (0 - 255)
uint8_t no_flashes; // number of LED flashes if the alarm is active
}alarm_t;
and
typedef struct{
msg_e req_type; // request type
uint8_t blk_no; // block number
uint8_t no_records; // number of influenced records
uint8_t data_id[MAX_NO_RECORDS]; // data id, max. number of records in one block
uint16_t value[MAX_NO_RECORDS]; // written value, max. number of records in one block
uint8_t cleared_alarm_no; // number of the alarm which should be cleared
uint8_t flash_load; // 0 = Go into flash load mode
uint8_t mode[6]; // 000000 - Normal, BOOTBL - Boot block
uint8_t data_block[BLOCK_SIZE]; // one block in flash memory
uint8_t flash_page_number; // page number in flash memory (starting at 1)
uint8_t flash_block_number; // block number in flash memory (starting at 1)
}req_t;
If you want to store any type of struct in your queue, you have to use void * type and store in the queue only the pointers to any structs.
typedef struct{
void *buffer[BUFFER_SIZE]; // buffer
uint16_t size; // length of the queue
uint16_t count; // number of elements present in the queue
void *p_head; // pointer to head of the queue (read end)
void *p_tail; // pointer to tail of the queue (write end)
}circular_buffer_t;
Then, you have just to put any pointer in your queue like this:
circular_buffer_t p_cb;
my_struct_t *my_struct = malloc(sizeof(my_struct_t));
// set
p_cb.buffer[0] = (void*)my_struct;
// get
(my_struct_t*)p_cb.buffer[0];
1. Storing structs by value
If you specify the struct size when creating the queue, you can use it to store actual structs (copied by value) into the buffer.
typedef struct {
u32 capacity;
u32 element_size;
u8 * head; // next free slot
u8 * tail; // oldest enqueued item
u8 * buffer;
u8 * buffer_end;
} circular_buffer_t;
void circbuff_init(circular_buffer_t *p_cb, u8 *buffer, u32 element_size, u32 capacity)
{
p_cb->capacity = capacity;
p_cb->element_size = element_size;
p_cb->buffer = buffer;
p_cb->buffer_end = buffer + (capacity * element_size);
p_cb->head = buffer;
p_cb->tail = buffer;
}
Note that .count is redundant, you can calculate it at any time, and removing it makes reader/writer syncronization easier (in case that you read and write from different interrupts).
You need to take care to pass the correct buffer size and element_size:
circbuff_init(p_cb, buffer, sizeof(SomeStruct), sizeof(buffer) / sizeof(SomeStruct));
And then you just copy each element:
bool circbuff_dequeue(circular_buffer_t *hnd, void *dst)
{
// if empty, do nothing
if (circbuff_isEmpty(hnd))
return false;
memcpy(dst, hnd->tail, hnd->element_size);
hnd->tail = modulo_increment(hnd, hnd->tail);
return true;
}
2. Storing pointers to structs
This is already mentioned in some other answer.
3. Using a macro to create a typed buffer for each struct type
This is similar to how klib works. You would have to call certain macros to define each concrete type of circular buffer (for each struct), but then you would have compile time type safety.
Like I've mentioned in my comment above, I'd recommend using a union to store different types in one queue slot. Additionally, some type indicator is needed to distinguish them. Here's an example:
First, redefine req_t as req_t1, adding a type indicator as the first member:
typedef struct _req_t1
{
int type;
// append the members of your first structure here
}
req_t1;
Define the second type to be stored in an analogous way as req_t2:
typedef struct _req_t2
{
int type;
// append the members of your second structure here
}
req_t2;
Now redefine req_t as a union, containing both types, plus a standalone member that represents the type indicator, in order to test for the stored type:
typedef union _req_t
{
int type;
req_t1 item1;
req_t2 item2;
}
req_t;
Now you can use your circular buffer as before. However, req_t is now a compound member that might be interpreted as either type.
typedef struct _circular_buffer_t
{
req_t buffer [BUFFER_SIZE]; // buffer
uint16_t size; // length of the queue
uint16_t count; // number of elements present in the queue
req_t *p_head; // pointer to head of the queue (read end)
req_t *p_tail; // pointer to tail of the queue (write end)
}
circular_buffer_t;
To access the head, you use p_head->type to identify the type that's contained in this slot. If it indicates req_t1, you use p_head->item1 to access the members of req_t1, otherwise p_head->item2 for req_t2. This approach can be extended to any number of types.
What you want, is in fact a structure with a generic type field. The C language doesn't provide support for that. The best you can do it's to try to emulate that behavior. One way to do that is using macros or using generic pointers. Look here for more info about that: Pseudo-generics in C
There is a function to set the "valid data length" value: SetFileValidData, but I didn't find a way to get the "valid data length" value.
I want to know about given file if the EOF is different from the VDL, because writing after the VDL in case of VDL<EOF will cause a performance penalty as described here.
I found this page, claims that:
there is no mechanism to query the value of the VDL
So the answer is "you can't".
If you care about performance you can set the VDL to the EOF, but then note that you may allow access old garbage on your disk - the part between those two pointers, that supposed to be zeros if you would access that file without setting the VDL to point the EOF.
Looked into this. No way to get this information via any API, even the e.g. NtQueryInformationFile API (FileEndOfFileInformation only worked with NtSetInformationFile). So finally I read this by manually reading NTFS records. If anyone has a better way, please tell! This also obviously only works with full system access (and NTFS) and might be out of sync with the in-memory information Windows uses.
#pragma pack(push)
#pragma pack(1)
struct NTFSFileRecord
{
char magic[4];
unsigned short sequence_offset;
unsigned short sequence_size;
uint64 lsn;
unsigned short squence_number;
unsigned short hardlink_count;
unsigned short attribute_offset;
unsigned short flags;
unsigned int real_size;
unsigned int allocated_size;
uint64 base_record;
unsigned short next_id;
//char padding[470];
};
struct MFTAttribute
{
unsigned int type;
unsigned int length;
unsigned char nonresident;
unsigned char name_lenght;
unsigned short name_offset;
unsigned short flags;
unsigned short attribute_id;
unsigned int attribute_length;
unsigned short attribute_offset;
unsigned char indexed_flag;
unsigned char padding1;
//char padding2[488];
};
struct MFTAttributeNonResident
{
unsigned int type;
unsigned int lenght;
unsigned char nonresident;
unsigned char name_length;
unsigned short name_offset;
unsigned short flags;
unsigned short attribute_id;
uint64 starting_vnc;
uint64 last_vnc;
unsigned short run_offset;
unsigned short compression_size;
unsigned int padding;
uint64 allocated_size;
uint64 real_size;
uint64 initial_size;
};
#pragma pack(pop)
HANDLE GetVolumeData(const std::wstring& volfn, NTFS_VOLUME_DATA_BUFFER& vol_data)
{
HANDLE vol = CreateFileW(volfn.c_str(), GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (vol == INVALID_HANDLE_VALUE)
return vol;
DWORD ret_bytes;
BOOL b = DeviceIoControl(vol, FSCTL_GET_NTFS_VOLUME_DATA,
NULL, 0, &vol_data, sizeof(vol_data), &ret_bytes, NULL);
if (!b)
{
CloseHandle(vol);
return INVALID_HANDLE_VALUE;
}
return vol;
}
int64 GetFileValidData(HANDLE file, HANDLE vol, const NTFS_VOLUME_DATA_BUFFER& vol_data)
{
BY_HANDLE_FILE_INFORMATION hfi;
BOOL b = GetFileInformationByHandle(file, &hfi);
if (!b)
return -1;
NTFS_FILE_RECORD_INPUT_BUFFER record_in;
record_in.FileReferenceNumber.HighPart = hfi.nFileIndexHigh;
record_in.FileReferenceNumber.LowPart = hfi.nFileIndexLow;
std::vector<BYTE> buf;
buf.resize(sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER) + vol_data.BytesPerFileRecordSegment - 1);
NTFS_FILE_RECORD_OUTPUT_BUFFER* record_out = reinterpret_cast<NTFS_FILE_RECORD_OUTPUT_BUFFER*>(buf.data());
DWORD bout;
b = DeviceIoControl(vol, FSCTL_GET_NTFS_FILE_RECORD, &record_in,
sizeof(record_in), record_out, 4096, &bout, NULL);
if (!b)
return -1;
NTFSFileRecord* record = reinterpret_cast<NTFSFileRecord*>(record_out->FileRecordBuffer);
unsigned int currpos = record->attribute_offset;
MFTAttribute* attr = nullptr;
while ( (attr==nullptr ||
attr->type != 0xFFFFFFFF )
&& record_out->FileRecordBuffer + currpos +sizeof(MFTAttribute)<buf.data() + bout)
{
attr = reinterpret_cast<MFTAttribute*>(record_out->FileRecordBuffer + currpos);
if (attr->type == 0x80
&& record_out->FileRecordBuffer + currpos + attr->attribute_offset+sizeof(MFTAttributeNonResident)
< buf.data()+ bout)
{
if (attr->nonresident == 0)
return -1;
MFTAttributeNonResident* dataattr = reinterpret_cast<MFTAttributeNonResident*>(record_out->FileRecordBuffer
+ currpos + attr->attribute_offset);
return dataattr->initial_size;
}
currpos += attr->length;
}
return -1;
}
[...]
NTFS_VOLUME_DATA_BUFFER vol_data;
HANDLE vol = GetVolumeData(L"\\??\\D:", vol_data);
if (vol != INVALID_HANDLE_VALUE)
{
int64 vdl = GetFileValidData(alloc_test->getOsHandle(), vol, vol_data);
if(vdl>=0) { [...] }
[...]
}
[...]
The SetValidData (according to MSDN) can be used to create for example a large file without having to write to the file. For a database this will allocate a (contiguous) storage area.
As a result, it seems the file size on disk will have changed without any data having been written to the file.
By implication, any GetValidData (which does not exist) just returns the size of the file, so you can use GetFileSize which returns the "valid" file size.
I think you are confused as to what "valid data length" actually means. Check this answer.
Basically, while SetEndOfFile lets you increase the length of a file quickly, and allocates the disk space, if you skip to the (new) end-of-file to write there, all the additionally allocated disk space would need to be overwritten with zeroes, which is kind of slow.
SetFileValidData lets you skip that zeroing-out. You're telling the system, "I am OK with whatever is in those disk blocks, get on with it". (This is why you need the SE_MANAGE_VOLUME_NAME priviledge, as it could reveal priviledged data to unpriviledged users if you don't overwrite the data. Users with this priviledge can access the raw drive data anyway.)
In either case, you have set the new effective size of the file. (Which you can read back.) What, exactly, should a seperate "read file valid data" report back? SetFileValidData told the system that whatever is in those disk blocks is "valid"...
Different approach of explanation:
The documentation mentions that the "valid data length" is being tracked; the purpose for this is for the system to know which range (from end-of-valid-data to end-of-file) it still needs to zero out, in the context of SetEndOfFile, when necessary (e.g. you closing the file). You don't need to read back this value, because the only way it could be different from the actual file size is because you, yourself, did change it via the aforementioned functions...
I tried to find out the functionality of this function but I couldn't.. It is defined in Linux/arch/sparc/kernel/process_32.c Thanks
asmlinkage int sparc_do_fork(unsigned long clone_flags,
unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size)
{
unsigned long parent_tid_ptr, child_tid_ptr;
unsigned long orig_i1 = regs->u_regs[UREG_I1];
long ret;
parent_tid_ptr = regs->u_regs[UREG_I2];
child_tid_ptr = regs->u_regs[UREG_I4];
ret = do_fork(clone_flags, stack_start, stack_size,
(int __user *) parent_tid_ptr,
(int __user *) child_tid_ptr);
/* If we get an error and potentially restart the system
* call, we're screwed because copy_thread() clobbered
* the parent's %o1. So detect that case and restore it
* here.
*/
if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
regs->u_regs[UREG_I1] = orig_i1;
return ret;
}
It appears to be right there in the source code.
It's a wrapper around the regular Linux do_fork() call, one which saves and restores data (specifically, regs->u_regs[UREG_I1], which equates to the SPARC output register 1) that would otherwise be corrupted under certain circumstances:
/* If we get an error and potentially restart the system
* call, we're screwed because copy_thread() clobbered
* the parent's %o1. So detect that case and restore it
* here.
*/
It does this with:
unsigned long orig_i1 = regs->u_regs[UREG_I1]; // Save it.
ret = do_fork(...);
if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK) // It may be corrupt
regs->u_regs[UREG_I1] = orig_i1; // so restore it.