mirror of
https://github.com/osnr/TabFS.git
synced 2024-06-10 09:52:21 +02:00
fix truncating in defineFile()
- in the C part: enable FUSE_CAP_ATOMIC_O_TRUNC so that open() will get called with O_TRUNC in flags instead of truncate() being called separately - this also prevents truncate() from calling setData() with an empty string when a file is opened with O_TRUNC - in defineFile()->open(): if O_TRUNC is used, don't call getData() but start with an empty file as if it had just been truncated - in defineFile()->write()/truncate(): correct buffer resizing/copying
This commit is contained in:
parent
6d65a48d4e
commit
a7ab34ebbc
|
@ -19,6 +19,9 @@ const unix = {
|
||||||
S_IFREG: 0100000, // regular
|
S_IFREG: 0100000, // regular
|
||||||
S_IFLNK: 0120000, // symbolic link
|
S_IFLNK: 0120000, // symbolic link
|
||||||
S_IFSOCK: 0140000, // socket
|
S_IFSOCK: 0140000, // socket
|
||||||
|
|
||||||
|
// Open flags
|
||||||
|
O_TRUNC: 01000,
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnixError extends Error {
|
class UnixError extends Error {
|
||||||
|
@ -110,6 +113,7 @@ const Cache = {
|
||||||
return handle;
|
return handle;
|
||||||
},
|
},
|
||||||
getObjectForHandle(handle) { return this.store[handle]; },
|
getObjectForHandle(handle) { return this.store[handle]; },
|
||||||
|
setObjectForHandle(handle, object) { this.store[handle] = object; },
|
||||||
removeObjectForHandle(handle) { delete this.store[handle]; }
|
removeObjectForHandle(handle) { delete this.store[handle]; }
|
||||||
};
|
};
|
||||||
function toUtf8Array(stringOrArray) {
|
function toUtf8Array(stringOrArray) {
|
||||||
|
@ -141,7 +145,10 @@ const defineFile = (getData, setData) => ({
|
||||||
|
|
||||||
// We call getData() once when the file is opened, then cache that
|
// We call getData() once when the file is opened, then cache that
|
||||||
// data for all subsequent reads from that application.
|
// data for all subsequent reads from that application.
|
||||||
async open({path}) { return { fh: Cache.storeObject(toUtf8Array(await getData(path))) }; },
|
async open({path, flags}) {
|
||||||
|
const data = !(flags & unix.O_TRUNC) ? await getData(path) : "";
|
||||||
|
return { fh: Cache.storeObject(toUtf8Array(data)) };
|
||||||
|
},
|
||||||
async read({path, fh, size, offset}) {
|
async read({path, fh, size, offset}) {
|
||||||
return { buf: String.fromCharCode(...Cache.getObjectForHandle(fh).slice(offset, offset + size)) }
|
return { buf: String.fromCharCode(...Cache.getObjectForHandle(fh).slice(offset, offset + size)) }
|
||||||
},
|
},
|
||||||
|
@ -150,9 +157,11 @@ const defineFile = (getData, setData) => ({
|
||||||
const bufarr = stringToUtf8Array(buf);
|
const bufarr = stringToUtf8Array(buf);
|
||||||
if (offset + bufarr.length > arr.length) {
|
if (offset + bufarr.length > arr.length) {
|
||||||
const newArr = new Uint8Array(offset + bufarr.length);
|
const newArr = new Uint8Array(offset + bufarr.length);
|
||||||
newArr.set(arr); arr = newArr;
|
newArr.set(arr.slice(0, Math.min(offset, arr.length)));
|
||||||
|
arr = newArr;
|
||||||
|
Cache.setObjectForHandle(fh, arr);
|
||||||
}
|
}
|
||||||
for (let i = 0; i < bufarr.length; i++) { arr[offset + i] = bufarr[i]; }
|
arr.set(bufarr, offset);
|
||||||
// I guess caller should override write() if they want to actually
|
// I guess caller should override write() if they want to actually
|
||||||
// patch and not just re-set the whole string (for example,
|
// patch and not just re-set the whole string (for example,
|
||||||
// if they want to hot-reload just one function the user modified)
|
// if they want to hot-reload just one function the user modified)
|
||||||
|
@ -165,11 +174,12 @@ const defineFile = (getData, setData) => ({
|
||||||
// (but `echo hi > foo.txt`, the main thing I care about, uses
|
// (but `echo hi > foo.txt`, the main thing I care about, uses
|
||||||
// O_TRUNC which thankfully doesn't do that)
|
// O_TRUNC which thankfully doesn't do that)
|
||||||
let arr = toUtf8Array(await getData(path));
|
let arr = toUtf8Array(await getData(path));
|
||||||
if (size > arr.length) {
|
if (size !== arr.length) {
|
||||||
const newArr = new Uint8Array(size);
|
const newArr = new Uint8Array(size);
|
||||||
newArr.set(arr); arr = newArr;
|
newArr.set(arr.slice(0, Math.min(size, arr.length)));
|
||||||
|
arr = newArr;
|
||||||
}
|
}
|
||||||
await setData(path, utf8ArrayToString(arr.slice(0, size))); return {};
|
await setData(path, utf8ArrayToString(arr)); return {};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
16
fs/tabfs.c
16
fs/tabfs.c
|
@ -423,6 +423,20 @@ static int tabfs_create(const char *path, mode_t mode, struct fuse_file_info *fi
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define want_capability(conn, flag) \
|
||||||
|
do { \
|
||||||
|
if (conn->capable & flag) { \
|
||||||
|
conn->want |= flag; \
|
||||||
|
} else { \
|
||||||
|
eprintln("warning: " #flag " not supported"); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void *tabfs_init(struct fuse_conn_info *conn) {
|
||||||
|
want_capability(conn, FUSE_CAP_ATOMIC_O_TRUNC);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct fuse_operations tabfs_oper = {
|
static const struct fuse_operations tabfs_oper = {
|
||||||
.getattr = tabfs_getattr,
|
.getattr = tabfs_getattr,
|
||||||
.readlink = tabfs_readlink,
|
.readlink = tabfs_readlink,
|
||||||
|
@ -441,6 +455,8 @@ static const struct fuse_operations tabfs_oper = {
|
||||||
|
|
||||||
.mkdir = tabfs_mkdir,
|
.mkdir = tabfs_mkdir,
|
||||||
.create = tabfs_create,
|
.create = tabfs_create,
|
||||||
|
|
||||||
|
.init = tabfs_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|
Loading…
Reference in a new issue