📄 create.c
字号:
{ uid_t r;#ifdef UID_NOBODY r = UID_NOBODY;#else static uid_t uid_nobody; if (!uid_nobody && !uname_to_uid ("nobody", &uid_nobody)) uid_nobody = -2; r = uid_nobody;#endif *negative = r < 0; return r;}booluid_to_chars (uid_t v, char *p, size_t s){ return to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");}booluintmax_to_chars (uintmax_t v, char *p, size_t s){ return to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");}voidstring_to_chars (char const *str, char *p, size_t s){ tar_copy_str (p, str, s); p[s - 1] = '\0';}/* A file is considered dumpable if it is sparse and both --sparse and --totals are specified. Otherwise, it is dumpable unless any of the following conditions occur: a) it is empty *and* world-readable, or b) current archive is /dev/null */boolfile_dumpable_p (struct tar_stat_info *st){ if (dev_null_output) return totals_option && sparse_option && ST_IS_SPARSE (st->stat); return !(st->archive_file_size == 0 && (st->stat.st_mode & MODE_R) == MODE_R);}/* Writing routines. *//* Write the EOT block(s). Zero at least two blocks, through the end of the record. Old tar, as previous versions of GNU tar, writes garbage after two zeroed blocks. */voidwrite_eot (void){ union block *pointer = find_next_block (); memset (pointer->buffer, 0, BLOCKSIZE); set_next_block_after (pointer); pointer = find_next_block (); memset (pointer->buffer, 0, available_space_after (pointer)); set_next_block_after (pointer);}/* Write a "private" header */union block *start_private_header (const char *name, size_t size){ time_t t; union block *header = find_next_block (); memset (header->buffer, 0, sizeof (union block)); tar_name_copy_str (header->header.name, name, NAME_FIELD_SIZE); OFF_TO_CHARS (size, header->header.size); time (&t); TIME_TO_CHARS (t, header->header.mtime); MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode); UID_TO_CHARS (getuid (), header->header.uid); GID_TO_CHARS (getgid (), header->header.gid); MAJOR_TO_CHARS (0, header->header.devmajor); MINOR_TO_CHARS (0, header->header.devminor); strncpy (header->header.magic, TMAGIC, TMAGLEN); strncpy (header->header.version, TVERSION, TVERSLEN); return header;}/* Create a new header and store there at most NAME_FIELD_SIZE bytes of the file name */static union block *write_short_name (struct tar_stat_info *st){ union block *header = find_next_block (); memset (header->buffer, 0, sizeof (union block)); tar_name_copy_str (header->header.name, st->file_name, NAME_FIELD_SIZE); return header;}#define FILL(field,byte) do { \ memset(field, byte, sizeof(field)-1); \ (field)[sizeof(field)-1] = 0; \} while (0)/* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */static voidwrite_gnu_long_link (struct tar_stat_info *st, const char *p, char type){ size_t size = strlen (p) + 1; size_t bufsize; union block *header; char *tmpname; header = start_private_header ("././@LongLink", size); FILL(header->header.mtime, '0'); FILL(header->header.mode, '0'); FILL(header->header.uid, '0'); FILL(header->header.gid, '0'); FILL(header->header.devmajor, 0); FILL(header->header.devminor, 0); uid_to_uname (0, &tmpname); UNAME_TO_CHARS (tmpname, header->header.uname); free (tmpname); gid_to_gname (0, &tmpname); GNAME_TO_CHARS (tmpname, header->header.gname); free (tmpname); strcpy (header->header.magic, OLDGNU_MAGIC); header->header.typeflag = type; finish_header (st, header, -1); header = find_next_block (); bufsize = available_space_after (header); while (bufsize < size) { memcpy (header->buffer, p, bufsize); p += bufsize; size -= bufsize; set_next_block_after (header + (bufsize - 1) / BLOCKSIZE); header = find_next_block (); bufsize = available_space_after (header); } memcpy (header->buffer, p, size); memset (header->buffer + size, 0, bufsize - size); set_next_block_after (header + (size - 1) / BLOCKSIZE);}static size_tsplit_long_name (const char *name, size_t length){ size_t i; if (length > PREFIX_FIELD_SIZE) length = PREFIX_FIELD_SIZE + 1; for (i = length - 1; i > 0; i--) if (ISSLASH (name[i])) break; return i;}static union block *write_ustar_long_name (const char *name){ size_t length = strlen (name); size_t i; union block *header; if (length > PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1) { ERROR ((0, 0, _("%s: file name is too long (max %d); not dumped"), quotearg_colon (name), PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1)); return NULL; } i = split_long_name (name, length); if (i == 0 || length - i - 1 > NAME_FIELD_SIZE) { ERROR ((0, 0, _("%s: file name is too long (cannot be split); not dumped"), quotearg_colon (name))); return NULL; } header = find_next_block (); memset (header->buffer, 0, sizeof (header->buffer)); memcpy (header->header.prefix, name, i); memcpy (header->header.name, name + i + 1, length - i - 1); return header;}/* Write a long link name, depending on the current archive format */static voidwrite_long_link (struct tar_stat_info *st){ switch (archive_format) { case POSIX_FORMAT: xheader_store ("linkpath", st, NULL); break; case V7_FORMAT: /* old V7 tar format */ case USTAR_FORMAT: case STAR_FORMAT: ERROR ((0, 0, _("%s: link name is too long; not dumped"), quotearg_colon (st->link_name))); break; case OLDGNU_FORMAT: case GNU_FORMAT: write_gnu_long_link (st, st->link_name, GNUTYPE_LONGLINK); break; default: abort(); /*FIXME*/ }}static union block *write_long_name (struct tar_stat_info *st){ switch (archive_format) { case POSIX_FORMAT: xheader_store ("path", st, NULL); break; case V7_FORMAT: if (strlen (st->file_name) > NAME_FIELD_SIZE-1) { ERROR ((0, 0, _("%s: file name is too long (max %d); not dumped"), quotearg_colon (st->file_name), NAME_FIELD_SIZE - 1)); return NULL; } break; case USTAR_FORMAT: case STAR_FORMAT: return write_ustar_long_name (st->file_name); case OLDGNU_FORMAT: case GNU_FORMAT: write_gnu_long_link (st, st->file_name, GNUTYPE_LONGNAME); break; default: abort(); /*FIXME*/ } return write_short_name (st);}union block *write_extended (bool global, struct tar_stat_info *st, union block *old_header){ union block *header, hp; char *p; int type; if (st->xhdr.buffer || st->xhdr.stk == NULL) return old_header; xheader_finish (&st->xhdr); memcpy (hp.buffer, old_header, sizeof (hp)); if (global) { type = XGLTYPE; p = xheader_ghdr_name (); } else { type = XHDTYPE; p = xheader_xhdr_name (st); } xheader_write (type, p, &st->xhdr); free (p); header = find_next_block (); memcpy (header, &hp.buffer, sizeof (hp.buffer)); return header;}static union block *write_header_name (struct tar_stat_info *st){ if (archive_format == POSIX_FORMAT && !string_ascii_p (st->file_name)) { xheader_store ("path", st, NULL); return write_short_name (st); } else if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < strlen (st->file_name)) return write_long_name (st); else return write_short_name (st);}/* Header handling. *//* Make a header block for the file whose stat info is st, and return its address. */union block *start_header (struct tar_stat_info *st){ union block *header; header = write_header_name (st); if (!header) return NULL; /* Override some stat fields, if requested to do so. */ if (owner_option != (uid_t) -1) st->stat.st_uid = owner_option; if (group_option != (gid_t) -1) st->stat.st_gid = group_option; if (mode_option) st->stat.st_mode = ((st->stat.st_mode & ~MODE_ALL) | mode_adjust (st->stat.st_mode, S_ISDIR (st->stat.st_mode) != 0, initial_umask, mode_option, NULL)); /* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a) for a few tars and came up with the following interoperability matrix: WRITER 1 2 3 4 5 6 7 8 9 READER . . . . . . . . . 1 = SunOS 4.2 tar # . . # # . . # # 2 = NEC SVR4.0.2 tar . . . # # . . # . 3 = Solaris 2.1 tar . . . . . . . . . 4 = GNU tar 1.11.1 . . . . . . . . . 5 = HP-UX 8.07 tar . . . . . . . . . 6 = Ultrix 4.1 . . . . . . . . . 7 = AIX 3.2 . . . . . . . . . 8 = Hitachi HI-UX 1.03 . . . . . . . . . 9 = Omron UNIOS-B 4.3BSD 1.60Beta . = works # = ``impossible file type'' The following mask for old archive removes the `#'s in column 4 above, thus making GNU tar both a universal donor and a universal acceptor for Paul's test. */ if (archive_format == V7_FORMAT || archive_format == USTAR_FORMAT) MODE_TO_CHARS (st->stat.st_mode & MODE_ALL, header->header.mode); else MODE_TO_CHARS (st->stat.st_mode, header->header.mode); { uid_t uid = st->stat.st_uid; if (archive_format == POSIX_FORMAT && MAX_OCTAL_VAL (header->header.uid) < uid) { xheader_store ("uid", st, NULL); uid = 0; } if (!UID_TO_CHARS (uid, header->header.uid)) return NULL; } { gid_t gid = st->stat.st_gid; if (archive_format == POSIX_FORMAT && MAX_OCTAL_VAL (header->header.gid) < gid) { xheader_store ("gid", st, NULL); gid = 0; } if (!GID_TO_CHARS (gid, header->header.gid)) return NULL; } { off_t size = st->stat.st_size; if (archive_format == POSIX_FORMAT && MAX_OCTAL_VAL (header->header.size) < size) { xheader_store ("size", st, NULL); size = 0; } if (!OFF_TO_CHARS (size, header->header.size)) return NULL; } { struct timespec mtime = set_mtime_option ? mtime_option : st->mtime; if (archive_format == POSIX_FORMAT) { if (MAX_OCTAL_VAL (header->header.mtime) < mtime.tv_sec || mtime.tv_nsec != 0) xheader_store ("mtime", st, &mtime); if (MAX_OCTAL_VAL (header->header.mtime) < mtime.tv_sec) mtime.tv_sec = 0; } if (!TIME_TO_CHARS (mtime.tv_sec, header->header.mtime)) return NULL; } /* FIXME */ if (S_ISCHR (st->stat.st_mode) || S_ISBLK (st->stat.st_mode)) { major_t devmajor = major (st->stat.st_rdev); minor_t devminor = minor (st->stat.st_rdev); if (archive_format == POSIX_FORMAT && MAX_OCTAL_VAL (header->header.devmajor) < devmajor) { xheader_store ("devmajor", st, NULL); devmajor = 0; } if (!MAJOR_TO_CHARS (devmajor, header->header.devmajor)) return NULL; if (archive_format == POSIX_FORMAT && MAX_OCTAL_VAL (header->header.devminor) < devminor) { xheader_store ("devminor", st, NULL); devminor = 0; } if (!MINOR_TO_CHARS (devminor, header->header.devminor)) return NULL; } else if (archive_format != GNU_FORMAT && archive_format != OLDGNU_FORMAT) { if (!(MAJOR_TO_CHARS (0, header->header.devmajor) && MINOR_TO_CHARS (0, header->header.devminor))) return NULL; } if (archive_format == POSIX_FORMAT) { xheader_store ("atime", st, NULL); xheader_store ("ctime", st, NULL); } else if (incremental_option) if (archive_format == OLDGNU_FORMAT || archive_format == GNU_FORMAT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -