MacOS /usr/bin/目录下 Operation not permitted的解决

mac系统下的Rootless机制,让我们在root权限下也不能随心所欲的读写所有路径了,特殊情况下我们需要关闭Rootless时,可尝试如下操作:

  1. 重启按住 Command+R,进入恢复模式,打开Terminal;

  2. 键入命令 csrutil disable

  3. 再次重启,即可对 usr/bin 目录下文件进行修改;

  4. 如果要恢复保护机制,重新进入保护模式,输入 csrutil enable;

Rootless机制是对抗恶意程序的最后防线,除非特殊需要时我们才将其关闭,否则保持开启状态

Mac OS包管理软件brew和port介绍

Mac OS中主要有三种包管理工具:MacPorts,Homebrew,Fink。这里简介Homebrew和MacPorts的区别:

MacPorts
因为 Mac OS 源自 BSD,因此将 BSD 中的 Port 移植到 OS 成为 MacPorts 就一点不奇怪。MacPorts 会独立于 OS 自建一套仓库树,OS 的包执行目录为 /usr/local,而 MacPorts 的包执行目录为 /opt/local。MacPorts 尽量不影响系统现有程序,自然也就尽量少复用系统已有程序。MacPorts 安装包的过程是下载该程序的所有源文件及其依赖包,然后在本地进行 Build 生成最终的可执行文件。这样做的好处是在系统中存在一套独立的生态环境,从而不影响系统自身的生态环境,缺点就是浪费了系统自身的生态资源。

Homebrew
在 Lion 之后兴起的包管理工具,工作方式与 MacPorts 类似,下载源代码然后本地 Build。不同之处在于 Homebrew 采取与 MacPorts 截然相反的态度,对系统资源是最大程度的利用,因此可以说 Homebrew 是直接对现有系统生态环境进行修改,所有包也是直接安装到现有的生态环境中,这样做的好处是节约了系统资源,但缺点是每一次操作都是直接对系统进行修改,严重依赖和影响现有系统。

使用 MacPorts 和 Homebrew 都需要预装 XCode Command Line Tools,即意味着还需要提前预装 XCode。(根据官方文档来看,Fink 安装比较新的工具包时,因为提前编译完成所以无需依赖 XCode,但对于一些不是二进制的包,如果需要本地编译,还是需要依赖 XCode。换而言之,如果想在 OS 中编译源码,都需要 XCode 提供支持)

Kotlin: 几种设计模式

创建型模式

原始模型

interface Computer {
	val cpu: String
}

class PC(override val cpu: String = "Core"): Computer
class Server(override val cpu: String = "Xeon"): Computer

enum class ComputerType {
	PC, Server
}

class ComputerFactory {
	fun produce(type: ComputerType): Computer {
		return when(type) {
			ComputerType.PC -> PC()
			ComputerType.Server -> Server()
		}
	}
}

>>> val comp = ComputerFactory().produce(ComputerType.PC)
>>> println(comp.cpu)
Core

Tg: Serialized binary TL-schema in vkext format(*.tlo)

---types---
/////
//
// Serialized binary TL-schema in vkext format
//
/////

tls.schema_v2 version:int date:int types_num:# types:types_num*[tls.Type] constructor_num:# constructors:constructor_num*[tls.Combinator] functions_num:# functions:functions_num*[tls.Combinator] = tls.Schema;

tls.type name:int id:string constructors_num:int flags:int arity:int params_type:long = tls.Type;
tls.combinator name:int id:string type_name:int left:tls.CombinatorLeft right:tls.CombinatorRight = tls.Combinator;
tls.combinatorLeftBuiltin = tls.CombinatorLeft;
tls.combinatorLeft args_num:# args:args_num*[tls.Arg] = tls.CombinatorLeft;

tls.combinatorRight value:tls.TypeExpr = tls.CombinatorRight;

tls.arg id:string flags:# var_num:flags.1?int exist_var_num:flags.2?int exist_var_bit:flags.2?int type:tls.TypeExpr = tls.Arg;

tls.exprType _:tls.TypeExpr = tls.Expr;
tls.exprNat _:tls.NatExpr = tls.Expr;

tls.natConst value:int = tls.NatExpr;
tls.natVar dif:int var_num:int = tls.NatExpr;

tls.typeVar var_num:int flags:int = tls.TypeExpr;
tls.array multiplicity:tls.NatExpr args_num:# args:args_num*[tls.Arg] = tls.TypeExpr;
tls.typeExpr name:int flags:int children_num:# children:children_num*[tls.Expr] = tls.TypeExpr;
---functions---

Tg:TL-formal

See also TL Language. For the syntax of declaring combinators, see in article Formal declaration of TL combinators. For the syntax of patterns, see in article Formal declaration of TL patterns.

Tokens

Comments are the same as in C/C++. They are removed by a lexical parser (for example, being replaced by a single space). Whitespace separates tokens. Except for string constants, tokens cannot contain spaces.

Character classes:

lc-letter ::= `a` | `b` | ... | `z`
uc-letter ::= `A` | `B` | ... | `Z`
digit ::= `0` | `1` | ... | `9`
hex-digit ::= digit | `a` | `b` | `c` | `d` | `e` | `f`
underscore ::= `_`
letter ::= lc-letter | uc-letter
ident-char ::= letter | digit | underscore

Tg: Current MTProto TL-schema

Below you will find the current MTProto TL-schema. More detais on TL.

int ? = Int;
long ? = Long;
double ? = Double;
string ? = String;

vector {t:Type} # [ t ] = Vector t;

int128 4*[ int ] = Int128;
int256 8*[ int ] = Int256;

