李巨虎《操作系統(tǒng)》課設(shè)----“文件系統(tǒng)”基于C的實(shí)現(xiàn)(Day1)

# 今天是六一兒童節(jié)
# 下周一就要開始課設(shè)了
# 爭(zhēng)取在第一天給老師檢查吧
# 之后一個(gè)禮拜就可以好好復(fù)習(xí)算法設(shè)計(jì)的期末考試了
# 病了兩天真是難受
# 兩天沒有好好學(xué)習(xí) QWQ

Part 0 前言

整個(gè)程序是在Mac os的環(huán)境下開發(fā)的海蔽,因?yàn)橛幸恍┑讓酉到y(tǒng)調(diào)洪乍,Windows可能無(wú)法正常運(yùn)行庆亡,不過Linux應(yīng)該問題不大。

首先我是很想拿這個(gè)課設(shè)的滿分的录煤,仔細(xì)看了課設(shè)的要求鳄厌,如果要拿到滿分的話,需要有完整的文件系統(tǒng)妈踊,還要做到“命令端”和“文件系統(tǒng)端”的獨(dú)立運(yùn)行了嚎、相互通信。這個(gè)真的是比算法設(shè)計(jì)的課設(shè)工作量大多了(算法課設(shè)我就寫了百來行的代碼廊营,這個(gè)估摸著得上千了)歪泳。

講實(shí)話多進(jìn)程的東西寫的并不多,有寫露筒,但是也沒有太多的研究這個(gè)呐伞,所以這次課設(shè)對(duì)我來說難點(diǎn)就在于進(jìn)程間的通信了。也百度了一下Unix/Linux下的進(jìn)程通信的東西慎式,要實(shí)現(xiàn)的話基本就是用FIFO伶氢、消息隊(duì)列來實(shí)現(xiàn)趟径。

Part 1 架構(gòu)

架構(gòu)

架構(gòu)就如上圖吧,F(xiàn)ileSystem以讀寫的方式連接disk.dat(模擬的物理磁盤)癣防,再以IPC的方式連接各個(gè)Shell(命令端)蜗巧,當(dāng)然這里還有很多細(xì)節(jié)就先不討論了。

Part 2 文件系統(tǒng)的核心代碼

這里先上一個(gè)FileSystem的實(shí)現(xiàn)代碼(還沒Debug)蕾盯,共413行幕屹。

FileSys.h
(6.2號(hào)更新,補(bǔ)了一些注釋级遭,修復(fù)了一些“肉眼可見”的Bug望拖,因?yàn)檎麄€(gè)文件系統(tǒng)還未真正運(yùn)行過。)

#ifndef FileSys_h
#define FileSys_h

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define DISK_MEMO 10 * 1024 * 1024    // 磁盤總空間
#define DISK_SIZE 1024                 // 每個(gè)磁盤塊的大小
#define DISK_NUM DISK_MEMO / DISK_SIZE // 磁盤塊的數(shù)目

#define FAT_SIZE DISK_NUM * sizeof(fatitem)   // FAT表的大小
#define ROOT_DISK_NO FAT_SIZE / DISK_SIZE + 1 // 根目錄起始盤塊號(hào)
#define ROOT_DISK_SIZE sizeof(direct)         // 目錄大小

#define DIR_MAXSIZE 1024     // 路徑最大長(zhǎng)度
#define MSD 5                // 目錄最大子文件數(shù)量
#define MOFN 20              // 最大打開文件
#define MAX_WRITE 1024 * 128 // 最大寫入文字長(zhǎng)度
#define FILENAME_MAXLEN 64   // 最長(zhǎng)文件名稱長(zhǎng)度

typedef struct
{
    int item;     // 下一個(gè)磁盤的指針
    char em_disk; // 是否空閑(‘0’為空閑装畅,‘1’為非空閑)
} fatitem;

// FCB結(jié)構(gòu)體
typedef struct
{
    char name[FILENAME_MAXLEN]; // 名字
    char property;              // 屬性(‘1’是目錄靠娱,‘0’是文件)
    int size;                   // 文件/目錄 字節(jié)數(shù)
    int firstdisk;              // 文件/目錄 起始盤塊號(hào)
    int next;                   // 子目錄起始盤塊號(hào)
    int sign;                   // 根目錄識(shí)別符(1為根目錄標(biāo)識(shí)沧烈,0為非根目錄標(biāo)識(shí))
} FCB;

typedef struct
{
    FCB directitem[MSD + 2];
} direct;

// 打開文件表 實(shí)例結(jié)構(gòu)體
struct opentableitem
{
    char name[9];  // 文件名稱
    int firstdisk; // 文件起始盤塊號(hào)
    int size;      // 文件大小
};

