1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
|
/*
* Copyright (c) 2006-2025 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscall_internal.h"
/**
* @brief Get filesystem statistics.
*
* This function retrieves statistics about the filesystem at the specified path,
* storing the results in the provided `statfs` structure. It can be used to obtain
* information such as the total number of blocks, free blocks, available inodes, etc.
*
* @param[in] path The path to the filesystem to query. If the path is the root directory
* (`"/"`), it returns statistics for the root filesystem.
* @param[out] buf A pointer to a `statfs` structure where the filesystem statistics will
* be stored. This structure includes information such as:
* - `f_type`: The type of the filesystem.
* - `f_bsize`: The optimal block size for I/O operations.
* - `f_blocks`: Total number of blocks in the filesystem.
* - `f_bfree`: Number of free blocks.
* - `f_bavail`: Number of free blocks available to non-superuser.
* - `f_files`: Total number of file nodes (inodes).
* - `f_ffree`: Number of free inodes.
* - `f_favail`: Number of inodes available to non-superuser.
* - `f_flag`: Flags describing the filesystem.
* - `f_namelen`: Maximum length of a filename.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @note This function is useful for determining the available space and file system
* characteristics of a mounted filesystem.
*
* @see sys_fstatfs
*/
sysret_t sys_statfs(const char *path, struct statfs *buf)
{
int ret = 0;
size_t len;
size_t copy_len;
char *copy_path;
struct statfs statfsbuff = { 0 };
if (!lwp_user_accessable((void *)buf, sizeof(struct statfs)))
{
return -EFAULT;
}
len = lwp_user_strlen(path);
if (len <= 0)
{
return -EFAULT;
}
copy_path = (char *)rt_malloc(len + 1);
if (!copy_path)
{
return -ENOMEM;
}
copy_len = lwp_get_from_user(copy_path, (void *)path, len);
if (copy_len == 0)
{
rt_free(copy_path);
return -EFAULT;
}
copy_path[copy_len] = '\0';
ret = _SYS_WRAP(statfs(copy_path, &statfsbuff));
rt_free(copy_path);
if (ret == 0)
{
lwp_put_to_user(buf, &statfsbuff, sizeof statfsbuff);
}
return ret;
}
/**
* @brief Get extended filesystem statistics (64-bit).
*
* This function retrieves extended statistics about the filesystem at the specified path,
* using 64-bit values for larger filesystems or filesystems with a large number of blocks or inodes.
* The information is stored in the provided `statfs` structure, which includes details such as total
* blocks, free blocks, available inodes, etc.
*
* @param[in] path The path to the filesystem to query. Typically, this would be the root directory
* (`"/"`) for the root filesystem, or any other directory on the filesystem.
* @param[in] sz The size of the `statfs` structure. This parameter allows for future extensions
* of the `statfs` structure without breaking compatibility with older applications.
* @param[out] buf A pointer to a `statfs` structure where the extended filesystem statistics
* will be stored. This structure includes information such as:
* - `f_bsize`: The optimal block size for I/O operations.
* - `f_blocks`: Total number of blocks in the filesystem.
* - `f_bfree`: Number of free blocks.
* - `f_bavail`: Number of free blocks available to non-superuser.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @note This function is particularly useful for querying large filesystems or filesystems with
* 64-bit addresses or data values, and is an extended version of the standard `sys_statfs`.
*
* @see sys_statfs
*/
sysret_t sys_statfs64(const char *path, size_t sz, struct statfs *buf)
{
int ret = 0;
size_t len;
size_t copy_len;
char *copy_path;
struct statfs statfsbuff = { 0 };
if (!lwp_user_accessable((void *)buf, sizeof(struct statfs)))
{
return -EFAULT;
}
if (sz != sizeof(struct statfs))
{
return -EINVAL;
}
len = lwp_user_strlen(path);
if (len <= 0)
{
return -EFAULT;
}
copy_path = (char *)rt_malloc(len + 1);
if (!copy_path)
{
return -ENOMEM;
}
copy_len = lwp_get_from_user(copy_path, (void *)path, len);
if (copy_len == 0)
{
rt_free(copy_path);
return -EFAULT;
}
copy_path[copy_len] = '\0';
ret = _SYS_WRAP(statfs(copy_path, &statfsbuff));
rt_free(copy_path);
if (ret == 0)
{
lwp_put_to_user(buf, &statfsbuff, sizeof statfsbuff);
}
return ret;
}
/**
* @brief Get filesystem statistics for a file descriptor.
*
* This function retrieves statistics about the filesystem containing the file referred to by the
* file descriptor `fd`. The information is stored in the provided `statfs` structure, which includes
* details such as total blocks, free blocks, available inodes, etc.
*
* @param[in] fd The file descriptor referring to an open file. The file descriptor must be
* valid and represent a file on a mounted filesystem.
* @param[out] buf A pointer to a `statfs` structure where the filesystem statistics will be
* stored. This structure includes information such as:
* - `f_bsize`: The optimal block size for I/O operations.
* - `f_blocks`: Total number of blocks in the filesystem.
* - `f_bfree`: Number of free blocks.
* - `f_bavail`: Number of free blocks available to non-superuser.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @note This function is useful for obtaining filesystem information about a specific file
* represented by its file descriptor, rather than querying the filesystem associated with
* a specific path.
*
* @see sys_statfs
*/
sysret_t sys_fstatfs(int fd, struct statfs *buf)
{
int ret = 0;
struct statfs statfsbuff = { 0 };
if (!lwp_user_accessable((void *)buf, sizeof(struct statfs)))
{
return -EFAULT;
}
ret = _SYS_WRAP(fstatfs(fd, &statfsbuff));
if (ret == 0)
{
lwp_put_to_user(buf, &statfsbuff, sizeof statfsbuff);
}
return ret;
}
/**
* @brief Get 64-bit filesystem statistics for a file descriptor.
*
* This function retrieves 64-bit statistics about the filesystem containing the file referred to by
* the file descriptor `fd`. The statistics are stored in the provided `statfs` structure, which
* includes details such as total blocks, free blocks, available inodes, etc. The function differs
* from `sys_fstatfs` in that it supports 64-bit values for filesystem sizes and counts.
*
* @param[in] fd The file descriptor referring to an open file. The file descriptor must be
* valid and represent a file on a mounted filesystem.
* @param[in] sz The size of the `statfs` structure (typically used to ensure compatibility with
* different versions of the structure).
* @param[out] buf A pointer to a `statfs` structure where the filesystem statistics will be
* stored. This structure includes information such as:
* - `f_bsize`: The optimal block size for I/O operations.
* - `f_blocks`: Total number of blocks in the filesystem (64-bit).
* - `f_bfree`: Number of free blocks (64-bit).
* - `f_bavail`: Number of free blocks available to non-superuser (64-bit).
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
* @note This function is particularly useful for systems supporting 64-bit filesystem statistics.
* It provides extended accuracy for large filesystems, including those with very large
* numbers of blocks or inodes.
*
* @see sys_fstatfs
*/
sysret_t sys_fstatfs64(int fd, size_t sz, struct statfs *buf)
{
int ret = 0;
struct statfs statfsbuff = { 0 };
if (!lwp_user_accessable((void *)buf, sizeof(struct statfs)))
{
return -EFAULT;
}
if (sz != sizeof(struct statfs))
{
return -EINVAL;
}
ret = _SYS_WRAP(fstatfs(fd, &statfsbuff));
if (ret == 0)
{
lwp_put_to_user(buf, &statfsbuff, sizeof statfsbuff);
}
return ret;
}
static char *_cp_from_usr_string(char *dst, char *src, size_t length)
{
char *rc;
size_t copied_bytes;
if (length)
{
copied_bytes = lwp_get_from_user(dst, src, length);
dst[copied_bytes] = '\0';
rc = dst;
}
else
{
rc = RT_NULL;
}
return rc;
}
/**
* @brief Mount a filesystem.
*
* This function mounts a filesystem onto a specified directory. It allows for mounting various
* types of filesystems, including but not limited to `ext4`, `nfs`, and `tmpfs`. The function
* allows the specification of the source device, the target mount point, and additional parameters
* such as filesystem type, mount flags, and extra data.
*
* @param[in] source The source of the filesystem, which can be a device (e.g., `/dev/sda1`)
* or a network resource (e.g., a NFS share). For certain filesystems like
* `tmpfs`, this can be `NULL`.
* @param[in] target The target directory where the filesystem will be mounted.
* This should be an existing empty directory.
* @param[in] filesystemtype The type of filesystem to mount, e.g., `ext4`, `tmpfs`, `nfs`, etc.
* @param[in] mountflags Flags that control the mount operation, such as `MS_RDONLY` for read-only
* mounts or `MS_NODEV` to prevent device files from being created.
* @param[in] data Optional data that is passed to the filesystem's mount handler. This
* may be used for setting up specific parameters for the filesystem type.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @note Mounting a filesystem on an existing mount point can replace the existing filesystem at that
* location. Make sure the target directory is empty before mounting to avoid any conflicts.
*/
sysret_t sys_mount(char *source, char *target, char *filesystemtype,
unsigned long mountflags, void *data)
{
char *kbuffer, *ksource, *ktarget, *kfs;
size_t len_source, len_target, len_fs;
char *tmp = NULL;
int ret = 0;
struct stat buf = { 0 };
char *dev_fullpath = RT_NULL;
len_source = source ? lwp_user_strlen(source) : 0;
if (len_source < 0)
{
return -EINVAL;
}
len_target = target ? lwp_user_strlen(target) : 0;
if (len_target <= 0)
{
return -EINVAL;
}
len_fs = filesystemtype ? lwp_user_strlen(filesystemtype) : 0;
if (len_fs < 0)
{
return -EINVAL;
}
kbuffer = (char *)rt_malloc(len_source + 1 + len_target + 1 + len_fs + 1);
if (!kbuffer)
{
return -ENOMEM;
}
/* get parameters from user space */
ksource = kbuffer;
ktarget = ksource + len_source + 1;
kfs = ktarget + len_target + 1;
ksource = _cp_from_usr_string(ksource, source, len_source);
ktarget = _cp_from_usr_string(ktarget, target, len_target);
kfs = _cp_from_usr_string(kfs, filesystemtype, len_fs);
if (mountflags & MS_REMOUNT)
{
ret = dfs_remount(ktarget, mountflags, data);
}
else
{
if (strcmp(kfs, "nfs") == 0)
{
tmp = ksource;
ksource = NULL;
}
if (strcmp(kfs, "tmp") == 0)
{
ksource = NULL;
}
if (ksource && !dfs_file_stat(ksource, &buf) && S_ISBLK(buf.st_mode))
{
dev_fullpath = dfs_normalize_path(RT_NULL, ksource);
RT_ASSERT(rt_strncmp(dev_fullpath, "/dev/", sizeof("/dev/") - 1) == 0);
ret = dfs_mount(dev_fullpath + sizeof("/dev/") - 1, ktarget, kfs, 0, tmp);
}
else
{
ret = dfs_mount(ksource, ktarget, kfs, 0, tmp);
}
if (ret < 0)
{
ret = -rt_get_errno();
}
}
rt_free(kbuffer);
rt_free(dev_fullpath);
return ret;
}
/**
* @brief Unmount a filesystem.
*
* This function unmounts a previously mounted filesystem from a specified target directory or file.
* It removes the filesystem from the system, making the resources associated with it available for
* other uses. It can also support additional flags to control the unmounting behavior.
*
* @param[in] __special_file The target directory or mount point from which the filesystem is to be
* unmounted. This should be a valid mount point that was previously mounted.
* @param[in] __flags Flags that control the unmounting behavior. Common flags include:
* - `MNT_FORCE`: Forces the unmount even if the filesystem is busy.
* - `MNT_DETACH`: Detaches the filesystem, allowing it to be unmounted
* asynchronously.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @note The `MNT_FORCE` flag should be used with caution, as it may result in data loss or corruption
* if there are pending writes or active processes using the filesystem.
*
* @see sys_mount
*/
sysret_t sys_umount2(char *__special_file, int __flags)
{
char *copy_special_file;
size_t len_special_file, copy_len_special_file;
int ret = 0;
len_special_file = lwp_user_strlen(__special_file);
if (len_special_file <= 0)
{
return -EFAULT;
}
copy_special_file = (char *)rt_malloc(len_special_file + 1);
if (!copy_special_file)
{
return -ENOMEM;
}
copy_len_special_file = lwp_get_from_user(copy_special_file, __special_file, len_special_file);
copy_special_file[copy_len_special_file] = '\0';
ret = dfs_unmount(copy_special_file);
rt_free(copy_special_file);
return ret;
}
/**
* @brief Create a new hard link to an existing file.
*
* This function creates a new hard link to an existing file, making the file accessible from
* multiple filenames. The new link points to the same inode as the existing file, meaning
* both names refer to the same underlying data. The link count for the file is incremented.
*
* @param[in] existing The path to the existing file. It must be an absolute or relative path
* to a file that already exists.
* @param[in] new The path to the new link to be created. This can be a new filename or
* an existing directory where the link will be placed.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @note Hard links share the same inode number, meaning changes to the data of the file via one
* link will be reflected in all hard links. Deleting any of the links will not remove the
* file data until all links are deleted.
*/
sysret_t sys_link(const char *existing, const char *new)
{
int ret = -1;
int err = 0;
#ifdef RT_USING_DFS_V2
#ifdef ARCH_MM_MMU
int len = 0;
char *kexisting = RT_NULL;
char *knew = RT_NULL;
len = lwp_user_strlen(existing);
if (len <= 0)
{
return -EFAULT;
}
kexisting = (char *)kmem_get(len + 1);
if (!kexisting)
{
return -ENOMEM;
}
if (lwp_get_from_user(kexisting, (void *)existing, len + 1) != (len + 1))
{
kmem_put(kexisting);
return -EINVAL;
}
len = lwp_user_strlen(new);
if (len <= 0)
{
kmem_put(kexisting);
return -EFAULT;
}
knew = (char *)kmem_get(len + 1);
if (!knew)
{
kmem_put(kexisting);
return -ENOMEM;
}
if (lwp_get_from_user(knew, (void *)new, len + 1) != (len + 1))
{
kmem_put(knew);
kmem_put(kexisting);
return -EINVAL;
}
ret = dfs_file_link(kexisting, knew);
if (ret < 0)
{
err = GET_ERRNO();
}
kmem_put(knew);
kmem_put(kexisting);
#else
ret = dfs_file_link(existing, new);
#endif
#else
SET_ERRNO(EFAULT);
err = GET_ERRNO();
#endif
return (err < 0 ? err : ret);
}
/**
* @brief Create a symbolic link to an existing file or directory.
*
* This function creates a new symbolic link, which is a special file that contains a reference
* to another file or directory. The symbolic link allows for easy redirection or aliasing of
* file paths. Unlike a hard link, a symbolic link can point to a file or directory across
* different file systems.
*
* @param[in] existing The path to the existing file or directory that the symbolic link
* will refer to. It must be an absolute or relative path.
* @param[in] new The path to the new symbolic link to be created. This must be a valid
* path where the link will be placed.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @note A symbolic link is distinct from a hard link in that it points to the path of the target
* file or directory, rather than directly to the inode. If the target file or directory is
* removed or moved, the symbolic link will become "broken" and will not resolve to a valid
* location.
*/
sysret_t sys_symlink(const char *existing, const char *new)
{
int ret = -1;
int err = 0;
#ifdef ARCH_MM_MMU
ret = lwp_user_strlen(existing);
if (ret <= 0)
{
return -EFAULT;
}
ret = lwp_user_strlen(new);
if (ret <= 0)
{
return -EFAULT;
}
#endif
#ifdef RT_USING_DFS_V2
ret = dfs_file_symlink(existing, new);
if (ret < 0)
{
err = GET_ERRNO();
}
#else
SET_ERRNO(EFAULT);
#endif
return (err < 0 ? err : ret);
}
/**
* @brief Create an event file descriptor.
*
* This function creates an eventfd, which is a file descriptor used for event notification.
* Eventfd is a simple mechanism to notify threads or processes about certain events using
* an integer counter. It is typically used for inter-process communication (IPC) or
* synchronization purposes, where one thread or process increments the counter to signal
* another thread or process.
*
* @param[in] count Initial value for the eventfd counter. It can be set to a non-zero
* value to initialize the counter to that value.
* @param[in] flags Flags that control the behavior of the eventfd. Valid flags include:
* - `EFD_CLOEXEC`: Set the close-on-exec flag for the eventfd.
* - `EFD_NONBLOCK`: Set the non-blocking flag for the eventfd.
*
* @return sysret_t On success, returns a valid file descriptor referring to the eventfd. On
* failure, returns a negative error code.
*
* @note Eventfd can be used for both counting and signaling purposes. It provides
* efficient signaling between threads or processes.
*/
sysret_t sys_eventfd2(unsigned int count, int flags)
{
int ret;
ret = eventfd(count, flags);
return (ret < 0 ? GET_ERRNO() : ret);
}
/**
* @brief Create an epoll instance.
*
* This function creates an epoll instance, which is used for monitoring multiple file descriptors
* to see if I/O is possible on them. It allows a program to efficiently wait for events such as
* data being available for reading or space becoming available for writing. Epoll provides a scalable
* mechanism for managing large numbers of file descriptors.
*
* @param[in] flags Flags that control the behavior of the epoll instance. The valid flags include:
* - `EPOLL_CLOEXEC`: Set the close-on-exec flag for the epoll instance.
* - `EPOLL_NONBLOCK`: Set the non-blocking flag for the epoll instance.
*
* @return sysret_t On success, returns a file descriptor for the epoll instance. On failure,
* returns a negative error code.
*
* @note The `sys_epoll_create1` function is similar to `sys_epoll_create`, but it allows for
* additional control over the epoll instance creation via flags.
*/
sysret_t sys_epoll_create1(int flags)
{
int ret;
ret = epoll_create(flags);
return (ret < 0 ? GET_ERRNO() : ret);
}
/**
* @brief Control an epoll instance.
*
* This function performs control operations on an epoll instance, such as adding, modifying,
* or removing file descriptors from the epoll instance's interest list.
*
* @param[in] fd The file descriptor of the epoll instance created using `sys_epoll_create` or `sys_epoll_create1`.
* @param[in] op The operation to perform on the epoll instance. It can be one of the following:
* - `EPOLL_CTL_ADD`: Add the specified file descriptor to the epoll interest list.
* - `EPOLL_CTL_MOD`: Modify the event mask of an existing file descriptor in the epoll interest list.
* - `EPOLL_CTL_DEL`: Remove the specified file descriptor from the epoll interest list.
* @param[in] fd2 The file descriptor to be added, modified, or removed from the epoll interest list.
* @param[in] ev A pointer to an `epoll_event` structure that describes the event to be associated with `fd2`.
* This parameter is required for `EPOLL_CTL_ADD` and `EPOLL_CTL_MOD`, but not for `EPOLL_CTL_DEL`.
*
* @return sysret_t On success, returns `0`. On failure, returns a negative error code.
*
* @note This function is typically used to manage the set of file descriptors monitored by an epoll instance.
*/
sysret_t sys_epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
{
int ret = 0;
struct epoll_event *kev = RT_NULL;
if (ev)
{
if (!lwp_user_accessable((void *)ev, sizeof(struct epoll_event)))
{
return -EFAULT;
}
kev = kmem_get(sizeof(struct epoll_event));
if (kev == RT_NULL)
{
return -ENOMEM;
}
if (lwp_get_from_user(kev, ev, sizeof(struct epoll_event)) != sizeof(struct epoll_event))
{
kmem_put(kev);
return -EINVAL;
}
ret = epoll_ctl(fd, op, fd2, kev);
kmem_put(kev);
}
else
{
ret = epoll_ctl(fd, op, fd2, RT_NULL);
}
return (ret < 0 ? GET_ERRNO() : ret);
}
/**
* @brief Wait for events on an epoll file descriptor, with the ability to block for specific signals.
*
* This function waits for events on an epoll file descriptor. It blocks until one or more events
* are available or a timeout occurs. In addition to waiting for events, it can also block for specific signals
* as specified by the `sigs` argument.
*
* @param[in] fd The file descriptor of the epoll instance, created using `sys_epoll_create` or `sys_epoll_create1`.
* @param[out] ev A pointer to an array of `epoll_event` structures that will receive the events that have occurred.
* @param[in] cnt The maximum number of events to return. This specifies the size of the `ev` array.
* @param[in] to The timeout in milliseconds. A negative value means no timeout, and `0` means non-blocking.
* @param[in] sigs A pointer to a signal set (`sigset_t`) that specifies the signals to block during the wait.
* If `NULL`, no signals are blocked.
* @param[in] sigsetsize The size of the signal set (`sigs`) in bytes. This should be the size of `sigset_t` if `sigs` is not `NULL`.
*
* @return sysret_t On success, returns the number of events returned (may be `0` if the timeout expires with no events).
* On failure, returns a negative error code.
*
* @note This function is similar to `sys_epoll_wait`, but it also allows for signal handling, blocking the calling thread
* from receiving signals specified in the `sigs` set while waiting for events.
*/
sysret_t sys_epoll_pwait(int fd,
struct epoll_event *ev,
int cnt,
int to,
const sigset_t *sigs,
unsigned long sigsetsize)
{
int ret = 0;
struct epoll_event *kev = RT_NULL;
sigset_t *ksigs = RT_NULL;
if (!lwp_user_accessable((void *)ev, cnt * sizeof(struct epoll_event)))
{
return -EFAULT;
}
kev = kmem_get(cnt * sizeof(struct epoll_event));
if (kev == RT_NULL)
{
return -ENOMEM;
}
if (sigs != RT_NULL)
{
if (!lwp_user_accessable((void *)sigs, sizeof(sigset_t)))
{
kmem_put(kev);
return -EFAULT;
}
ksigs = kmem_get(sizeof(sigset_t));
if (ksigs == RT_NULL)
{
kmem_put(kev);
return -ENOMEM;
}
if (lwp_get_from_user(ksigs, (void *)sigs, sizeof(sigset_t)) != sizeof(sigset_t))
{
kmem_put(kev);
kmem_put(ksigs);
return -EINVAL;
}
}
ret = epoll_pwait(fd, kev, cnt, to, ksigs);
if (ret > 0)
{
lwp_put_to_user((void *)ev, kev, ret * sizeof(struct epoll_event));
}
if (sigs != RT_NULL)
{
kmem_put(ksigs);
}
kmem_put(kev);
return (ret < 0 ? GET_ERRNO() : ret);
}
/**
* @brief Truncate a file to a specified length.
*
* This function resizes the file associated with the given file descriptor `fd` to the specified length.
* If the current size of the file is greater than the specified length, the file is truncated. If the file is smaller,
* it is extended, and the new space is initialized to zero.
*
* @param[in] fd The file descriptor referring to the file to truncate. This must be a valid open file descriptor.
* @param[in] length The new length of the file. The file will be truncated or extended to this size.
*
* @return sysret_t On success, returns `0`. On failure, returns a negative error code.
*
* @note The file descriptor `fd` must be opened with write permissions for this operation to succeed.
*/
sysret_t sys_ftruncate(int fd, size_t length)
{
int ret;
ret = ftruncate(fd, length);
return (ret < 0 ? GET_ERRNO() : ret);
}
/**
* @brief Set file access and modification times.
*
* This function updates the access and modification times of a file or directory referenced by `__fd` or `__path`.
* If `__fd` is a valid file descriptor, the times will be applied to the file or directory it refers to.
* If `__fd` is `AT_FDCWD`, the times will be applied to the file or directory specified by `__path`.
* The `__times` argument consists of two `timespec` values: the first represents the access time,
* and the second represents the modification time. If `__times` is `NULL`, the current time is used.
*
* @param[in] __fd The file descriptor of the file or directory to modify, or `AT_FDCWD` to modify using `__path`.
* @param[in] __path The path to the file or directory to modify. Ignored if `__fd` is not `AT_FDCWD`.
* @param[in] __times An array of two `timespec` structures. The first element is the access time, and the second is the modification time.
* If `__times` is `NULL`, the current time is used for both access and modification times.
* @param[in] __flags Flags to modify behavior. Supported flags include:
* - `AT_SYMLINK_NOFOLLOW`: Do not follow symbolic links.
* - `AT_NO_AUTOMOUNT`: Do not trigger automounting.
*
* @return sysret_t On success, returns `0`. On failure, returns a negative error code.
*
* @note This function modifies both access and modification times of files, and may affect file system timestamps.
*/
sysret_t sys_utimensat(int __fd, const char *__path, const struct timespec __times[2], int __flags)
{
#ifdef RT_USING_DFS_V2
#ifdef ARCH_MM_MMU
int ret = -1;
rt_size_t len = 0;
char *kpath = RT_NULL;
len = lwp_user_strlen(__path);
if (len <= 0)
{
return -EINVAL;
}
kpath = (char *)kmem_get(len + 1);
if (!kpath)
{
return -ENOMEM;
}
lwp_get_from_user(kpath, (void *)__path, len + 1);
ret = utimensat(__fd, kpath, __times, __flags);
kmem_put(kpath);
return ret;
#else
if (!lwp_user_accessable((void *)__path, 1))
{
return -EFAULT;
}
int ret = utimensat(__fd, __path, __times, __flags);
return ret;
#endif
#else
return -1;
#endif
}
/**
* @brief Change file permissions.
*
* This function changes the permissions of a file or directory specified by the `pathname`.
* The new permissions are specified using the `mode` argument, which is a bitwise OR of permission bits.
* The permissions apply to the file owner, group, and others, depending on the value of `mode`.
*
* @param[in] pathname The path to the file or directory whose permissions are to be changed.
* @param[in] mode The new permissions to set, represented as a bitwise OR of permission flags.
* For example, `S_IRUSR`, `S_IWUSR`, `S_IRGRP`, etc.
*
* @return sysret_t On success, returns `0`. On failure, returns a negative error code.
*
* @note If the file or directory is a symbolic link, this function will modify the permissions of the symbolic link itself,
* not the target file or directory.
*/
sysret_t sys_chmod(const char *pathname, mode_t mode)
{
char *copy_file;
size_t len_file, copy_len_file;
struct dfs_attr attr = { 0 };
int ret = 0;
len_file = lwp_user_strlen(pathname);
if (len_file <= 0)
{
return -EFAULT;
}
copy_file = (char *)rt_malloc(len_file + 1);
if (!copy_file)
{
return -ENOMEM;
}
copy_len_file = lwp_get_from_user(copy_file, (void *)pathname, len_file);
attr.st_mode = mode;
attr.ia_valid |= ATTR_MODE_SET;
copy_file[copy_len_file] = '\0';
ret = dfs_file_setattr(copy_file, &attr);
rt_free(copy_file);
return (ret < 0 ? GET_ERRNO() : ret);
}
/**
* @brief Changes the permissions of an open file descriptor.
*
* @param[in] fd The open file descriptor.
* @param[in] mode The new file permission bits.
* @return sysret_t Zero on success, otherwise a negative error code.
*/
sysret_t sys_fchmod(int fd, mode_t mode)
{
int ret;
ret = fchmod(fd, mode);
return (ret < 0 ? GET_ERRNO() : ret);
}
/**
* @brief Change the ownership of a file or directory.
*
* This function changes the owner and/or group of the file or directory specified by `pathname`.
* The `owner` and `group` parameters represent the new owner and group IDs, respectively. If either
* parameter is set to `-1`, that aspect (owner or group) will remain unchanged.
*
* @param[in] pathname The path to the file or directory whose ownership is to be changed.
* @param[in] owner The new owner ID. If set to `-1`, the owner's ID is not changed.
* @param[in] group The new group ID. If set to `-1`, the group's ID is not changed.
*
* @return sysret_t On success, returns `0`. On failure, returns a negative error code.
*
* @note The caller must have the appropriate permissions (i.e., be the superuser or the file owner)
* to change the ownership of a file or directory.
*/
sysret_t sys_chown(const char *pathname, uid_t owner, gid_t group)
{
char *copy_file;
size_t len_file, copy_len_file;
struct dfs_attr attr = { 0 };
int ret = 0;
len_file = lwp_user_strlen(pathname);
if (len_file <= 0)
{
return -EFAULT;
}
copy_file = (char *)rt_malloc(len_file + 1);
if (!copy_file)
{
return -ENOMEM;
}
copy_len_file = lwp_get_from_user(copy_file, (void *)pathname, len_file);
if (owner >= 0)
{
attr.st_uid = owner;
attr.ia_valid |= ATTR_UID_SET;
}
if (group >= 0)
{
attr.st_gid = group;
attr.ia_valid |= ATTR_GID_SET;
}
copy_file[copy_len_file] = '\0';
ret = dfs_file_setattr(copy_file, &attr);
rt_free(copy_file);
return (ret < 0 ? GET_ERRNO() : ret);
}
|