3
25
2014
0

火狐开发者工具、Object.watch 以及地址栏图标

之前通过 userChrome.js 脚本把火狐的地址栏图标弄回来了,但是一直有这么个问题:打开一个会自动跳转的标签页,比如 t.co 或者登陆状态下的 Google 搜索结果时,首先会显示跳转前的网站的图标(这没问题),然后开始载入新页面了(这问题也不大),然后新页面是使用 HTTPS 的(比如 MDN),于是就会看到地址栏图标后边已经变成绿色、显示出了站点信息(如「Mozilla Foundation (US)」),但是图标仍旧是跳转前的图标

经过探索,我发现火狐在载入新页面时并不会及时更改网站的图标(即该 tab 对象的.image属性;大概是因为默认情况下,即标签页里那个图标,它会被「载入中」的图标取代),但是其它信息都会及时更改,这才造成了不一致。既然这段时间取不到网站的图标,那么用默认图标好了。但问题是,怎么知道地址栏的 URL 已经改变了呢?

我试过在urlbar上监听change事件。Firebug 在调试chrome://browser/content/browser.xul页面时说会有这么个事件,但是真正在 chrome 里运行时却发现没有这样的事件被触发。

还想到了通过 Object.watch 方法要监听tab.linkedBrowser.currentURI属性的更改,但是好像也没有被调用。也许那个 nsIURI 对象一直在那里,只是它的值在变而已。

期间还试过 addProgressListener。大概是用法不对,无果。

后来结合了以上两个方案,决定监听urlbar.value的更改。这下终于好用了。有点小坑的是,因为一直在尝试各种方案,没仔细看文档,结果没注意注册到.watch方法中的函数要返回实际要设置的属性值,把火狐地址栏搞坏掉了……

在调试过程中,浏览器控制台(取代了以前的「错误控制台」,快捷键还是Ctrl-Shift-J)比「代码片断速记器」好用(它实际上是火狐自带调试工具中的「Web 控制台」运行在 chrome 上的版本):

火狐的「浏览器控制台」

  • chrome 脚本中的console.log等日志会记录在浏览器控制台,并且可以按关键字过滤(比如我今天一直在用的userChrome
  • 浏览器控制台支持 Tab 补全
  • 代码片断速记器每次打开之后需要手动切换「在浏览器环境中执行」
  • 代码片断速记器中不支持选择即复制、中键点击即粘贴功能,不支持 GTK 自定义的编辑快捷键
  • 浏览器控制台中直接记录对象的话,点击之后会出现和代码片断速记器Ctrl-i快捷键一样的「对象查看器」

不过浏览器控制台不支持将日志中的对象直接在脚本中使用(Firebug 支持)。

哦还有,MozRepl 在开启 chrome 调试的时候,是连接到最后一个有焦点的火狐窗口的(而不一定是chrome://browser/content/browser.xul这个)。期间搞错了一次,发现里边竟然连gBrowser变量都没有 -_-|||

最后,辛辛苦苦接着出来的新版代码(其实没改多少):

if(location == "chrome://browser/content/browser.xul"){

  var eTLDService = Components.classes["@mozilla.org/network/effective-tld-service;1"]
                    .getService(Components.interfaces.nsIEffectiveTLDService);

  function updateIcon(event){
    var tab = event.target;
    if(tab != gBrowser.selectedTab){
      return;
    }
    var icon = tab.image || 'chrome://mozapps/skin/places/defaultFavicon.png';
    var identity = document.getElementById('identity-box');
    if('chromeUI'.indexOf(identity.className) != -1){
      // already has a pretty icon as list-style-image
      icon = '';
    }
    console.log('updateIcon', icon, tab.linkedBrowser.currentURI.spec, event);
    document.getElementById('page-proxy-favicon').src = icon;
    if('verifiedDomain'.indexOf(identity.className) != -1){
      var identityLabel = document.getElementById('identity-icon-labels');
      identityLabel.collapsed = false;

      var domain;
      try{
        domain = eTLDService.getBaseDomain(tab.linkedBrowser.currentURI);
      }catch(ex){ // NS_ERROR_HOST_IS_IP_ADDRESS
        domain = tab.linkedBrowser.currentURI.host;
      }

      document.getElementById('identity-icon-label').value = domain;
    }
  }

  var container = gBrowser.tabContainer;
  // includes TabSelect (.selected is modified)
  container.addEventListener("TabAttrModified", updateIcon, false);
  document.getElementById('urlbar').watch('value', function(prop, oldval, newval){
    console.log('urlbar value changed to ' + newval);
    document.getElementById('page-proxy-favicon').src = 'chrome://mozapps/skin/places/defaultFavicon.png';
    return newval;
  }, false);

  })();
}
Category: 火狐 | Tags: 火狐 userChrome
3
14
2014
4