// 打開文件 結(jié)構(gòu)體
typedef struct
{
    struct opentableitem openitem[MOFN];
    int cur_size; // 當(dāng)前打開文件的數(shù)目
} opentable;

fatitem *fat;          // FAT表
direct *root;          // 根目錄地址
direct *cur_dir;       // 當(dāng)前目錄
opentable u_opentable; // 文件打開表
int fd = -1;           // 文件打開表的序號(hào)
char *bufferdir;       // 記錄當(dāng)前路徑的名稱
char *fdisk;           // 虛擬磁盤起始地址(內(nèi)存中)

// FAT表數(shù)據(jù)設(shè)定函數(shù)
void fatitemset(fatitem *, int, char);

// FCB數(shù)據(jù)設(shè)定函數(shù)
void FCBset(FCB *, int, int, char *, int, char, int);

// 文件初始化掠兄,生成空的模擬磁盤物理文件(當(dāng)沒有disk.dat文件時(shí)執(zhí)行)
void initfile();

// 模擬磁盤數(shù)據(jù)初始化
void format();

// 進(jìn)入物理磁盤文件
void enter();

// 退出程序,保存物理文件
void halt();

// 新建文件
int create(char *);

// 打開文件
int open(char *);

// 關(guān)閉文件
int close(char *);

// 文件寫入
int write(int, char *, int);

// 文件讀取
int read(int, char *);

// 文件刪除
int del(char *);

// 新建文件夾
int mkdir(char *);

// 刪除文件夾
int rmdir(char *);

void initfile()
{
    fdisk = (char *)malloc(DISK_MEMO * sizeof(char));
    format();
}

void fatitemset(fatitem *f, int i, char e)
{
    f->item = I;
    f->em_disk = e;
}

void FCBset(FCB *fcb, int sign, int firstdisk, char *name, int next, char property, int size)
{
    fcb->sign = sign;
    fcb->firstdisk = firstdisk;
    strcpy(fcb->name, name);
    fcb->next = next;
    fcb->property = property;
    fcb->size = size;
}

void format()
{
    int I;
    FILE *fp;
    // FAT初始化
    // FAT的初始地址是disk的地址往后移 1K
    fat = (fatitem *)(fdisk + DISK_SIZE);
    fatitemset(&fat[0], -1, '1'); // 引導(dǎo)塊初始化
    // 1-ROOT全部置為1
    for (i = 1; i < ROOT_DISK_NO - 1; I++)
        fatitemset(&fat[i], i + 1, '1');
    fatitemset(&fat[ROOT_DISK_NO], -1, '0');
    for (i = ROOT_DISK_NO + 1; i < DISK_NUM - 1; I++)
        fatitemset(&fat[i], -1, '0');

    root = (direct *)(fdisk + DISK_SIZE + FAT_SIZE);
    FCBset(&root->directitem[0], 1, ROOT_DISK_NO, ".", ROOT_DISK_NO, '1', ROOT_DISK_SIZE);
    FCBset(&root->directitem[1], 1, ROOT_DISK_NO, "..", ROOT_DISK_NO, '1', ROOT_DISK_SIZE);
    for (i = 2; i < MSD + 2; I++)
        FCBset(&root->directitem[i], 0, -1, "", -1, '0', 0);

    if ((fp = fopen("./disk.dat", "wb")) == NULL)
    {
        printf("Error: Can't open disk.");
        return;
    }
    if ((fwrite(fdisk, DISK_MEMO, 1, fp)) != 1)
        printf("Error: Disk write error!");
    fclose(fp);
};

void enter()
{
    FILE *fp;
    int I;
    fdisk = (char *)malloc(DISK_MEMO * sizeof(char));
    if ((fp = fopen("./disk.dat", "rb")) == NULL)
    {
        printf("Error: Can't open disk.");
        return;
    }
    if (!fread(fdisk, DISK_MEMO, 1, fp))
    {
        printf("Error: Can't open disk.");
        exit(0);
    }
    fat = (fatitem *)(fdisk + DISK_SIZE);
    root = (direct *)(fdisk + DISK_SIZE + FAT_SIZE);
    fclose(fp);
    for (i = 0; i < MOFN; I++)
    {
        strcpy(u_opentable.openitem[i].name, "");
        u_opentable.openitem[i].firstdisk = -1;
        u_opentable.openitem[i].size = 0;
    }
    u_opentable.cur_size = 0;
    cur_dir = root;
    // bufferdir = (char *)malloc(DIR_MAXSIZE * sizeof(char));
    // strcpy(bufferdir, "Root:");
}

