long lseek(int fd, long offset, int origin);sets the current position in the file whose descriptor is fd to offset, which is taken relative to the location specified byorigin. Subsequent reading or writing will begin at that position. origin can be 0, 1, or 2 to specify thatoffset is to be measured from the beginning, from the current position, or from the end of the file respectively. For example, to append to a file (the redirection >> in the UNIX shell, or"a" for fopen), seek to the end before writing:
lseek(fd, 0L, 2);To get back to the beginning (``rewind''),
lseek(fd, 0L, 0);Notice the 0L argument; it could also be written as (long) 0 or just as0 if lseek is properly declared.
With lseek, it is possible to treat files more or less like arrays, at the price of slower access. For example, the following function reads any number of bytes from any arbitrary place in a file. It returns the number read, or-1 on error.
#include "syscalls.h" /*get: read n bytes from position pos */ int get(int fd, long pos, char *buf, int n) { if (lseek(fd, pos, 0) >= 0) /* get to pos */ return read(fd, buf, n); else return -1; }
The return value from lseek is a long that gives the new position in the file, or-1 if an error occurs. The standard library function fseek is similar tolseek except that the first argument is a FILE * and the return is non-zero if an error occurred.
====
http://www.java-samples.com/showtutorial.php?tutorialid=571
----------------------------------------------------------------------------------------------------------------------------
本章最後一個需要我們涉及的東西是 llseek 方法, 它有用(對於某些設備)並且容易實現.
llseek 方法實現了 lseek 和 llseek 系統調用. 我們已經說了如果 llseek 方法從設備的操作中缺失, 內核中的缺省的實現進行移位通過修改 filp->f_pos, 這是文件中的當前讀寫位置. 請注意對於 lseek 系統調用要正確工作, 讀和寫方法必須配合, 通過使用和更新它們收到的作爲的參數的 offset 項.
你可能需要提供你自己的方法, 如果移位操作對應一個在設備上的物理操作. 一個簡單的例子可在 scull 驅動中找到:
loff_t scull_llseek(struct file *filp, loff_t off, int whence) { struct scull_dev *dev = filp->private_data; loff_t newpos; switch(whence) { case 0: /* SEEK_SET */ newpos = off; break; case 1: /* SEEK_CUR */ newpos = filp->f_pos + off; break; case 2: /* SEEK_END */ newpos = dev->size + off; break; default: /* can't happen */ return -EINVAL; } if (newpos < 0) return -EINVAL; filp->f_pos = newpos; return newpos; }
唯一設備特定的操作是從設備中獲取文件長度. 在 scull 中 read 和 write 方法如需要地一樣協作, 如同在第 3 章所示.
儘管剛剛展示的這個實現對 scull 有意義, 它處理一個被很好定義了的數據區, 大部分設備提供了一個數據流而不是一個數據區(想想串口或者鍵盤), 並且移位這些設備沒有意義. 如果這就是你的設備的情況, 你不能只制止聲明 llseek 操作, 因爲缺省的方法允許移位. 相反, 你應當通知內核你的設備不支持 llseek , 通過調用 nonseekable_open 在你的 open 方法中.
int nonseekable_open(struct inode *inode; struct file *filp);
這個調用標識了給定的 filp 爲不可移位的; 內核從不允許一個 lseek 調用在這樣一個文件上成功. 通過用這樣的方式標識這個文件, 你可確定不會有通過 pread 和 pwrite 系統調用的方式來試圖移位這個文件.
完整起見, 你也應該在你的 file_operations 結構中設置 llseek 方法到一個特殊的幫忙函數 no_llseek, 它定義在 <linux/fs.h>.
====