00001
00002
00003
00004
00005 #include <ustar.h>
00006 #include <syscall.h>
00007 #include <stdio.h>
00008 #include <string.h>
00009
00010 static void usage (void);
00011 static bool make_tar_archive (const char *archive_name,
00012 char *files[], size_t file_cnt);
00013
00014 int
00015 main (int argc, char *argv[])
00016 {
00017 if (argc < 3)
00018 usage ();
00019
00020 return (make_tar_archive (argv[1], argv + 2, argc - 2)
00021 ? EXIT_SUCCESS : EXIT_FAILURE);
00022 }
00023
00024 static void
00025 usage (void)
00026 {
00027 printf ("tar, tar archive creator\n"
00028 "Usage: tar ARCHIVE FILE...\n"
00029 "where ARCHIVE is the tar archive to create\n"
00030 " and FILE... is a list of files or directories to put into it.\n"
00031 "(ARCHIVE itself will not be included in the archive, even if it\n"
00032 "is in a directory to be archived.)\n");
00033 exit (EXIT_FAILURE);
00034 }
00035
00036 static bool archive_file (char file_name[], size_t file_name_size,
00037 int archive_fd, bool *write_error);
00038
00039 static bool archive_ordinary_file (const char *file_name, int file_fd,
00040 int archive_fd, bool *write_error);
00041 static bool archive_directory (char file_name[], size_t file_name_size,
00042 int file_fd, int archive_fd, bool *write_error);
00043 static bool write_header (const char *file_name, enum ustar_type, int size,
00044 int archive_fd, bool *write_error);
00045
00046 static bool do_write (int fd, const char *buffer, int size, bool *write_error);
00047
00048 static bool
00049 make_tar_archive (const char *archive_name, char *files[], size_t file_cnt)
00050 {
00051 static const char zeros[512];
00052 int archive_fd;
00053 bool success = true;
00054 bool write_error = false;
00055 size_t i;
00056
00057 if (!create (archive_name, 0))
00058 {
00059 printf ("%s: create failed\n", archive_name);
00060 return false;
00061 }
00062 archive_fd = open (archive_name);
00063 if (archive_fd < 0)
00064 {
00065 printf ("%s: open failed\n", archive_name);
00066 return false;
00067 }
00068
00069 for (i = 0; i < file_cnt; i++)
00070 {
00071 char file_name[128];
00072
00073 strlcpy (file_name, files[i], sizeof file_name);
00074 if (!archive_file (file_name, sizeof file_name,
00075 archive_fd, &write_error))
00076 success = false;
00077 }
00078
00079 if (!do_write (archive_fd, zeros, 512, &write_error)
00080 || !do_write (archive_fd, zeros, 512, &write_error))
00081 success = false;
00082
00083 close (archive_fd);
00084
00085 return success;
00086 }
00087
00088 static bool
00089 archive_file (char file_name[], size_t file_name_size,
00090 int archive_fd, bool *write_error)
00091 {
00092 int file_fd = open (file_name);
00093 if (file_fd >= 0)
00094 {
00095 bool success;
00096
00097 if (inumber (file_fd) != inumber (archive_fd))
00098 {
00099 if (!isdir (file_fd))
00100 success = archive_ordinary_file (file_name, file_fd,
00101 archive_fd, write_error);
00102 else
00103 success = archive_directory (file_name, file_name_size, file_fd,
00104 archive_fd, write_error);
00105 }
00106 else
00107 {
00108
00109 success = true;
00110 }
00111
00112 close (file_fd);
00113
00114 return success;
00115 }
00116 else
00117 {
00118 printf ("%s: open failed\n", file_name);
00119 return false;
00120 }
00121 }
00122
00123 static bool
00124 archive_ordinary_file (const char *file_name, int file_fd,
00125 int archive_fd, bool *write_error)
00126 {
00127 bool read_error = false;
00128 bool success = true;
00129 int file_size = filesize (file_fd);
00130
00131 if (!write_header (file_name, USTAR_REGULAR, file_size,
00132 archive_fd, write_error))
00133 return false;
00134
00135 while (file_size > 0)
00136 {
00137 static char buf[512];
00138 int chunk_size = file_size > 512 ? 512 : file_size;
00139 int read_retval = read (file_fd, buf, chunk_size);
00140 int bytes_read = read_retval > 0 ? read_retval : 0;
00141
00142 if (bytes_read != chunk_size && !read_error)
00143 {
00144 printf ("%s: read error\n", file_name);
00145 read_error = true;
00146 success = false;
00147 }
00148
00149 memset (buf + bytes_read, 0, 512 - bytes_read);
00150 if (!do_write (archive_fd, buf, 512, write_error))
00151 success = false;
00152
00153 file_size -= chunk_size;
00154 }
00155
00156 return success;
00157 }
00158
00159 static bool
00160 archive_directory (char file_name[], size_t file_name_size, int file_fd,
00161 int archive_fd, bool *write_error)
00162 {
00163 size_t dir_len;
00164 bool success = true;
00165
00166 dir_len = strlen (file_name);
00167 if (dir_len + 1 + READDIR_MAX_LEN + 1 > file_name_size)
00168 {
00169 printf ("%s: file name too long\n", file_name);
00170 return false;
00171 }
00172
00173 if (!write_header (file_name, USTAR_DIRECTORY, 0, archive_fd, write_error))
00174 return false;
00175
00176 file_name[dir_len] = '/';
00177 while (readdir (file_fd, &file_name[dir_len + 1]))
00178 if (!archive_file (file_name, file_name_size, archive_fd, write_error))
00179 success = false;
00180 file_name[dir_len] = '\0';
00181
00182 return success;
00183 }
00184
00185 static bool
00186 write_header (const char *file_name, enum ustar_type type, int size,
00187 int archive_fd, bool *write_error)
00188 {
00189 static char header[512];
00190 return (ustar_make_header (file_name, type, size, header)
00191 && do_write (archive_fd, header, 512, write_error));
00192 }
00193
00194 static bool
00195 do_write (int fd, const char *buffer, int size, bool *write_error)
00196 {
00197 if (write (fd, buffer, size) == size)
00198 return true;
00199 else
00200 {
00201 if (!*write_error)
00202 {
00203 printf ("error writing archive\n");
00204 *write_error = true;
00205 }
00206 return false;
00207 }
00208 }