void halt()
{
    FILE *fp;
    int I;
    if ((fp = fopen("./disk.dat", "wb")) == NULL)
    {
        printf("Error: Can't open disk.");
        return;
    }
    if ((fwrite(fdisk, DISK_MEMO, 1, fp)) != 1)
        printf("Error: Disk write error!");
    fclose(fp);
    free(fdisk);
    free(bufferdir);
    return;
}

int create(char *name)
{
    int i, j;
    if (strlen(name) > FILENAME_MAXLEN)
        return -1;
    for (j = 2; j < MSD + 2; j++)
        if (!strcmp(cur_dir->directitem[j].name, name))
            return -4;
    for (i = 2; i < MSD + 2; I++)
        if (cur_dir->directitem[i].firstdisk == -1)
            break;
    if (i > MSD + 2)
        return -2;
    if (u_opentable.cur_size >= MOFN)
        return -3;
    for (j = ROOT_DISK_NO + 1; j < DISK_NUM; j++)
        if (fat[j].em_disk == '0')
            break;
    if (j >= DISK_NUM)
        return -5;
    fat[j].em_disk = '1';
    FCBset(&cur_dir->directitem[i], 0, j, name, j, '0', 0);
    fd = open(name);
    return 0;
}

int open(char *name)
{
    int i, j;
    for (i = 2; i < MSD + 2; I++)
        if (strcmp(cur_dir->directitem[i].name, name))
            break;
    if (i >= MSD + 2)
        return -1;
    if (cur_dir->directitem[i].property == '1')
        return -4;
    for (j = 0; j < MOFN; j++)
        if (!strcmp(u_opentable.openitem[j].name, name))
            break;
    if (j < MOFN)
        return -2;
    if (u_opentable.cur_size >= MOFN)
        return -3;
    for (j = 0; j < MOFN; j++)
        if (u_opentable.openitem[j].firstdisk == -1)
            break;
    u_opentable.openitem[j].firstdisk = cur_dir->directitem[i].firstdisk;
    strcpy(u_opentable.openitem[j].name, name);
    u_opentable.openitem[j].size = cur_dir->directitem[i].size;
    u_opentable.cur_size++;
    return j;
}

int close(char *name)
{
    int I;
    for (i = 0; i < MOFN; I++)
        if (!strcmp(u_opentable.openitem[i].name, name))
            break;
    if (i >= MOFN)
        return -1;
    u_opentable.openitem[i].firstdisk = -1;
    u_opentable.openitem[i].size = 0;
    strcpy(u_opentable.openitem[i].name, "");
    u_opentable.cur_size--;
    return 0;
}

int write(int fd, char *buf, int len)
{
    char *first;
    int item, i, j, k;
    int ilen1, ilen2, modlen, temp;

    item = u_opentable.openitem[fd].firstdisk;
    for (i = 2; i < MSD + 2; I++)
        if (cur_dir->directitem[i].firstdisk == item)
            break;
    temp = I;
    while (fat[item].item != -1)
        item = fat[item].item;
    // 找到文件的末地址
    first = fdisk + item * DISK_SIZE + u_opentable.openitem[fd].size % DISK_SIZE;
    if (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE > len)
    {
        // 最后一塊磁盤剩余的大小大于要寫入的大小
        strcpy(first, buf);
        u_opentable.openitem[fd].size += len;
        cur_dir->directitem[temp].size += len;
    }
    else
    {
        for (i = 0; i < (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE); I++)
            first[i] = buf[I];

        // 剩余長(zhǎng)度
        ilen1 = len - (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE);
        // 需要新磁盤塊
        ilen2 = (ilen1 - 1) / DISK_SIZE + 1;
        // 最后一塊磁盤的長(zhǎng)度
        modlen = ilen1 % DISK_SIZE;

        for (j = 0; j < ilen2; j++)
        {
            for (i = ROOT_DISK_NO + 1; i < DISK_NUM; I++)
                if (fat[i].em_disk == '0')
                    break;
            if (i >= DISK_NUM)
                return -1;
            first = fdisk + i * DISK_SIZE;
            if (j == ilen2 - 1)
                for (k = 0; k < len - (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE - j * DISK_SIZE); k++)
                    first[k] = buf[k];
            else
                for (k = 0; k < DISK_SIZE; k++)
                    //這里的k是不是有問題锌雀?蚂夕?
                    first[k] = buf[k];
            //這里的item是不是也有問題?腋逆?
            fat[item].item = I;
            fat[i].em_disk = '1';
            fat[i].item = -1;
        }
        u_opentable.openitem[fd].size += len;
        cur_dir->directitem[temp].size += len;
    }
    return 0;
}