Linux 系统时间变更通知

每一次,系统从挂起状态恢复,系统日志里总会多这么几行:

systemd[1]: Time has been changed
crond[324]: time disparity of 698 minutes detected

一个来自 systemd,一个来自 dcron,都是说系统时间改变了。那么它们是怎么知道系统时间改变的呢?

dcron 的代码很少,所以很快就可以找到。因为 dcron 每一次的睡眠时长它自己知道,所以当它再次从睡眠状态醒来,发现时间变化特别大时,它就会察觉到。也就是说,小的变化它会察觉不到的。

systemd 呢?这家伙一直在使用 Linux 新加特性,比如上次发现的 prctl 的 PR_SET_CHILD_SUBREAPER 功能。这次它也没有让我失望,它使用了 timerfd 的一个鲜为人知的标志位——TFD_TIMER_CANCEL_ON_SET。timerfd 是 Linux 2.6.25 引入的特性,而TFD_TIMER_CANCEL_ON_SET这个标志位则据说 Linux 3.0 引入的,但是到目前为止(man-pages 3.61),手册里没有提到它,系统头文件里也没有它。

这个标志位是干什么的呢?其实很简单,是当系统时钟被重设时向程序发送通知,包括通过系统调用设置系统时间,以及系统从硬件时钟更新时间时。当事件发生时,在该 timerfd 上的读取操作会返回 -1 表示失败,而 errno 被设置成ECANCELED。下边是一个简单的演示程序,在系统时间变化时打印一条消息:

#include<unistd.h>
#include<sys/timerfd.h>
#include<stdbool.h>
#include<stdint.h>
#include<errno.h>
#include<stdlib.h>
#include<stdio.h>
#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
#ifndef TFD_TIMER_CANCEL_ON_SET
#  define TFD_TIMER_CANCEL_ON_SET (1 << 1)
#endif

int main(int argc, char **argv){
  int fd;
  struct itimerspec its = {
    .it_value.tv_sec = TIME_T_MAX,
  };
  fd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
  if(fd < 0){
    perror("timerfd_create");
    exit(1);
  }
  if(timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET,
        &its, NULL) < 0) {
    perror("timerfd_settime");
    exit(1);
  }
  uint64_t exp;
  ssize_t s;
  while(true){
    s = read(fd, &exp, sizeof(uint64_t));
    if(s == -1 && errno == ECANCELED){
      printf("time changed.\n");
    }else{
      printf("meow? s=%zd, exp=%lu\n", s, exp);
    }
  }
  return 0;
}

编译并运行该程序,然后拿 date 命令设置时间试试吧 =w= 当然记得用虚拟机哦,因为系统时间乱掉的时候会发生不好的事情喵~

date 091508002012
Category: Linux | Tags: systemd linux
3
13
2014
1

我的浏览器A到Z

Re: 的确挺好玩的~

那个 frecency 懒得去研究是干什么用的,大概是频度之类的?frecency 即是火狐地址栏著名的 frecency 算法的值。

A
标题:工作台 - Chito
URL:http://lilydjwg.is-programmer.com/admin
访问次数:1828
frecency:3564600
最后访问日期:2014-03-13 21:26:42

B
标题:搜索结果 (页 1) / Arch Linux 中文论坛
URL:https://bbs.archlinuxcn.org/search.php?action=show_new
访问次数:1550
frecency:3100000
最后访问日期:2014-03-13 21:47:33

C
标题:Twitter / Interactions
URL:https://twitter.com/i/connect
访问次数:673
frecency:1063004
最后访问日期:2014-03-13 20:30:28

D
标题:豆瓣
URL:http://www.douban.com/
访问次数:290
frecency:212507
最后访问日期:2014-02-26 21:34:39

E
标题:所有消息 - SegmentFault
URL:http://segmentfault.com/user/events
访问次数:298
frecency:539380
最后访问日期:2014-03-13 21:44:30

F
标题:Index of /ftp/python
URL:http://python.org/ftp/python/
访问次数:7
frecency:2614
最后访问日期:2014-02-19 23:45:13