resPQ#05162463 nonce:int128 server_nonce:int128 pq:bytes server_public_key_fingerprints:Vector<long> = ResPQ;

p_q_inner_data#83c95aec pq:bytes p:bytes q:bytes nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data;

server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:bytes = Server_DH_Params;

server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:bytes g_a:bytes server_time:int = Server_DH_inner_data;

client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:bytes = Client_DH_Inner_Data;

dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer;

rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult;
rpc_error#2144ca19 error_code:int error_message:string = RpcError;

rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
rpc_answer_dropped_running#cd78e586 = RpcDropAnswer;
rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer;

future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt;
future_salts#ae500895 req_msg_id:long now:int salts:vector<future_salt> = FutureSalts;

pong#347773c5 msg_id:long ping_id:long = Pong;

destroy_session_ok#e22045fc session_id:long = DestroySessionRes;
destroy_session_none#62d350c9 session_id:long = DestroySessionRes;

new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession;

msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;
message msg_id:long seqno:int bytes:int body:Object = Message;
msg_copy#e06046b2 orig_message:Message = MessageCopy;

gzip_packed#3072cfa1 packed_data:bytes = Object;

msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck;

bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification;
bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;

msg_resend_req#7d861a08 msg_ids:Vector<long> = MsgResendReq;
msgs_state_req#da69fb52 msg_ids:Vector<long> = MsgsStateReq;
msgs_state_info#04deb57d req_msg_id:long info:bytes = MsgsStateInfo;
msgs_all_info#8cc0d131 msg_ids:Vector<long> info:bytes = MsgsAllInfo;
msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;

---functions---

req_pq#60469778 nonce:int128 = ResPQ;

req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:bytes q:bytes public_key_fingerprint:long encrypted_data:bytes = Server_DH_Params;

set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:bytes = Set_client_DH_params_answer;

rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;
get_future_salts#b921bd04 num:int = FutureSalts;
ping#7abe77ec ping_id:long = Pong;
ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;
destroy_session#e7512126 session_id:long = DestroySessionRes;

http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;

Tg: Service Messages

Response to an RPC query

A response to an RPC query is normally wrapped as follows:

rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult;

Here req_msg_id is the identifier of the message sent by the other party and containing an RPC query. This way, the recipient knows that the result is a response to the specific RPC query in question. At the same time, this response serves as acknowledgment of the other party’s receipt of the req_msg_id message.

Note that the response to an RPC query must also be acknowledged. Most frequently, this coincides with the transmission of the next message (which may have a container attached to it carrying a service message with the acknowledgment).

RPC Error

The result field returned in response to any RPC query may also contain an error message in the following format:

rpc_error#2144ca19 error_code:int error_message:string = RpcError;

Tg: Binary Data Serialization

MTProto operation requires that elementary and composite data types as well as queries to which such data types are passed as arguments or by which they are returned, be transmitted in binary format (i. e. serialized) . The TL language is used to describe the data types to be serialized.

General Definitions

For our purposes, we can identify a type with the set of its (serialized) values understood as strings (finite sequences) of 32-bit numbers (transmitted in little endian order).

Therefore:

  • Alphabet (A), in this case, is a set of 32-bit numbers (normally, signed, i. e. between -2^31 and 2^31 - 1).
  • Value, in this case, is the same as a string in Alphabet A, i. e. a finite (possibly, empty) sequence of 32-bit numbers. The set of all such sequences is designated as A*.
  • Type, for our purposes, is the same as the set of legal values of a type, i. e. some set T which is a subset of A* and is a prefix code (i. e. no element of T may be a prefix for any other element). Therefore, any sequence from A* can contain no more than one prefix that is a member of T.
  • Value of Type T is any sequence (value) which is a member of T as a subset of A*.
  • Compatible Types are the types T and T’ not intersecting as subsets of A*, such that the union of T and T' is a prefix code.
  • Coordinated System of Types is a finite or infinite set of types T_1, …, T_n, …, such that any two types from this set are compatible.
  • Data Type is the same as type in the sense of the definition above.
  • Functional Type is a type describing a function; it is not a type in the sense of the definition above. Initially, we ignore the existence of functional types and describe only the data types; however, in reality, functional types will later be implemented in some extension of this system using the so-called temporary combinators.

Tg: Type serialization

See Polymorphism in TL and TL Language.

It remains to describe how types, e.g. values of type Type, are transmitted (serialized). In general, there is nothing unexpected going on here: we have type constructors of various arities (for example, List is an arity-1 constructor, but IntList is a 0-arity constructor); and if we know that a 32-bit “name” is assigned to each type constructor, there are no further questions – values of type Type are serialized exactly like values of any other recursive type with a defined set of constructors of differing arity.

How can a 32-bit “name” be assigned to a type (a type constructor, to be more exact) such as List or IntList? It is proposed to use the sum of the names of all of its constructors, plus the CRC32 of the string with the designation of the type’s name and all of its parameters such as “IntList = Type” or “List X:Type = Type”. This way, the List constructor’s “name” is the sum of the CRC32s of the three strings “List X:Type = Type”, “cons X:Type hd:X tl:List X = List X”, and “nil X:Type = List X”. For “bare” types (which, formally speaking, are subtypes of the corresponding “boxed” type), the situation is somewhat more complicated; the logical negation of the corresponding constructor’s name is used. For built-in bareand boxed types (for example, int and Int), a pseudo-declaration is used (for example, int ? = Int").

  • This description is somewhat outdated and may be updated in the future. Specifically, how to treat the ! modifier has not been explained.*