int read(int fd, char *buf)
{
    int len = u_opentable.openitem[fd].size;
    char *first;
    int i, j, item;
    int ilen1, modlen;
    item = u_opentable.openitem[fd].firstdisk;
    ilen1 = (len - 1) / DISK_SIZE + 1;
    modlen = len % DISK_SIZE;
    first = fdisk + item * DISK_SIZE;
    for (i = 0; i < ilen1; i++)
    {
        if (i == ilen1 - 1)
            for (j = 0; j < len - i * DISK_SIZE; j++)
                buf[i * DISK_SIZE + j] = first[j];
        else
        {
            for (j = 0; j < len - i * DISK_SIZE; j++)
                buf[i * DISK_SIZE + j] = first[j];
            item = fat[item].item;
            first = fdisk + item * DISK_SIZE;
        }
    }
    return 0;
}

int del(char *name)
{
    int i, cur_item, item, temp;
    for (i = 2; i < MSD + 2; I++)
        if (!strcmp(cur_dir->directitem[i].name, name))
            break;
    if (i >= MSD + 2)
        return -1;
    cur_item = I;
    if (cur_dir->directitem[cur_item].property != '0')
        return -3;
    for (i = 0; i < MOFN; I++)
        if (!strcmp(u_opentable.openitem[i].name, name))
            return -2;
    item = cur_dir->directitem[cur_item].firstdisk;
    while (item != -1)
    {
        temp = fat[item].item;
        fat[item].item = -1;
        fat[item].em_disk = '0';
        item = temp;
    }
    FCBset(&cur_dir->directitem[cur_item], 0, -1, "", -1, '0', 0);
    return 0;
}

int mkdir(char *name)
{
    int i, j;
    direct *cur_mkdir;
    if (!strcmp(name, ".") || !strcmp(name, ".."))
        return -4;
    if (strlen(name) > FILENAME_MAX)
        return -1;
    for (j = 2; j < MSD + 2; j++)
        if (!strcmp(cur_dir->directitem[j].name, name))
            break;
    if (j < MSD + 2)
        return -3;
    for (j = ROOT_DISK_NO + 1; j < DISK_NUM; j++)
        if (fat[j].em_disk == '0')
            break;
    if (j > DISK_NUM)
        return -5;
    fat[j].em_disk = '1';
    FCBset(&cur_dir->directitem[i], 0, j, name, j, '1', ROOT_DISK_SIZE);
    cur_mkdir = (direct *)(fdisk + cur_dir->directitem[i].firstdisk * DISK_SIZE);
    FCBset(&cur_mkdir->directitem[0], 0, cur_dir->directitem[i].firstdisk, ".", cur_mkdir->directitem[0].firstdisk, '1', ROOT_DISK_SIZE);
    FCBset(&cur_mkdir->directitem[0], cur_dir->directitem[0].sign, cur_dir->directitem[0].firstdisk, "..", cur_mkdir->directitem[1].firstdisk, '1', ROOT_DISK_SIZE);
    for (i = 2; i < MSD + 2; I++)
        FCBset(&cur_mkdir->directitem[i], 0, -1, "", -1, '0', 0);
    return 0;
}

int rmdir(char *name)
{
    int i, j, item;
    direct *temp_dir;
    for (i = 2; i < MSD + 2; I++)
        if (!strcmp(cur_dir->directitem[i].name, name))
            break;
    if (i >= MSD + 2)
        return -1;
    if (cur_dir->directitem[i].property != '1')
        return -3;
    temp_dir = (direct *)(fdisk + cur_dir->directitem[i].next * DISK_SIZE);
    for (j = 2; j < MSD + 2; j++)
        // 文件夾不為空
        if (temp_dir->directitem[j].next != -1)
            break;
    if (j < MSD + 2)
        return -2;
    item = cur_dir->directitem[i].firstdisk;
    fat[item].em_disk = '0';
    FCBset(&cur_dir->directitem[i], 0, -1, "", -1, '0', 0);
    return 0;
}

#endif

一更(6/2上午10:08)更新一下6.1號(hào)所有的工作量

先這么寫著婿牍,等課設(shè)做完再把整篇文章的格式規(guī)范一下。


代碼統(tǒng)計(jì)量截圖

Part 3 “前后端”通信

截至目前已經(jīng)寫了1,446行代碼了惩歉,但是感覺還只是完成了一個(gè)空架(真是好大的工作量啊??)等脂。重要的是,著1,446行代碼中已經(jīng)實(shí)現(xiàn)了用IPC協(xié)議(消息列隊(duì))實(shí)現(xiàn)進(jìn)程通信撑蚌。為什么不用命名管道(FIFO)呢上遥,主要是FIFO在處理一對(duì)多要這種情況時(shí),要使用這種結(jié)構(gòu):

