2 * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * LATCHESAR IONKOV AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
23 #define _XOPEN_SOURCE 600
35 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
37 typedef struct File File
;
44 static void rfs_connclose(Npconn
*conn
);
45 static int rfs_read(Npfilefid
* file
, u64 offset
, u32 count
, u8
* data
, Npreq
*);
46 static int rfs_write(Npfilefid
* file
, u64 offset
, u32 count
, u8
* data
, Npreq
*);
47 static int rfs_wstat(Npfile
*, Npstat
*);
48 static void rfs_destroy(Npfile
*);
49 static Npfile
* rfs_create(Npfile
*dir
, char *name
, u32 perm
, Npuser
*uid
,
50 Npgroup
*gid
, char *extension
);
51 static Npfile
* rfs_first(Npfile
*dir
);
52 static Npfile
* rfs_next(Npfile
*dir
, Npfile
*prevchild
);
53 static int rfs_wstat(Npfile
*, Npstat
*);
54 static int rfs_remove(Npfile
*dir
, Npfile
*file
);
61 static char *Enospace
= "no space left";
67 .destroy
= rfs_destroy
,
76 .destroy
= rfs_destroy
,
79 static File
* file_alloc(void);
84 fprintf(stderr
, "ramfs: -d -u user -w nthreads -b blocksize "
85 "-o mount-options mount-point\n");
90 main(int argc
, char **argv
)
92 int c
, debuglevel
, nwthreads
, fd
;
95 char *opts
, *logfile
, *s
;
101 logfile
= "/tmp/ramfs.log";
102 user
= np_default_users
->uid2user(np_default_users
, getuid());
103 while ((c
= getopt(argc
, argv
, "du:w:b:o:l:")) != -1) {
110 user
= np_default_users
->uname2user(np_default_users
, optarg
);
114 blksize
= strtol(optarg
, &s
, 10);
120 nwthreads
= strtol(optarg
, &s
, 10);
134 fprintf(stderr
, "invalid option\n");
139 fprintf(stderr
, "invalid user\n");
143 fd
= open(logfile
, O_WRONLY
| O_APPEND
| O_CREAT
, 0666);
145 fprintf(stderr
, "cannot open log file %s: %d\n", logfile
, errno
);
152 if (dup2(fd
, 2) < 0) {
153 fprintf(stderr
, "dup failed: %d\n", errno
);
166 root
= npfile_alloc(NULL
, strdup(""), ROOTPERM
|Dmdir
, qidpath
++,
167 &dirops
, file_alloc());
170 root
->atime
= time(NULL
);
171 root
->mtime
= root
->atime
;
173 root
->gid
= user
->dfltgroup
;
176 srv
= np_pipesrv_create(nwthreads
);
180 npfile_init_srv(srv
, root
);
184 srv
->debuglevel
= debuglevel
;
185 srv
->connclose
= rfs_connclose
;
186 np_pipesrv_mount(srv
, argv
[optind
], user
->uname
, 0, opts
);
200 f
= malloc(sizeof(*f
));
208 file_truncate(File
*f
, u64 size
)
220 n
= (size
/blksize
+ (size
%blksize
?1:0)) * blksize
;
221 buf
= realloc(f
->data
, n
);
231 rfs_connclose(Npconn
*conn
)
237 rfs_read(Npfilefid
* fid
, u64 offset
, u32 count
, u8
* data
, Npreq
*req
)
246 if (file
->length
< offset
+count
)
247 n
= file
->length
- offset
;
252 memmove(data
, f
->data
+ offset
, n
);
257 rfs_write(Npfilefid
* fid
, u64 offset
, u32 count
, u8
* data
, Npreq
*req
)
265 if (fid
->omode
& Oappend
)
266 offset
= file
->length
;
269 if (file
->length
< offset
+count
) {
270 pthread_mutex_lock(&file
->lock
);
271 if (file_truncate(f
, offset
+count
)) {
272 np_werror(Enospace
, ENOSPC
);
273 pthread_mutex_unlock(&file
->lock
);
277 if (offset
+count
> f
->datasize
) {
278 if (f
->datasize
- offset
> 0)
279 n
= f
->datasize
- offset
;
285 if (file
->length
< offset
)
286 memset(f
->data
+ file
->length
, 0, offset
-
288 file
->length
= offset
+ count
;
290 pthread_mutex_unlock(&file
->lock
);
294 memmove(f
->data
+ offset
, data
, n
);
300 rfs_wstat(Npfile
*file
, Npstat
*stat
)
304 char *sname
, *oldname
;
306 u64 length
, oldlength
;
316 lockparent
= stat
->name
.len
!= 0;
318 pthread_mutex_lock(&file
->parent
->lock
);
320 if (stat
->name
.len
!= 0) {
321 sname
= np_strdup(&stat
->name
);
322 nfile
= npfile_find(file
->parent
, sname
);
325 np_werror(Eexist
, EEXIST
);
328 npfile_decref(nfile
);
330 oldname
= file
->name
;
334 if (stat
->length
!= (u64
) ~0) {
335 oldlength
= file
->length
;
336 length
= stat
->length
;
337 if (file_truncate(f
, length
)) {
338 np_werror(Enospace
, ENOSPC
);
342 if (length
> f
->datasize
)
343 length
= f
->datasize
;
345 if (file
->length
< length
)
346 memset(f
->data
+ file
->length
, 0, length
- file
->length
);
348 file
->length
= length
;
351 if (stat
->mode
!= (u32
) ~0) {
352 oldperm
= file
->mode
;
353 file
->mode
= stat
->mode
;
356 if (stat
->mtime
!= (u32
)~0) {
357 oldmtime
= file
->mtime
;
358 file
->mtime
= stat
->mtime
;
363 pthread_mutex_unlock(&file
->parent
->lock
);
370 file
->name
= oldname
;
374 file
->mode
= oldperm
;
377 file
->mtime
= oldmtime
;
379 if (oldlength
!= ~0) {
380 file
->length
= oldlength
;
381 file_truncate(f
, oldlength
);
385 pthread_mutex_unlock(&file
->parent
->lock
);
391 rfs_destroy(Npfile
* file
)
401 rfs_create(Npfile
*dir
, char *name
, u32 perm
, Npuser
*uid
, Npgroup
*gid
,
409 np_werror(Eperm
, EPERM
);
420 file
= npfile_alloc(dir
, name
, perm
, qidpath
++, ops
, f
);
428 dir
->dirlast
->next
= file
;
429 file
->prev
= dir
->dirlast
;
431 dir
->dirfirst
= file
;
434 file
->extension
= strdup(extension
);
440 rfs_first(Npfile
*dir
)
442 npfile_incref(dir
->dirfirst
);
443 return dir
->dirfirst
;
447 rfs_next(Npfile
*dir
, Npfile
*prevchild
)
449 npfile_incref(prevchild
->next
);
450 return prevchild
->next
;
454 rfs_remove(Npfile
*dir
, Npfile
*file
)
456 if (dir
->dirfirst
== file
)
457 dir
->dirfirst
= file
->next
;
459 file
->prev
->next
= file
->next
;
462 file
->next
->prev
= file
->prev
;
464 if (file
== dir
->dirlast
)
465 dir
->dirlast
= file
->prev
;