G
标题:Gmail
URL:https://mail.google.com/mail/
访问次数:396
frecency:449053
最后访问日期:2014-02-28 20:26:26

H
标题:工作台 - Chito
URL:http://lilydjwg.is-programmer.com/admin
访问次数:1828
frecency:3564600
最后访问日期:2014-03-13 21:26:42

I
标题:依云's Blog
URL:http://lilydjwg.is-programmer.com/
访问次数:100
frecency:126258
最后访问日期:2014-03-09 23:28:52

J
标题:jQAPI - Alternative jQuery Documentation Browser
URL:file:///home/lilydjwg/%E6%96%87%E6%A1%A3/%E7%BD%91%E9%A1%B5/Javascript/jqapi_2013-01-21/index.html
访问次数:5
frecency:1446
最后访问日期:2013-12-18 02:25:01

K
标题:The Linux Kernel Archives
URL:http://kernel.org/
访问次数:41
frecency:33347
最后访问日期:2014-03-02 21:47:12

L
标题:Lua 5.2 Reference Manual - contents
URL:file:///usr/share/doc/lua/contents.html#index
访问次数:24
frecency:14682
最后访问日期:2014-03-05 21:47:52

M
标题:Google 地图
URL:https://maps.google.com/
访问次数:83
frecency:52035
最后访问日期:2014-03-12 19:30:50

N
标题:None
URL:http://lilydjwg.is-programmer.com/admin/posts/new
访问次数:24
frecency:33600
最后访问日期:2014-03-13 22:08:35

O
标题:查看版面 - Vim和Emacs • Ubuntu中文论坛
URL:http://forum.ubuntu.org.cn/viewforum.php?f=68
访问次数:236
frecency:166138
最后访问日期:2014-03-02 22:26:47

P
标题:Python Module Index — Python v3.3.0 documentation
URL:file:///home/lilydjwg/%E6%96%87%E6%A1%A3/%E7%BC%96%E7%A8%8B/Python/python/py-modindex.html
访问次数:124
frecency:169744
最后访问日期:2014-03-10 23:10:46

Q
标题:Qt 4.8:
URL:jar:file:///home/.ecryptfs/lilydjwg/public/%E6%96%87%E6%A1%A3/%E7%BC%96%E7%A8%8B/qt4-doc/qt4-doc.zip!/index.html
访问次数:9
frecency:5198
最后访问日期:2014-03-06 22:05:35

R
标题:InoReader • 轻便快捷的 RSS 阅读器
URL:https://www.inoreader.com/
访问次数:155
frecency:177119
最后访问日期:2014-03-12 22:41:51

S
标题:SegmentFault
URL:http://segmentfault.com/
访问次数:1486
frecency:411473
最后访问日期:2014-03-13 20:47:13

T
标题:Google 翻译
URL:http://translate.google.cn/?hl=zh-CN
访问次数:138
frecency:145314
最后访问日期:2014-03-11 23:50:21

U
标题:Pinboard: public bookmarks for vayn
URL:http://pinboard.in/u:vayn
访问次数:13
frecency:5589
最后访问日期:2014-02-16 18:42:04

V
标题:查看版面 - Vim和Emacs • Ubuntu中文论坛
URL:http://forum.ubuntu.org.cn/viewforum.php?f=68
访问次数:236
frecency:166138
最后访问日期:2014-03-02 22:26:47

W
标题:新浪微博-随时随地分享身边的新鲜事儿
URL:http://weibo.com/
访问次数:78
frecency:117933
最后访问日期:2014-02-27 22:51:10

X
标题:None
URL:http://localhost/xcache/
访问次数:6
frecency:6688
最后访问日期:2014-03-02 22:50:15

Y
标题:soimort/you-get
URL:https://github.com/soimort/you-get
访问次数:24
frecency:19374
最后访问日期:2014-03-07 21:13:24

Z
标题:消息 - 知乎
URL:http://www.zhihu.com/notifications
访问次数:528
frecency:823165
最后访问日期:2014-03-09 16:53:10


附:从 URL 生成这些数据的代码。当然,还有后期处理,是用 Vim 简单地做了几次正则替换。

#!/usr/bin/env python3

import os
import sys
import sqlite3
from time import strftime, localtime

places = os.path.expanduser('~/.mozilla/firefox/profile/places.sqlite')