FIFO實(shí)現(xiàn)機(jī)制

這樣子的話争涌,假設(shè)有N個(gè)命令端的話粉楚,我們則需要建立 2+N 條FIFO,雖然說課設(shè)并不需要考慮這種極端情況亮垫,但是強(qiáng)迫癥的我(???♂?)還是覺得這種做法不是很好模软,因?yàn)镕IFO多次創(chuàng)建、釋放容易出問題饮潦。

于是燃异,我打算用F2S(file_system to shell)、S2F(shell to file system)來實(shí)現(xiàn)命令端和文件管理端的通信(理論上其實(shí)一個(gè)消息隊(duì)列也可以實(shí)現(xiàn))继蜡。

自定義的Message結(jié)構(gòu)體

struct s2fmsg 
{
    long int mtype;
    int serverid;
    int oper;
    char data[128];
};

struct f2smsg
{
    long int mtype;
    int oper;
    int status;
    char data[128];
};

命令端用S2F隊(duì)列向文件系統(tǒng)端發(fā)送請(qǐng)求特铝,文件系統(tǒng)用F2S向命令端發(fā)送請(qǐng)求結(jié)果(像極了request暑中,原諒我的淺薄理解)。乍一看鲫剿,和FIFO很像鳄逾,那它是怎么實(shí)現(xiàn)只用兩條隊(duì)列呢?這里是因?yàn)橄㈥?duì)列比FIFO多了一個(gè)關(guān)鍵性的功能灵莲,就是消息隊(duì)列傳輸?shù)南⒂幸粋€(gè) long int mtype的屬性雕凹,而命令端在接收文件系統(tǒng)端的回傳信息的時(shí)候,可以根據(jù)這個(gè)long int mtype來選擇接收mtype等于特定值的消息政冻∶兜郑基于這個(gè),我們就可以給 f2smsgmtype附加命令端的id明场。

(要繼續(xù)寫課設(shè)了汽摹,爭(zhēng)取明天前做好)
持續(xù)更新中……
最后一次更新于6/1上午10:36

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市苦锨,隨后出現(xiàn)的幾起案子逼泣,更是在濱河造成了極大的恐慌,老刑警劉巖舟舒,帶你破解...
    沈念sama閱讀 210,835評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拉庶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡秃励,警方通過查閱死者的電腦和手機(jī)氏仗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來夺鲜,“玉大人皆尔,你說我怎么就攤上這事”依” “怎么了慷蠕?”我有些...
    開封第一講書人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)榄审。 經(jīng)常有香客問我砌们,道長(zhǎng),這世上最難降的妖魔是什么搁进? 我笑而不...
    開封第一講書人閱讀 56,303評(píng)論 1 282
  • 正文 為了忘掉前任浪感,我火速辦了婚禮,結(jié)果婚禮上饼问,老公的妹妹穿的比我還像新娘影兽。我一直安慰自己,他們只是感情好莱革,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,375評(píng)論 5 384
  • 文/花漫 我一把揭開白布峻堰。 她就那樣靜靜地躺著讹开,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捐名。 梳的紋絲不亂的頭發(fā)上旦万,一...
    開封第一講書人閱讀 49,729評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音镶蹋,去河邊找鬼成艘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛贺归,可吹牛的內(nèi)容都是我干的淆两。 我是一名探鬼主播,決...
    沈念sama閱讀 38,877評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼拂酣,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼秋冰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起婶熬,我...
    開封第一講書人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤剑勾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后尸诽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甥材,經(jīng)...
    沈念sama閱讀 44,088評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盯另,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,443評(píng)論 2 326
  • 正文 我和宋清朗相戀三年性含,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸳惯。...
    茶點(diǎn)故事閱讀 38,563評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡商蕴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芝发,到底是詐尸還是另有隱情绪商,我是刑警寧澤,帶...
    沈念sama閱讀 34,251評(píng)論 4 328
  • 正文 年R本政府宣布辅鲸,位于F島的核電站格郁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏独悴。R本人自食惡果不足惜例书,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,827評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望刻炒。 院中可真熱鬧决采,春花似錦、人聲如沸坟奥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至晒喷,卻和暖如春孝偎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凉敲。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工邪媳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荡陷。 一個(gè)月前我還...
    沈念sama閱讀 46,240評(píng)論 2 360
  • 正文 我出身青樓雨效,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親废赞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子徽龟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,435評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容