Не ясно, какие ограничения накладываются на упражнения в классе, и мой индонезийский язык не так хорош, как Энгли sh ОП, и Chrome, похоже, не хотел переводить файл README.md
на Страница GitHub https://github.com/VYPRATAMA009/sisop-modul-3.
Для решения проблемы, описанной в вопросе (с точки зрения желаемого результата), нет необходимости использовать ни потоки, ни fork()
и exec*()
для реализации программы.
Практически всегда плохая идея смешивать потоки с fork()
и exec*()
- выбрать многопоточность или многопроцессорность, но не оба одновременно.
Программа должна обработать параметр (-f
, чтобы проверить только обычные файлы; не перемещать файлы любого типа), а затем обработать любые остаточные имена файлов. Обработка имени состоит из проверки обычного файла, если необходимо, поиска расширения с помощью strrchr()
, создания каталога с таким именем расширения, затем форматирования имени в подкаталоге, а затем переименования файла, чтобы он перешел в каталог. и освобождая выделенную память.
#include "stderr.h"
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
static bool is_regular(const char *filename);
static void mk_directory(const char *dirname);
static void move_file(const char *filename);
static bool check_file = false;
static const char usestr[] = "[-f] file [...]";
static const char optstr[] = "f";
int main(int argc, char *argv[])
{
int opt;
err_setarg0(argv[0]);
while ((opt = getopt(argc, argv, optstr)) != -1)
{
switch (opt)
{
case 'f':
check_file = true;
break;
default:
err_usage(usestr);
/*NOTREACHED*/
}
}
if (optind == argc)
err_usage(usestr);
for (int i = optind; i < argc; i++)
move_file(argv[i]);
return 0;
}
static bool is_regular(const char *filename)
{
struct stat sb;
if (stat(filename, &sb) != 0)
err_syserr("failed to get status of file '%s': ", filename);
return S_ISREG(sb.st_mode);
}
static void mk_directory(const char *dirname)
{
if (mkdir(dirname, 0755) != 0)
{
if (errno != EEXIST)
err_syserr("failed to create directory '%s': ", dirname);
}
}
static void move_file(const char *filename)
{
char *dot = strrchr(filename, '.');
if (check_file && !is_regular(filename))
{
err_remark("'%s' is not a regular file\n", filename);
return;
}
if (dot == NULL || dot == filename || dot[1] == '\0')
{
err_remark("file '%s' does not have an extension\n", filename);
return;
}
mk_directory(dot + 1);
size_t namelen = strlen(dot + 1) + strlen(filename) + sizeof("/");
char *buffer = malloc(namelen);
if (buffer == NULL)
err_syserr("failed to allocated %zu bytes memory: ", namelen);
sprintf(buffer, "%s/%s", dot + 1, filename);
if (rename(filename, buffer) != 0)
err_syserr("failed to rename '%s' to '%s': ", filename, buffer);
free(buffer);
}
Это использует мои функции отчетов об ошибках, которые доступны в моем репозитории SOQ (вопросы о переполнении стека) на GitHub в виде файлов stderr.c
и stderr.h
в подкаталоге src / libsoq .
Имеется каталог, который начинается с:
$ ls -la
total 56
drwxr-xr-x 15 jonathanleffler staff 480 Apr 2 22:14 .
drwxr-xr-x 241 jonathanleffler staff 7712 Apr 2 22:16 ..
-rw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:12 .junk
-rw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:12 .junk.
-rw-r--r-- 1 jonathanleffler staff 1036 Apr 2 22:06 binge.c
-rw-r--r-- 1 jonathanleffler staff 666 Apr 2 22:06 garbage.c
-rw-r--r-- 1 jonathanleffler staff 1772 Apr 2 21:11 junk-0.0.1.tar.gz
-rw-r--r-- 1 jonathanleffler staff 1772 Apr 2 21:10 junk-1.txt
-rw-r--r-- 1 jonathanleffler staff 1772 Apr 2 21:10 junk-2.txt
-rw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:12 junk.
-rw-r--r-- 1 jonathanleffler staff 1772 Apr 2 21:10 junk.c
drwxr-xr-x 3 jonathanleffler staff 96 Apr 2 22:04 junk.dir
prw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:10 junk.fifo
lrwxr-xr-x 1 jonathanleffler staff 8 Apr 2 21:12 junk.lnk -> junk.dir
-rw-r--r-- 1 jonathanleffler staff 812 Apr 2 22:06 trash.c
$
с запущенной программой (mf29
скомпилировано из * 1032) *) дает:
$ mf29 -f .j* *
mf29 -f .j* *
mf29: file '.junk' does not have an extension
mf29: file '.junk.' does not have an extension
mf29: file 'junk.' does not have an extension
mf29: 'junk.dir' is not a regular file
mf29: 'junk.fifo' is not a regular file
mf29: 'junk.lnk' is not a regular file
$ ls -la
total 0
drwxr-xr-x 11 jonathanleffler staff 352 Apr 2 22:37 .
drwxr-xr-x 241 jonathanleffler staff 7712 Apr 2 22:16 ..
-rw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:12 .junk
-rw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:12 .junk.
drwxr-xr-x 6 jonathanleffler staff 192 Apr 2 22:37 c
drwxr-xr-x 3 jonathanleffler staff 96 Apr 2 22:37 gz
-rw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:12 junk.
drwxr-xr-x 3 jonathanleffler staff 96 Apr 2 22:04 junk.dir
prw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:10 junk.fifo
lrwxr-xr-x 1 jonathanleffler staff 8 Apr 2 21:12 junk.lnk -> junk.dir
drwxr-xr-x 4 jonathanleffler staff 128 Apr 2 22:37 txt
$
Затем восстановление перемещенных файлов и повторный запуск без опции -f
приводит к:
$ mv ?/* ??/* ???/* ????/* .
$ rmdir ? ?? ??? ????
$ mf29 .j* *
mf29: file '.junk' does not have an extension
mf29: file '.junk.' does not have an extension
mf29: file 'junk.' does not have an extension
$ ls -la
total 0
drwxr-xr-x 11 jonathanleffler staff 352 Apr 2 22:42 .
drwxr-xr-x 241 jonathanleffler staff 7712 Apr 2 22:16 ..
-rw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:12 .junk
-rw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:12 .junk.
drwxr-xr-x 6 jonathanleffler staff 192 Apr 2 22:42 c
drwxr-xr-x 3 jonathanleffler staff 96 Apr 2 22:42 dir
drwxr-xr-x 3 jonathanleffler staff 96 Apr 2 22:42 fifo
drwxr-xr-x 3 jonathanleffler staff 96 Apr 2 22:42 gz
-rw-r--r-- 1 jonathanleffler staff 0 Apr 2 22:12 junk.
drwxr-xr-x 3 jonathanleffler staff 96 Apr 2 22:42 lnk
drwxr-xr-x 4 jonathanleffler staff 128 Apr 2 22:42 txt
$
Если вы предоставляете имена с несколькими компонентами пути, это обычно ошибка:
$ ../mf29 ~/src/cmd/timecmd.c
mf29: failed to rename '/Users/jonathanleffler/src/cmd/timecmd.c' to 'c//Users/jonathanleffler/src/cmd/timecmd.c': error (2) No such file or directory
$
Существуют различные способы, которые можно исправить - это зависит от желаемого результата. Функция POSIX basename()
может быть полезной. Функция mkpath()
также может быть полезна.