def main():
  db = sqlite3.connect(places)
  sql = '''select title, visit_count, frecency, last_visit_date
           from moz_places where url = ? limit 1'''
  c = db.cursor()

  for url in sys.stdin:
    url = url.strip()
    c.execute(sql, (url,))
    title, visit_count, frecency, last_visit_date = c.fetchall()[0]
    print('''\
标题:%s
URL:%s
访问次数:%d
frecency:%d
最后访问日期:%s
''' % (title, url, visit_count, frecency,
       strftime('%Y-%m-%d %H:%M:%S', localtime(last_visit_date//1000000))))

if __name__ == '__main__':
  main()

又附:上边的代码忘记写是哪个字母了 -_-||| 已经补上,用了个 Vim 宏来完成。话说好久没用 Vim 宏了呢~

Category: 未分类 | Tags: 程序员 火狐 浏览器
3
13
2014
4

Python 3 的 super() 和 __class__

子类里访问父类的同名属性,而又不想直接引用父类的名字,因为说不定什么时候会去修改它,所以数据还是只保留一份的好。其实呢,还有更好的理由不去直接引用父类的名字,参见 Python’s super() considered super! | Deep Thoughts by Raymond Hettinger

这时候就该 super() 登场啦——

class A:
  def m(self):
    print('A')

class B(A):
  def m(self):
    print('B')
    super().m()

B().m()

当然 Python 2 里 super() 是一定要参数的,所以得这么写:

class B(A):
  def m(self):
    print('B')
    super(B, self).m()

需要提到自己的名字。这个名字也是动态查找的,在这种情况下替换第三方库中的类会出问题。

super() 很好地解决了访问父类中的方法的问题。那么,如果要访问父类的父类(准确地说,是方法解析顺序(MRO)中位于第三的类)的属性呢?

比如,B 类是继承 A 的,它重写了 A 的 m 方法。现在我们需要一个 C 类,它需要 B 类的一些方法,但是不要 B 的 m 方法,而改用 A 的。怎么间接地引用到 A 的 m 方法呢?使用self.__class__肯定是不行的,因为 C 还可能被进一步继承。

从文档中我注意到,super 的实现是通过插入一个名为 __class__ 的名字来实现的(super 会从调用栈里去查找这个 __class__ 名字)。所以,就像文档里暗示的,其实可以直接在定义方法时访问 __class__ 名字,它总是该方法被定义的类。继续我们的单字母类:

class C(B):
  def m(self):
    print('C')
    # see the difference!
    print(__class__.__mro__)
    print(self.__class__.__mro__)
    __class__.__mro__[2].m(self)

class D(C):
  def m(self):
    print('D')
    super().m()

o = D()
o.m()

会得到:

D
C
(<class 't.C'>, <class 't.B'>, <class 't.A'>, <class 'object'>)
(<class 't.D'>, <class 't.C'>, <class 't.B'>, <class 't.A'>, <class 'object'>)
A

不过,PyPy 并不支持这个 __class__ 名字。

Category: python | Tags: Python
3
9
2014
8

GM 脚本:GMail 日期正常化

我所谓的「正常化」,就是适合人而不是机器读取的格式啦。比如你们说「12/2/14」这是哪天呢……明明可以显示成「20YY年M月DD日 上午H:MM」这样子的(鼠标移过去会出现),但是为什么非要我去移鼠标呢。于是就有了这个很简单的脚本:

// ==UserScript==
// @name           GMail 日期正常化
// @namespace      http://lilydjwg.is-programmer.com/
// @description    将 GMail 中的日期使用更适合人阅读的形式显示
// @include        https://mail.google.com/*
// @grant	   none
// ==/UserScript==

var doit = function(){
  var elements = document.querySelectorAll('span[alt]');
  for(var i=0, len=elements.length; i<len; i++){
    elements[i].textContent = elements[i].getAttribute('alt');
  }
};
document.addEventListener('overflow', doit);
window.addEventListener('focus', doit);

点此安装

Category: 火狐 | Tags: gmail GreaseMonkey
3
8
2014
9

编译 Android 版 htop

编译完 lsof,却发现 htop 还是不能用……另开一个终端 strace 之,才知它竟然在调用 /bin/sh 而不是 /system/bin/sh。检查之,原来这个 htop 来自 Terminal IDE,是一个静态链接的版本,大概是使用 glibc 的吧,所以才会去标准位置寻找命令解释器。

编译过程:

path+=/opt/android-ndk/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin
mkdir android-build && cd android-build
CFLAGS='-I/ldata/media/temp/android/installed_binaries/include/ncurses -I/ldata/media/temp/android/installed_binaries/include' LDFLAGS=-L/ldata/media/temp/android/installed_binaries/lib CC='arm-linux-androideabi-gcc --sysroot=/opt/android-ndk/platforms/android-18/arch-arm' ../configure --host=arm-linux-gnu --prefix=/system --bindir=/system/xbin --disable-unicode
rm ../config.h

然后修改当前目录中的 config.h 文件,注释掉 HAVE_NATIVE_AFFINITY 行,添加两个 syscall 的定义,即:

// #define HAVE_NATIVE_AFFINITY 1
#define SYS_ioprio_get __NR_ioprio_get
#define SYS_ioprio_set __NR_ioprio_set

继续 make 即可。

编译好的 htop 可由此下载

Category: Android | Tags: Android 交叉编译
3
8
2014
3

编译 Android 版 lsof

Android 自带的那个 lsof 实际上是 toolbox 里的,功能十分单一,除了显示出所有进程的所有打开的文件外就什么都不能做,连说明也没有 :-( 于是为了 htop 用着爽一点,还是自己编译一个吧。

首先弄个 GNU 工具链。Android NDK 的没有 tcp.h 头文件,会报 TCP_LISTEN 等标识符未定义。

  • 我使用 crosstool-NG 1.19.0 编译的 gcc 4.8.1。适用于 Arch Linux x86_64。第一次编译工具链,没想到在 crosstool-NG 的帮助下一次就编译好了,所以是未作静态链接的版本,其它版本的 Linux 可能无法运行。
  • zshaolin 使用的工具链 gcc 4.4.6。它是使用 crosstool-NG 1.13.2 编译的。

编译过程。使用了静态链接,最终文件大小 741K。

path+=/ldata/txtfiles/soft/arm-lilydjwg-linux-gnueabi/bin
LSOF_CC=arm-lilydjwg-linux-gnueabi-gcc LSOF_CFGF='-DHAS_STRFTIME -DHASNORPC_H -DGLIBCV' LSOF_VERS=3.0.8 ./Configure -n linux
make
arm-lilydjwg-linux-gnueabi-gcc -o lsof -static dfile.o dmnt.o dnode.o dproc.o dsock.o dstore.o arg.o main.o misc.o node.o print.o proc.o store.o usage.o util.o -L./lib -llsof
arm-lilydjwg-linux-gnueabi-strip lsof

编译好的 lsof 可由此下载

Category: Android | Tags: Android 交叉编译
3
6
2014
5

使用 PyQt 转换网页到 PDF

代码很简单,功能也很简单 =w=

#!/usr/bin/env python3

import sys

try:
  from PyQt4 import QtWebKit
  from PyQt4.QtCore import QUrl
  from PyQt4.QtGui import QApplication, QPrinter
except ImportError:
  from PySide import QtWebKit
  from PySide.QtCore import QUrl
  from PySide.QtGui import QApplication, QPrinter

app = QApplication(sys.argv)

def done(status):
  p = QPrinter()
  p.setOutputFormat(QPrinter.PdfFormat)
  p.setOutputFileName('a.pdf')
  view.print(p)
  app.exit()

view = QtWebKit.QWebView()
view.load(QUrl('http://lilydjwg.is-programmer.com/'))
view.loadFinished[bool].connect(done)
# PySide does not have QApplication.exec
app.exec_()

注意:虽然没有图形界面,但是还是需要 X 连接……

Category: python | Tags: Python PyQt Qt
3
3
2014
17

《冰雪奇缘》之缘——A站弹幕 JSON 转 crt

都是《冰雪奇缘》惹的祸,不仅画面美仑美奂,音乐激荡人心,而且还玩多语言版本的主题曲

you-get 竟助纣为虐,把歌词给下回来了!只叹 soimort 没有好人做到底,留一个语义不详的 JSON 让我情何以堪。

好在 muzuiget 才识不凡,有码略释其义,遂如我光影、声音、文字三位一体之愿!

编成代码数十行,只为女王歌一曲:

#!/usr/bin/env python3

import json
import sys

def cmtjson_reader(f):
  data = json.load(f)
  for o in data:
    c = o['c'].split(',')
    m = o['m']
    # see
    # https://github.com/muzuiget/niconvert/blob/master/niconvert/libsite/acfun.py
    start = float(c[0])
    yield start, m

def format_time(t):
  s, ms = divmod(t, 1)
  s = int(s)
  ms = int(ms * 1000)
  m, s = divmod(s, 60)
  h, m = divmod(m, 60)
  return '%d:%02d:%02d,%03d' % (h, m, s, ms)

def crt_writer(f):
  i = 0

  fmt = '%d\n%s --> %s\n%s\n\n'
  try:
    while True:
      t, m = yield
      ts = format_time(t)
      if i != 0:
        f.write(fmt % (i, format_time(old_t), ts, old_m))
      i += 1
      old_t = t
      old_m = m
  except GeneratorExit:
    f.write(fmt % (
      i+1, format_time(t), format_time(t+2), m))

def main():
  w = crt_writer(sys.stdout)
  w.send(None)
  old_d0 = 0
  for d in cmtjson_reader(sys.stdin):
    if d[0] < old_d0:
      break
    w.send(d)
    old_d0 = d[0]

if __name__ == '__main__':
  main()

mplayer 君虽识得 UTF-8 之码,却不通 fontconfig 之术,部分文字沦为了下划线。又及。

Category: python | Tags: python
3
2
2014
3

FUSE 初体验:Android dedupefs

自打知道 FUSE 以来都觉得亲手写一个 FUSE 文件系统是很好玩的事情,但是因为没好的自己能够很快实现的点子所以一直没动手。前段时间需要从 Android xrecovery 备份中取得一旧版本的应用,才决定动手的,顺便也练习一下很久没怎么用到的 C 语言。至于为什么不用 Python,好像那个 Python 绑定不太稳定的样子,Python 3 版更是如此。而且我也不希望效率太差。

首先介绍一下,所谓的「dedupefs」,就是把 Android xrecovery 的「dedupe」备份格式的数据挂载成文件系统来查看。其实仅仅只是想查看的话,把那个 dedupe 目录下的东东 gcc 一下就可以创建和解开 dedupe 的备份了,只是占用很多磁盘空间而已。

dedupe 的格式很简单,一个文本文件描述文件信息(时间、路径、大小、类型等),一个目录里全是 sha256 命名的文件来存储文件的数据,以便在备份时不同的备份中的相同文件只保存一次。

FUSE 嘛,我好像从来没看到过完整一点的文档,就是官方 API 文档也经常语焉不详。dedupefs 是参考 rofs 写的。dedupefs 也是只读的。

挂载之前,先得把 dedupe 的纯文本格式处理一下。纯文本适合存储和人阅读,但是查询效率低下。我决定用更适合处理纯文本的 Python,把数据存储到 GNU dbm 键值对数据库中,然后 dedupefs 直接读取数据库就好了。(于是顺便学会了在 C 中使用 GNU dbm :-))数据的组织方式如下:

  • d + 文件路径:该目录下的文件名列表
  • f + 文件路径:该文件的信息

这样要读取一个目录下的文件列表就查 d 开头的项,要取得一个文件的信息(stat)或者打开文件,就读 f 开头的。

下边是编码和调试过程中的经验与收获:

  • GNU dbm 没说它是线程安全的,所以它不是线程安全的。但是 FUSE 又是多线程的(调试用的单线程模式我就不玩的),所以读取数据库时要加锁。
  • GNU dbm 查询结果数据是要调用者来 free 的。
  • 因为涉及到二进制数据交换(Python <-> C),所以要注意在结构体声明时围上#pragma pack(push, 1)#pragma pack(pop),以免对齐不一致造成数据错误。
  • valgrind 用来诊断内存访问错误效果非常棒!
  • FUSE 的struct fuse_file_info里有个fh域可以用来存文件描述符,这样就不用像 rofs 那样每次读取都要打开一遍文件了。
  • FUSE 读取用的回调函数传的offset一定要用,要首先lseek(finfo->fh, offset, SEEK_SET);一下,不然指不定读取到什么地方的数据了。
  • FUSE 文件系统可以忽略文件权限,所以自己不在openaccess里判断的话,就可以访问到明明看上去不能访问的文件(这正在我想要的)。
  • du 命令读取文件占用磁盘空间时使用了struct statst_blocks域。如果在 FUSE 程序里不管它的话,那么 du 将总是报告占用了 0 字节的空间……这里的块大小总是 512 字节。

第一次写 FUSE 程序,虽然文档差了一点,但用起来还是挺方便 =w=

哦对了,android-dedupefs 的仓库链接。

部分静态文件存储由又拍云存储提供。 | Theme: Aeros 2.0 by TheBuckmaker.com